Default thread pool in tomcat of a spring boot application - java

In a spring boot application or in generally, does tomcat has a default thread pool configured?
If we do not configure anything, the tomcat will initiate new threads for each request and the thread gets destroy once the request finish?
And if a thread pool configured, particular thread would serve many requests when ever container pick that thread from pool?

Here is the configs of the embed Tomcat in springboot
server.tomcat.accept-count=100 # Maximum queue length for incoming connection requests when all possible request processing threads are in use.
server.tomcat.accesslog.buffered=true # Whether to buffer output such that it is flushed only periodically.
server.tomcat.accesslog.directory=logs # Directory in which log files are created. Can be absolute or relative to the Tomcat base dir.
server.tomcat.accesslog.enabled=false # Enable access log.
server.tomcat.accesslog.file-date-format=.yyyy-MM-dd # Date format to place in the log file name.
server.tomcat.accesslog.pattern=common # Format pattern for access logs.
server.tomcat.accesslog.prefix=access_log # Log file name prefix.
server.tomcat.accesslog.rename-on-rotate=false # Whether to defer inclusion of the date stamp in the file name until rotate time.
server.tomcat.accesslog.request-attributes-enabled=false # Set request attributes for the IP address, Hostname, protocol, and port used for the request.
server.tomcat.accesslog.rotate=true # Whether to enable access log rotation.
server.tomcat.accesslog.suffix=.log # Log file name suffix.
server.tomcat.additional-tld-skip-patterns= # Comma-separated list of additional patterns that match jars to ignore for TLD scanning.
server.tomcat.background-processor-delay=10s # Delay between the invocation of backgroundProcess methods. If a duration suffix is not specified, seconds will be used.
server.tomcat.basedir= # Tomcat base directory. If not specified, a temporary directory is used.
server.tomcat.internal-proxies=10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|\\
192\\.168\\.\\d{1,3}\\.\\d{1,3}|\\
169\\.254\\.\\d{1,3}\\.\\d{1,3}|\\
127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|\\
172\\.1[6-9]{1}\\.\\d{1,3}\\.\\d{1,3}|\\
172\\.2[0-9]{1}\\.\\d{1,3}\\.\\d{1,3}|\\
172\\.3[0-1]{1}\\.\\d{1,3}\\.\\d{1,3}\\
0:0:0:0:0:0:0:1\\
::1 # Regular expression that matches proxies that are to be trusted.
server.tomcat.max-connections=10000 # Maximum number of connections that the server accepts and processes at any given time.
server.tomcat.max-http-header-size=0 # Maximum size in bytes of the HTTP message header.
server.tomcat.max-http-post-size=2097152 # Maximum size in bytes of the HTTP post content.
server.tomcat.max-threads=200 # Maximum amount of worker threads.
server.tomcat.min-spare-threads=10 # Minimum amount of worker threads.
server.tomcat.port-header=X-Forwarded-Port # Name of the HTTP header used to override the original port value.
server.tomcat.protocol-header= # Header that holds the incoming protocol, usually named "X-Forwarded-Proto".
server.tomcat.protocol-header-https-value=https # Value of the protocol header indicating whether the incoming request uses SSL.
server.tomcat.redirect-context-root=true # Whether requests to the context root should be redirected by appending a / to the path.
server.tomcat.remote-ip-header= # Name of the HTTP header from which the remote IP is extracted. For instance, `X-FORWARDED-FOR`.
server.tomcat.resource.cache-ttl= # Time-to-live of the static resource cache.
server.tomcat.uri-encoding=UTF-8 # Character encoding to use to decode the URI.
server.tomcat.use-relative-redirects= # Whether HTTP 1.1 and later location headers generated by a call to sendRedirect will use relative or absolute redirects.
As you can see for the default value, the minimum amount of worker threads is 10, and the maximum amount of worker threads is 200, and the maximum queue length for incoming connection requests when all possible request processing threads are in use is 100.

Yes spring boot uses Embeded tomcat server, you can modify some of its configs in application.yml or application.properties By default it has 200 threads spring-docs
# EMBEDDED SERVER CONFIGURATION (ServerProperties)
server.port=8080
server.address= # bind to a specific NIC
server.session-timeout= # session timeout in seconds
server.context-path= # the context path, defaults to '/'
server.servlet-path= # the servlet path, defaults to '/'
server.tomcat.access-log-pattern= # log pattern of the access log
server.tomcat.access-log-enabled=false # is access logging enabled
server.tomcat.protocol-header=x-forwarded-proto # ssl forward headers
server.tomcat.remote-ip-header=x-forwarded-for
server.tomcat.basedir=/tmp # base dir (usually not needed, defaults to tmp)
server.tomcat.background-processor-delay=30; # in seconds
server.tomcat.max-threads = 0 # number of threads in protocol handler
server.tomcat.uri-encoding = UTF-8 # character encoding to use for URL decoding

Related

Limit number of emails per time from Log4j2 SMTPAppender

I use Apache Log4j2 and its SMTPAppender in an application. It's configured to send email notifications for events of level ERROR or above. Usually this works great.
But recently I had a batch processing situation in which thousands of ERROR lines were logged in a time interval of 5 minutes. My inbox was flooded with thousands of emails and our mail server blacklisted the affected application server...
To avoid such a mishap: Can we apply a maximum limit to the number of emails sent per time interval?
E.g. I'd like SMTPAppender to not send more than 20 emails per hour. If this limit is exceeded, further ERROR/FATAL lines should be aggregated into a single email which is sent as soon as one more email may be sent regarding the limit of 20/hour.
Is there a Log4j2-standard way to achieve that? How did you solve this task in your apps using Log4j2?
You can use BurstFilter. These are the parameters (from the documentation):
Parameter Name
Type
Description
level
String
Level of messages to be filtered. Anything at or below this level will be filtered out if maxBurst has been exceeded. The default is WARN meaning any messages that are higher than warn will be logged regardless of the size of a burst.
rate
float
The average number of events per second to allow.
maxBurst
integer
The maximum number of events that can occur before events are filtered for exceeding the average rate. The default is 10 times the rate.
onMatch
String
Action to take when the filter matches. May be ACCEPT, DENY or NEUTRAL. The default value is NEUTRAL.
onMismatch
String
Action to take when the filter does not match. May be ACCEPT, DENY or NEUTRAL. The default value is DENY.
<Appenders>
<SMTP> <!-- parameters omitted for brevity -->
<BurstFilter level="ERROR" rate="16" maxBurst="100"/>
</SMTP>
</Appenders>

About SpringBoot Tomcat acceptCount pool

I'm dealing with the Tomcat configuration on springboot.
Let's supposse i have the following configuration:
server:
tomcat:
min-spare-threads: ${min-tomcat-threads:20}
max-threads: ${max-tomcat-threads:20}
accept-count: ${accept-concurrent-queue:1}
max-connections: ${max-tomcat-connections:100}
I have a simple RestController with this code:
public String request(#Valid #RequestBody Info info) {
log.info("Thread sleeping");
Thread.sleep(8000);
return "OK";
}
Then i make the following test:
I send 200 HTTP request per second.
I check the log and as I expected I see 100 simultaneous executions and after 8 seconds I see the last one (queued).
Other executions are rejected.
The main problem that i have with this is that if i have a timeout control on client call (for example, 5 seconds), the queued operation will be processed on server anyways even if it was rejected on client.
I want to avoid this situation, so I tried:
server:
tomcat:
min-spare-threads: ${min-tomcat-threads:20}
max-threads: ${max-tomcat-threads:20}
accept-count: ${accept-concurrent-queue:0}
max-connections: ${max-tomcat-connections:100}
But this "0" is totally ignored (i think in this case it means "infinite").
So, my question is:
¿Is it possible to configure Tomcat to don't queue operations if the max-connections limit is reached?
Or maybe
¿Is it possible to configure Tomcat to reject any operation queued?
Thank you very much in advance.
Best regards.
The value of the acceptCount parameter is passed directly to the operating system: e.g. for UNIX-es it is passed to listen. Since an incoming connection is always put in the OS queue before the JVM accepts it, values lower than 1 make no sense. Tomcat explicitly ignores such values and keeps its default 100.
However, the real queue in Tomcat are the connections that where accepted from the OS queue, but are not being processed due to a lack of processing threads (maxThreads). You might have at most maxConnections - maxThreads + 1 such connections. In your case it's 81 connections waiting to be processed.

Tomcat datasource specific settings do not change when modified in application.properties file

I have a spring boot application, I use tomcat connection pooling for DB connections.
When I access the application, it by default creates 10 connections per login.
I get that this is due to
spring.datasource.tomcat.initial-size = 10(default value)
I modify this property in application.properties file to make it only 5.
But this doesn't modify anything.
Nor does this:
spring.datasource.max-active=5
Am I missing something?
You have 2 parameters impact inital size according to tomcat:
minIdle (int) The minimum number of established connections that
should be kept in the pool at all times. The connection pool can
shrink below this number if validation queries fail. Default value is
derived from initialSize:10 (also see testWhileIdle)
initialSize (int)The initial number of connections that are created
when the pool is started. Default value is 10
So you need to set those 2 parameters in PoolProperties:
PoolProperties p = new PoolProperties();
p.setMinIdle(5);
p.setInitialSize(5);
Very silly mistake, but please check where your properties are being used. In my case I had an xml file which was providing the database details. And the ones present in application.properties were ignored.
I was changing in application.properties so obviously it had no impact.
In the end I removed the xml file to only use application.properties file and it started working.
I used:
spring.datasource.tomcat.maxActive= 50
spring.datasource.tomcat.initialSize= 1
spring.datasource.tomcat.minIdle = 1
spring.datasource.tomcat.maxIdle = 5
spring.datasource.tomcat.testWhileIdle = true
Thank you #user7294900 . I thought of cross verifying because of your comment. :)

Cassandra query logging through spring configuration

is there any easy way to turn on query logging on cassandra through xml configuration? I'm using namespace:
xmlns:cassandra="http://www.springframework.org/schema/data/cassandra"
but I can't find any suitable solution. I was trying to turn on trace through cqlsh, but it dosen't work for my app.
I was trying also to add line:
<logger name="com.datastax.driver.core.QueryLogger.NORMAL" level="TRACE" />
But also doesn't work.
My versions:
spring-data-cassandra-1.4.0
cassandra: 2.1.5
Add a QueryLogger #Bean and get the Cluster #Autowired in:
#Bean
public QueryLogger queryLogger(Cluster cluster) {
QueryLogger queryLogger = QueryLogger.builder()
.build();
cluster.register(queryLogger);
return queryLogger;
}
(+ obviously configure QueryLogger.Builder as required).
Don't forget to set log levels to DEBUG/TRACE in your application.yml:
logging.level.com.datastax.driver.core.QueryLogger.NORMAL: DEBUG
logging.level.com.datastax.driver.core.QueryLogger.SLOW: TRACE
Voilà!
Please check out this link and check if you added the query logger to your cluster definition like stated:
Cluster cluster = ...
QueryLogger queryLogger = QueryLogger.builder(cluster)
.withConstantThreshold(...)
.withMaxQueryStringLength(...)
.build();
cluster.register(queryLogger);
Let me know if it helped.
If you are using Spring Data Cassandra 2.4+ QueryLogger is not available anymore, it was replaced with RequestTracker which can be configured in application.yml or overridden depending on your needs.
The Java driver provides a RequestTracker interface. You can specify an implementation of your own or use the provided RequestLogger implementation by configuring the properties in the datastax-java-driver.advanced.request-tracker namespace. The RequestLogger tracks every query your application executes and has options to enable logging for successful, failed, and slow queries. Use the slow query logger to identify queries that are not within your defined performance.
Configuration:
datastax-java-driver.advanced.request-tracker {
class = RequestLogger
logs {
# Whether to log successful requests.
success.enabled = true
slow {
# The threshold to classify a successful request as "slow". If this is unset, all
# successful requests will be considered as normal.
threshold = 1 second
# Whether to log slow requests.
enabled = true
}
# Whether to log failed requests.
error.enabled = true
# The maximum length of the query string in the log message. If it is longer than that, it
# will be truncated.
max-query-length = 500
# Whether to log bound values in addition to the query string.
show-values = true
# The maximum length for bound values in the log message. If the formatted representation of
# a value is longer than that, it will be truncated.
max-value-length = 50
# The maximum number of bound values to log. If a request has more values, the list of
# values will be truncated.
max-values = 50
# Whether to log stack traces for failed queries. If this is disabled, the log will just
# include the exception's string representation (generally the class name and message).
show-stack-traces = true
}
More details.
If you're using Spring Data for Apache Cassandra version 2.0 or higher, then you can use your logging configuration to activate CQL logging. Set the log level of org.springframework.data.cassandra.core.cql.CqlTemplate to DEBUG, no need to mess with QueryLogger:
-Dlogging.level.org.springframework.data.cassandra.core.cql.CqlTemplate=DEBUG
This can, of course, be permanently done in the application.properties.

On Windows - where is a mqji.properties for me to use?

My application is a stand alone Java app, that customers download, install and run. It uses MQ to communicate with a host, which has been working for years. Neither myself nor customers have anything MQ installed on their Windows machines; we include and use com.ibm.mq.jar to do the work.
Apparently though, MQ needs a mqji.properties file in the classpath to prevent this :
Unable to load message catalog - mqji
com.ibm.mq.MQException: Message catalog not found
So my question is : Where do I get one??
Here is a copy of my mqji.properties file.
Copy and paste into a text editor.
Save as mqji.properties
Put the directory that this file is in into your CLASSPATH.
# mqjiEn_US.properties
# Messages produced by the Websphere MQ Java interface classes
# (shared by bindings and by client)
# Messages beginning with MQJI are explanations for exceptions
# Messages beginning with MQJE are errors
#
# From class MQDistributionList
#
1=MQJI001: Queue manager object was null.
2=MQJI002: Not connected to a queue manager.
3=MQJI003: No object records supplied.
4=MQJI004: No response records supplied.
5=MQJI005: Not enough response records supplied.
6=MQJI006: An object or response record was null.
7=MQJI007: openResponse parameter was null.
8=MQJI008: Null message passed to put.
9=MQJI009: Null put message options passed to put.
10=MQJI010: Number of message trackers and response records do not match.
11=MQJI011: The distribution list has been closed.
#
# From class MQEnvironment
#
12=Websphere MQ Client for Java v5.3
#
# From class MQGetMessageOptions
#
13=MQJI013: Unsupported version number - {0}
14=MQJI014: Insufficient data received from queue manager.
15=MQJI015: Erroneous eyecatcher : {0}
#
# From class MQManagedObject
#
16=MQJI016: Object has been closed.
17=MQJI017: No selectors specified.
#
# From class MQMD
#
18=MQJI015: Erroneous eyecatcher : {0}
19=MQJI018: Array copy error in MQMD
#
# From class MQMessage
#
20=MQJI019: Malformed UTF string in MQMessage::readLine
21=MQJI020: Unsupported codeset : {0}
22=MQJI021: String index error occurred during codeset conversion
23=MQJI015: Erroneous eyecatcher : {0}
#
# From class MQOD
#
24=MQJI022: Unmatched number of object and response records
#
# From class MQPutMessageOptions
#
25=MQJI023: Null MQMessageTracker object supplied
#
# From class MQMessageTracker
#
26=MQJI024: Array copy error in MQMessageTracker
#
# From class MQQueue
#
27=MQJI025: Null MQMessage passed to get
28=MQJI026: Null MQGetMessageOptions passed to get
29=MQJI027: The queue has been closed
30=MQJI028: Null MQMessage passed to put
31=MQJI029: Null MQPutMessageOptions passed to put
#
# From class MQQueueManager
#
32=MQJI030: The queue manager does not support distribution lists.
#
# From class MQS390FloatSupport
#
33=MQJI031: Number outside of range for double precision S/390 Float
#
# From class MQS390PackedDecimalSupport
#
34=MQJI032: Invalid sign nibble in packed decimal
35=MQJI033: Packed Decimal digit outside of range 0-9
36=MQJI034: Outside of range for short packed decimal (+/-999)
37=MQJI035: Outside of range for integer packed decimal (+/-9999999)
38=MQJI036: Outside of range for long packed decimal (0+/-999999999999999)
#
# From class MQException
#
39=MQJE001: Completion Code {0}, Reason {1}
40=MQJE001: An MQException occurred: Completion Code {0}, Reason {1}\n{2}
#
# Messages produced by client only classes...
#
41=MQJI037: Error occurred during Websphere MQ API call - reason code {0}
42=MQJI038: Unexpected internal error during string index processing
43=MQJE002: Socket output stream was null
44=MQJE003: IO error transmitting message buffer
45=MQJE004: Socket input stream was null
46=MQJE005: TSH eyecatcher not found. Eyecatcher was {0}
47=MQJE006: Internal error during array copy
48=MQJE007: IO error reading message data
49=MQJE008: IOException whilst sending status message
50=MQJE009: Failed to build API header
51=MQJE010: Unknown host: {0}
52=MQJE011: Socket connection attempt refused
53=MQJE012: Security error - cannot connect to host {0}
54=MQJE013: Error accessing socket streams
55=MQJE014: Control Point rejected connection
56=MQJE015: Error connecting to Control Point
57=MQJE016: MQ queue manager closed channel immediately during connect\n\Closure reason = {0}
58=MQJE017: MQ queue manager sent status error {0} during connect
59=MQJE018: Protocol error - unexpected segment type received
60=MQJE019: Error creating initial data segment
61=MQJE020: CCSID not supported by queue manager
62=MQJE021: Encoding not supported by queue manager
63=MQJE022: FAP level not supported by queue manager
64=MQJE023: Negotiation failed on maximum messages per batch
65=MQJE024: Sequence wrap value not supported by queue manager
66=MQJE025: Channel closed after two initial changes. Closure reason {0}
67=MQJE026: Queue manager sent status error {0} during connect
68=MQJE027: Queue manager security exit rejected connection with error code {0}
69=MQJE028: Channel closed during security exchanges
70=MQJE029: Unexpected message type sent by queue manager
71=MQJE030: IOException during security flows
72=MQJE031: Security exit closed the channel
73=MQJE032: Queue manager security exit rejected connection with reason code {0}
74=MQJE033: A required security flow was not sent by the queue manager
75=MQJE034: Unexpected message type sent by queue manager
76=MQJE035: Negotiated maximum transmission size is too small
77=MQJE036: Queue manager rejected connection attempt
78=MQJE037: Remote queue manager closed the connection
79=MQJE038: Unexpected segment type {0} received
80=MQJE039: IOException whilst building connection data stream
81=MQJE040: Channel closed by exit
82=MQJE041: Unsupported version number - (0)
83=MQJE042: Erroneous eyecatcher: {0}
84=MQJE043: Insuffucient data received from queue manager
85=MQJE044: Array copy error in MQMD
86=MQJE045: Malformed UTF string
87=MQJE046: Unsupported codeset : {0}
88=MQJE047: String index error occurred during codeset conversion
89=MQJE048: Invalid sign nibble in packed decimal
90=MQJE049: Packed Decimal digit outside of range 0-9
91=MQJE050: Outside of range for short packed decimal (+/-999)
92=MQJE051: Outside of range for integer packed decimal (+/-9999999)
93=MQJE052: Outside of range for long packed decimal (0+/-999999999999999)
94=Websphere MQ Bindings for Java v5.3
95=MQJE053: The Websphere MQ Bindings for Java library could not be loaded
96=MQJE054: The queue manager does not support distribution lists
97=MQJE055: The queue manager does not support version 2 Websphere MQ API structures
98=MQJE056: Initial negotiation failure
99=MQJE057: Channel closed during security exchanges
100=MQJE058: Invalid number of object or response records
101=MQJE059: String index error
102=MQJE060: Could not find class {0}
103=MQJE061: Could not find field {0}
104=MQJE062: Could not find method {0}
#
# Messages used by MQManagedConnectionJ11, ManagedConnectionFactories
# and MQManagedConnectionMetaData
#
105=MQJI039: Invalid ConnectionRequestInfo object
106=MQJI040: MQManagedConnection already destroyed
107=MQJI041: Method {0} is not supported by Websphere MQ Classes for Java
108=MQJI042: MQManagedConnection is not reusable
#
# Messages from MQManagedConnectionMetaData
#
109=IBM Websphere MQ
110=Command Level {0}
#
# Messages from MQXAi
#
111=Security manager prevented access to native methods library for MQ XA support.
112=Failed to load native methods library for MQ XA support.
#
# Messages from MQXAResource
#
113=xa_open failed
114=XA operation failed, see errorCode
115=XAResource closed
#
# Messages produced by com.ibm.mq.MQMsg2
#
116=MQJE063: Unsupported character set {0}
117=MQJE064: Unsupported version of MQMD structure {0}
118=MQJE065: Inconsistent internal state detected
# message when server doesn't support client XA
119=client connection not XA enabled
#
# Messages produced via SSL options on a client connection
#
120=MQJE066: {0} provided as an unsupported object type
121=MQJE067: Peer name {0} did not match requested name {1}
122=MQJE068: Server certificate has been revoked
123=MQJE069: Unable to contact CertStore
124=MQJE070: SSL Protocol error: Channel not configured for SSL?
The correct answer here is that the customers need to download the actual WMQ client and install it with your application and that your application should be distributed without the WMQ client jars. This is true for a variety of reasons:
You are not authorized to redistribute the vendor's code. When WMQ client or server code is bundled in an OEM license, it is the full install and not just a few jar files.
One of the reasons for installing the full client is to get support. The full client install is free and includes a number of diagnostic facilities. The only reason not to require a full install is convenience and if you are charging money for the app any convenience is far outweighed by potential liability.
Maintenance. If the customer installs the WMQ client then they can apply periodic maintenance from IBM and know that it is a complete and intact distribution. Unless your company is prepared to guarantee that the components they choose to redistribute are a valid installation, you are better off using the official install. Given the nature of the question is asking this community what the valid non-vendor installation is, I don't see how your company can stand behind this configuration of IBM's code.
Regulatory compliance. If any of your customers are subject to PCI, SOX, HIPAA or government regulations, certification cannot be achieved under this configuration. For example, to be PCI compliant the deployed application must have applied Fix Pack 7.0.1.3 quite some time ago. Without the full install, it is impossible to apply the fix pack or prove to an auditor it has been installed based on the jars.
Security. If you are not using SSL or an exit than it is possible for your customers to impersonate one another or the WMQ administrative account. In order to be using SSL you would have to have installed the IBM JCCE provider which comes in GSKit, which is part of the full client install and contains native compiled C code ot available in jar files. Based on the description of the app, I'm guessing any of your customers can remotely, anonymously administer your QMgr and execute arbitrary OS code. Not good.
So the correct answer is for you and your clients to go download and install the full WMQ client (SupportPac MQC7) and configure the app to run on that. Anything less places your clients and your company at risk.
And if you have any doubt about the security exposures I mentioned, please refer to the IMPACT Hardening WebSphere MQ presentation and the WebSphere MQ Hands-on Security Lab posted here.

Categories