Axional Server includes a high performance object pool. It is the base of the JDBC pool. In this section there is a description of the pool architecture.
The pool handles the creation, life cycle and destruction of pooled objects.
The pool contains two queues, one of used objects and one for live free objects. The general life cycle of a pool operation is:
- A thread requests an object from the pool.
- If an object is in the free queue, it is moved to used queue, and health checked and returned to caller if sane. If not passes health check, a new object is created to be replaced the old one.
- If there are no free objects and the used size is less than the pool size limit, a new object is created, then placed on used queue and returned.
- If pool limit is full and there are no free objects for more than a period, an exception is thrown.
- Objects in free pool are periodically checked and are closed and removed it timed out.
- If pool has a check out count, each object is checked against it's checkout limit. If reached, they are destroyed.
The used queue pool is a
FIFO queue based on ConcurrentLinkedQueue
The free queue pool can be selected to be
In general, any of the three queues renders 1 million I/O request to the queue per second for a queue size of 10 and 10 concurrent threads
You can setup pool for specific tasks by setting up a custom configuration.
Each pool can have specific characteristics defined by using a pool configuration.
The pool configuration main class is
2.1 Pool configuration
Pools are created using the
Each pool has it's own set of configuration parameters that define either pool or object parameters
|setPoolType||Type||LIFO||LIFO, FIFO, ARRAY||The type of blocking pool|
|setPoolMaxSize||Integer||10||>1||Maximum number of elements to keep in pool|
|setPoolExtraSize||Integer||0||Maximum extra elements that can be added to pool when pool fires a bussy exception|
|setPoolMaxEmptyCount||Integer||0||0 not applied||When objects are subject to be recycled on a check out count basis, close the pool if it has been found up to
PoolMaxEmptyCount times empty.
This option must be used with caution. If application has live references to the pool the will be invalid. It should only be used when references to the pool are handled by BloquingQueuePool class.
|setPoolCheckIntervalSeconds||Integer||30||0 not applied||Interval between health check verifications of objects in free pool.|
|setPoolObjectMaxIdleSeconds||Integer||30||>1||Number of second an object can be idle in pool before it's been closed.|
|setPoolObjectMaxCheckOutCount||Integer||0||0 not applied||Maximum number of times an object can be used from pool before being destroyed.|
|setPoolObjectAcquireTimeoutSeconds||Integer||30||>1||Number of seconds before timeout a request from an object when pool is full.|
|setPoolObjectBornDieTimeoutSeconds||Integer||30||>1||Number of seconds before timeout a creation or destruction of an object|
2.2 JDBC Pool configuration
BlockingQueuePoolConfiguration is extended by JDBC implementation class
to add specific JDBC properties for JDBC pool handling.
|setJDBCQueryTimeout||Integer||300||The time in seconds to cancel a query|
|setJDBCCacheSize||Integer||100||The number of individual query
|setJDBCMaxCacheRows||Integer||-1||The maximum number of rows allowed in a cached
|setJDBCInitialSQL||String||An initial SQL statement to be sent to each new connection|
|setJDBCProperties||Properties||The properties to be sent to the JDBC driver prior aquire a connection|
3 Thread executors
Pool may priodically do tasks we call cleanners. A clenner is a time event that is periodically executed to ensure objects in pool are valid. This taks are performed using a Scheduler.
Additionally there are some operations that may take time and block the pool. For
example, in JDBC pools, when a connection is retuned it has to be pasivated. The
passivate process may fire closing JDBC statements. And this operation may block
or hang. To avoid this situations, passivate is executed in a ThreadPoolExecutor
and will use a timeout indicated by
The number of processor and the queue size of ThreadPoolExecutor are setup by default and can be modified by system parameters.
|Cleanner||ThreadPoolExecutor||JVM processors * passivateProcessorsScaleFactor (1)||passivateQueueSize 32 (2)|
The default vaules can be changed by setting java properties at startup
- deister.axional.server.pool.queues.BlockingQueuePool.passivateProcessorsScaleFactor : 2
- deister.axional.server.pool.queues.BlockingQueuePool.passivateQueueSize : 32
4 Thread pooling
The pool is used to manage thread concurrency limiting resource conumption but trying to give a fast response time.
4.1 Little’s Law
Little’s law says that the number of requests in a system equals the rate at which they arrive, multiplied by the average amount of time it takes to service an individual request. This law is so common in our every day lives that it’s surprising that it wasn’t proposed until the 1950s and only proven in the 1960s. Here’s an example of one form of Little’s law in action. Have you ever stood in a line and tried to figure out how long you’d be standing in it? You would consider how many people are in line and then have a quick glance at how long it took to service the person at the front of the queue. You would then multiply those two values together, producing an estimate of how long you’d be in line. If instead of looking at the length of the line, you observed how often new people were joining the line and then multiplied that value by the service time, you’d then know the average number of people that are either in the line or being serviced.
There are numerous other similar games you can play with Little’s law that will answer other questions like “how much time on average does a person stand in the queue waiting to be served?” and so on.$$ L = AV $$
Where L is the average number of customers in the system, A is the arrival rate and W is the average waiting time.
In a similar vein we can use Little’s law to determine thread pool size. All we have to do is measure the rate at which requests arrive and the average amount of time to service them. We can then plug those measurements into Little’s law to calculate the average number of requests in the system. If that number is less than the size of our thread pool then the size of the pool can be reduced accordingly. On the other hand if the number is larger than the size of our thread pool, things get a little more complicated.
In the case where we have more requests waiting than being executed the first thing we need to determine is if there’s enough capacity in the system to support a larger thread pool. To do that we must determine what resource is most likely to limit the application’s ability to scale. In this article we’ll assume that it’s CPU, though be aware that in real life it’s very likely to be something else. The easiest situation is that you have enough capacity to increase the size of the thread pool. If you don’t you’ll have to consider other options, be it tuning your application, adding more hardware, or some combination of both.