292814 make QoSFilter and DoSFilter JMX manageable

git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@1913 7e9141cc-0065-0410-87d8-b60c137991c4
This commit is contained in:
Michael Gorovoy 2010-06-02 02:29:05 +00:00
parent 727e58b0b4
commit 716b76fe5d
2 changed files with 376 additions and 21 deletions

View File

@ -125,18 +125,20 @@ public class DoSFilter implements Filter
protected long _delayMs;
protected long _throttleMs;
protected long _waitMs;
protected long _maxWaitMs;
protected long _maxRequestMs;
protected long _maxIdleTrackerMs;
protected boolean _insertHeaders;
protected boolean _trackSessions;
protected boolean _remotePort;
protected int _throttledRequests;
protected Semaphore _passes;
protected Queue<Continuation>[] _queue;
protected ContinuationListener[] _listener;
protected int _maxRequestsPerSec;
protected final ConcurrentHashMap<String, RateTracker> _rateTrackers=new ConcurrentHashMap<String, RateTracker>();
protected String _whitelistStr;
private final HashSet<String> _whitelist = new HashSet<String>();
private final Timeout _requestTimeoutQ = new Timeout();
@ -170,7 +172,6 @@ public class DoSFilter implements Filter
}
_rateTrackers.clear();
_whitelist.clear();
int baseRateLimit = __DEFAULT_MAX_REQUESTS_PER_SEC;
if (filterConfig.getInitParameter(MAX_REQUESTS_PER_S_INIT_PARAM) != null)
@ -182,15 +183,15 @@ public class DoSFilter implements Filter
delay = Integer.parseInt(filterConfig.getInitParameter(DELAY_MS_INIT_PARAM));
_delayMs = delay;
int passes = __DEFAULT_THROTTLE;
_throttledRequests = __DEFAULT_THROTTLE;
if (filterConfig.getInitParameter(THROTTLED_REQUESTS_INIT_PARAM) != null)
passes = Integer.parseInt(filterConfig.getInitParameter(THROTTLED_REQUESTS_INIT_PARAM));
_passes = new Semaphore(passes,true);
_throttledRequests = Integer.parseInt(filterConfig.getInitParameter(THROTTLED_REQUESTS_INIT_PARAM));
_passes = new Semaphore(_throttledRequests,true);
long wait = __DEFAULT_WAIT_MS;
if (filterConfig.getInitParameter(MAX_WAIT_INIT_PARAM) != null)
wait = Integer.parseInt(filterConfig.getInitParameter(MAX_WAIT_INIT_PARAM));
_waitMs = wait;
_maxWaitMs = wait;
long suspend = __DEFAULT_THROTTLE_MS;
if (filterConfig.getInitParameter(THROTTLE_MS_INIT_PARAM) != null)
@ -207,18 +208,10 @@ public class DoSFilter implements Filter
maxIdleTrackerMs = Long.parseLong(filterConfig.getInitParameter(MAX_IDLE_TRACKER_MS_INIT_PARAM));
_maxIdleTrackerMs = maxIdleTrackerMs;
String whitelistString = "";
_whitelistStr = "";
if (filterConfig.getInitParameter(IP_WHITELIST_INIT_PARAM) !=null )
whitelistString = filterConfig.getInitParameter(IP_WHITELIST_INIT_PARAM);
if (whitelistString.length() > 0)
{
StringTokenizer tokenizer = new StringTokenizer(whitelistString, ",");
while (tokenizer.hasMoreTokens())
_whitelist.add(tokenizer.nextToken().trim());
Log.info("Whitelisted IP addresses: {}", _whitelist.toString());
}
_whitelistStr = filterConfig.getInitParameter(IP_WHITELIST_INIT_PARAM);
initWhitelist();
String tmp = filterConfig.getInitParameter(INSERT_HEADERS_INIT_PARAM);
_insertHeaders = tmp==null || Boolean.parseBoolean(tmp);
@ -342,7 +335,7 @@ public class DoSFilter implements Filter
try
{
// check if we can afford to accept another request at this time
accepted = _passes.tryAcquire(_waitMs,TimeUnit.MILLISECONDS);
accepted = _passes.tryAcquire(_maxWaitMs,TimeUnit.MILLISECONDS);
if (!accepted)
{
@ -607,6 +600,281 @@ public class DoSFilter implements Filter
return null;
}
/* ------------------------------------------------------------ */
/**
* Initialize the IP address whitelist
*/
protected void initWhitelist()
{
_whitelist.clear();
StringTokenizer tokenizer = new StringTokenizer(_whitelistStr, ",");
while (tokenizer.hasMoreTokens())
_whitelist.add(tokenizer.nextToken().trim());
Log.info("Whitelisted IP addresses: {}", _whitelist.toString());
}
/* ------------------------------------------------------------ */
/**
* Get maximum number of requests from a connection per
* second. Requests in excess of this are first delayed,
* then throttled.
*
* @return maximum number of requests
*/
public int getMaxRequestsPerSec()
{
return _maxRequestsPerSec;
}
/* ------------------------------------------------------------ */
/**
* Get maximum number of requests from a connection per
* second. Requests in excess of this are first delayed,
* then throttled.
*
* @param value maximum number of requests
*/
public void setMaxRequestsPerSec(int value)
{
_maxRequestsPerSec = value;
}
/* ------------------------------------------------------------ */
/**
* Get delay (in milliseconds) that is applied to all requests
* over the rate limit, before they are considered at all.
*/
public long getDelayMs()
{
return _delayMs;
}
/* ------------------------------------------------------------ */
/**
* Set delay (in milliseconds) that is applied to all requests
* over the rate limit, before they are considered at all.
*
* @param value delay (in milliseconds), 0 - no delay, -1 - reject request
*/
public void setDelayMs(long value)
{
_delayMs = value;
}
/* ------------------------------------------------------------ */
/**
* Get maximum amount of time (in milliseconds) the filter will
* blocking wait for the throttle semaphore.
*
* @return maximum wait time
*/
public long getMaxWaitMs()
{
return _maxWaitMs;
}
/* ------------------------------------------------------------ */
/**
* Set maximum amount of time (in milliseconds) the filter will
* blocking wait for the throttle semaphore.
*
* @param value maximum wait time
*/
public void setMaxWaitMs(long value)
{
_maxWaitMs = value;
}
/* ------------------------------------------------------------ */
/**
* Get number of requests over the rate limit able to be
* considered at once.
*
* @return number of requests
*/
public long getThrottledRequests()
{
return _throttledRequests;
}
/* ------------------------------------------------------------ */
/**
* Set number of requests over the rate limit able to be
* considered at once.
*
* @param value number of requests
*/
public void setThrottledRequests(int value)
{
_passes = new Semaphore((value-_throttledRequests+_passes.availablePermits()), true);
_throttledRequests = value;
}
/* ------------------------------------------------------------ */
/**
* Get amount of time (in milliseconds) to async wait for semaphore.
*
* @return wait time
*/
public long getThrottleMs()
{
return _throttleMs;
}
/* ------------------------------------------------------------ */
/**
* Set amount of time (in milliseconds) to async wait for semaphore.
*
* @param value wait time
*/
public void setThrottleMs(long value)
{
_throttleMs = value;
}
/* ------------------------------------------------------------ */
/**
* Get maximum amount of time (in milliseconds) to allow
* the request to process.
*
* @return maximum processing time
*/
public long getMaxRequestMs()
{
return _maxRequestMs;
}
/* ------------------------------------------------------------ */
/**
* Set maximum amount of time (in milliseconds) to allow
* the request to process.
*
* @param value maximum processing time
*/
public void setMaxRequestMs(long value)
{
_maxRequestMs = value;
}
/* ------------------------------------------------------------ */
/**
* Get maximum amount of time (in milliseconds) to keep track
* of request rates for a connection, before deciding that
* the user has gone away, and discarding it.
*
* @return maximum tracking time
*/
public long getMaxIdleTrackerMs()
{
return _maxIdleTrackerMs;
}
/* ------------------------------------------------------------ */
/**
* Set maximum amount of time (in milliseconds) to keep track
* of request rates for a connection, before deciding that
* the user has gone away, and discarding it.
*
* @param value maximum tracking time
*/
public void setMaxIdleTrackerMs(long value)
{
_maxIdleTrackerMs = value;
}
/* ------------------------------------------------------------ */
/**
* Check flag to insert the DoSFilter headers into the response.
*
* @return value of the flag
*/
public boolean isInsertHeaders()
{
return _insertHeaders;
}
/* ------------------------------------------------------------ */
/**
* Set flag to insert the DoSFilter headers into the response.
*
* @param value value of the flag
*/
public void setInsertHeaders(boolean value)
{
_insertHeaders = value;
}
/* ------------------------------------------------------------ */
/**
* Get flag to have usage rate tracked by session if a session exists.
*
* @return value of the flag
*/
public boolean isTrackSessions()
{
return _trackSessions;
}
/* ------------------------------------------------------------ */
/**
* Set flag to have usage rate tracked by session if a session exists.
* @param value value of the flag
*/
public void setTrackSessions(boolean value)
{
_trackSessions = value;
}
/* ------------------------------------------------------------ */
/**
* Get flag to have usage rate tracked by IP+port (effectively connection)
* if session tracking is not used.
*
* @return value of the flag
*/
public boolean isRemotePort()
{
return _remotePort;
}
/* ------------------------------------------------------------ */
/**
* Set flag to have usage rate tracked by IP+port (effectively connection)
* if session tracking is not used.
*
* @param value value of the flag
*/
public void setRemotePort(boolean value)
{
_remotePort = value;
}
/* ------------------------------------------------------------ */
/**
* Get a list of IP addresses that will not be rate limited.
*
* @return comma-separated whitelist
*/
public String getWhitelist()
{
return _whitelistStr;
}
/* ------------------------------------------------------------ */
/**
* Set a list of IP addresses that will not be rate limited.
*
* @param value comma-separated whitelist
*/
public void setWhitelist(String value)
{
_whitelistStr = value;
initWhitelist();
}
/**
* A RateTracker is associated with a connection, and stores request rate
* data.

View File

@ -36,6 +36,7 @@ import org.eclipse.jetty.continuation.ContinuationSupport;
/**
* Quality of Service Filter.
*
* This filter limits the number of active requests to the number set by the "maxRequests" init parameter (default 10).
* If more requests are received, they are suspended and placed on priority queues. Priorities are determined by
* the {@link #getPriority(ServletRequest)} method and are a value between 0 and the value given by the "maxPriority"
@ -79,11 +80,16 @@ public class QoSFilter implements Filter
ServletContext _context;
long _waitMs;
long _suspendMs;
int _maxRequests;
Semaphore _passes;
Queue<Continuation>[] _queue;
ContinuationListener[] _listener;
String _suspended="QoSFilter@"+this.hashCode();
/* ------------------------------------------------------------ */
/**
* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
public void init(FilterConfig filterConfig)
{
_context=filterConfig.getServletContext();
@ -110,10 +116,10 @@ public class QoSFilter implements Filter
};
}
int passes=__DEFAULT_PASSES;
int _maxRequests=__DEFAULT_PASSES;
if (filterConfig.getInitParameter(MAX_REQUESTS_INIT_PARAM)!=null)
passes=Integer.parseInt(filterConfig.getInitParameter(MAX_REQUESTS_INIT_PARAM));
_passes=new Semaphore(passes,true);
_maxRequests=Integer.parseInt(filterConfig.getInitParameter(MAX_REQUESTS_INIT_PARAM));
_passes=new Semaphore(_maxRequests,true);
long wait = __DEFAULT_WAIT_MS;
if (filterConfig.getInitParameter(MAX_WAIT_INIT_PARAM)!=null)
@ -126,6 +132,10 @@ public class QoSFilter implements Filter
_suspendMs=suspend;
}
/* ------------------------------------------------------------ */
/**
* @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
@ -238,6 +248,83 @@ public class QoSFilter implements Filter
}
/* ------------------------------------------------------------ */
/**
* @see javax.servlet.Filter#destroy()
*/
public void destroy(){}
/* ------------------------------------------------------------ */
/**
* Get the (short) amount of time (in milliseconds) that the filter would wait
* for the semaphore to become available before suspending a request.
*
* @return wait time (in milliseconds)
*/
public long getWaitMs()
{
return _waitMs;
}
/* ------------------------------------------------------------ */
/**
* Set the (short) amount of time (in milliseconds) that the filter would wait
* for the semaphore to become available before suspending a request.
*
* @param value wait time (in milliseconds)
*/
public void setWaitMs(long value)
{
_waitMs = value;
}
/* ------------------------------------------------------------ */
/**
* Get the amount of time (in milliseconds) that the filter would suspend
* a request for while waiting for the semaphore to become available.
*
* @return suspend time (in milliseconds)
*/
public long getSuspendMs()
{
return _suspendMs;
}
/* ------------------------------------------------------------ */
/**
* Set the amount of time (in milliseconds) that the filter would suspend
* a request for while waiting for the semaphore to become available.
*
* @param value suspend time (in milliseconds)
*/
public void setSuspendMs(long value)
{
_suspendMs = value;
}
/* ------------------------------------------------------------ */
/**
* Get the maximum number of requests allowed to be processed
* at the same time.
*
* @return maximum number of requests
*/
public int getMaxRequests()
{
return _maxRequests;
}
/* ------------------------------------------------------------ */
/**
* Set the maximum number of requests allowed to be processed
* at the same time.
*
* @param passes the _passes to set
*/
public void setMaxRequests(int value)
{
_passes = new Semaphore((value-_maxRequests+_passes.availablePermits()), true);
_maxRequests = value;
}
}