How to set HTTP outbound gateway sending request using big buffer - file-upload

I use Spring Integration 4.3.9.RELEASE and Apache HTTP Component HttpClient (4.5.2) to relay request which includes 300k uploaded file to backend service. Sometimes the whole configuration works fine. But sometimes it doesn't perform very well and it will toke almost 10 minutes to send request and get ressponse. I write some tests in pure Java (refer to Sending HTTP POST Request In Java) and results as following.
+------------------------------+------------------------+
| Data block size | Pause | Totally time consuming |
+------------------------------+------------------------+
| 2k | 1 second | ~6 minutes |
| 2k | 0.1 seocnd | ~33 seconds |
| 4k | 0.1 second | ~16 seconds |
| 0.2k | 0.1 second | ~6 minutes |
+------------------------------+------------------------+
The scenarios pausing 1s per 2k and pausing 0.1s per 0.2k both have a close time elapsed value. I guess what mostly probably happenned is sending data with smaller block (0.2k) but less pause interval (0.1s). It is obviously unsatisfying that it takes 10 minutes to get response.
Then how to set the buffer a bit bigger to ensure performance?
My configuration is as following.
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<constructor-arg>
<bean class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
<constructor-arg>
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="org.apache.http.impl.client.HttpClients"/>
<property name="targetMethod" value="createMinimal"/>
</bean>
</constructor-arg>
<property name="connectTimeout" value="${wonders.cloud.api.request.timeout}" />
<property name="readTimeout" value="${wonders.cloud.api.request.timeout}" />
</bean>
</constructor-arg>
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.StringHttpMessageConverter" />
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
<bean class="org.springframework.http.converter.FormHttpMessageConverter">
</bean>
</list>
</property>
</bean>
<bean id="objectMapper" class="org.springframework.integration.support.json.Jackson2JsonObjectMapper">
<constructor-arg ref="jacksonObjectMapper" />
</bean>
<bean id="jacksonObjectMapper" class="com.fasterxml.jackson.databind.ObjectMapper" >
<property name="dateFormat">
<bean class="java.text.SimpleDateFormat">
<constructor-arg index="0" type="java.lang.String" value="yyyy-MM-dd'T'HH:mm:ss" />
</bean>
</property>
<property name="serializationInclusion" value="#{ T(com.fasterxml.jackson.annotation.JsonInclude.Include).NON_NULL }" />
</bean>
<bean class="org.springframework.beans.factory.config.MethodInvokingBean">
<property name="targetObject" ref="jacksonObjectMapper"/>
<property name="targetMethod" value="disable"/>
<property name="arguments" value="#{ T(com.fasterxml.jackson.databind.DeserializationFeature).FAIL_ON_UNKNOWN_PROPERTIES }"/>
</bean>
<bean class="org.springframework.beans.factory.config.MethodInvokingBean">
<property name="targetObject" ref="jacksonObjectMapper"/>
<property name="targetMethod" value="enable"/>
<property name="arguments" value="#{ T(com.fasterxml.jackson.databind.DeserializationFeature).READ_UNKNOWN_ENUM_VALUES_AS_NULL }"/>
</bean>
<int-http:inbound-gateway id="certificateInboundGateway"
path="/{uuid}/certificate"
supported-methods="POST"
request-channel="certificateRequestChannel"
reply-channel="certificateResponseChannel"
reply-key="fullway"
view-name="index">
<int-http:header name="uuid" expression="#pathVariables.uuid" />
</int-http:inbound-gateway>
<int:channel id="certificateRequestChannel" />
<int:channel id="certificateResponseChannel" />
<int:chain id="certificateProcessChain"
input-channel="certificateRequestChannel"
output-channel="certificateResponseChannel">
<int:header-enricher>
<int:header name="multipartForm" expression="payload"/>
</int:header-enricher>
<int:transformer expression="headers.uuid" />
<int:gateway request-channel="crmMemberInfoRetrieveChannel" />
<int:filter expression="payload != null" />
<int:transformer expression=" T(com.wd.fw.business.facade.huayan.transformer.WondersCloudObjectTransformer).buildCertificateForm(headers.multipartForm, payload.get('userid'), '${wonders.cloud.api.token}') " />
<int:transformer ref="commonHeaderEnricher" method="transform" />
<int:header-enricher>
<int:header name="octopus_sid" expression="'${wonders.cloud.api.octopus.sid}'" overwrite="true" />
<int:header name="Content-Type" expression="'multipart/form-data'" overwrite="true" />
<int:header name="octopus_apiid" expression="'${wonders.cloud.api.certificate.octopus.apiid}'" />
</int:header-enricher>
<int-http:outbound-gateway url="${wonders.cloud.api.protocol}://${wonders.cloud.api.host}/${wonders.cloud.api.context.path}"
http-method="POST"
header-mapper="headerMapper"
rest-template="restTemplate"
charset="UTF-8"
expected-response-type="java.lang.String">
<int-http:request-handler-advice-chain>
<ref bean="retrier" />
</int-http:request-handler-advice-chain>
</int-http:outbound-gateway>
<int:gateway request-channel="dataEncryptChannel" />
</int:chain>
Thanks a lot.

You can try something like this:
ConnectionConfig connConfig = ConnectionConfig.custom()
.setBufferSize(DESIRED_BUFFER_SIZE)
.build();
CloseableHttpClient client = HttpClients.custom()
.setDefaultConnectionConfig(connConfig)
.build();
Setting socket buffer size in Apache HttpClient
Is there a way to see what the current value and change it for the socket buffer size used by Apache Http Client?
But why do you think that the problem is not on the server side?

Increasing the buffer size doesn't help to improve the performance.
Eventually, I have to create a service activator which will send out request to remote via pure java approach mentioned in my question.
I write some tests in pure Java (refer to Sending HTTP POST Request In Java) and results as following.
I also compare the request sent to server and can not found any difference. It is quite odd.

Related

How to set AbandonedConfig in JedisPool - JedisExhaustedPoolException error

I am facing an issue similar to the one jedis-1929. We are using JedisPool with maxTotal=400 and have ensured that after using jedis from pool.getResource() we are returning the connection back to the pool in finally block using jedis.close() method. Version of jedis is 3.0.0. The issue appears after continuously running the program for several days. We are getting/setting key-value pair in Redis around 0.1m times per minute. The key and values are both quite small, values approx 120 bytes. Use-case is mostly read heavy.
Wanted to set AbandonConfig to ensure leaked connections if any get closed after a default timeout, but don't see a way to set AbandonConfig related settings for JedisPool. Following is the exception we get, when numActives become equal to maxTotal
redis.clients.jedis.exceptions.JedisExhaustedPoolException: Could not get a resource since the pool is exhausted
at redis.clients.jedis.util.Pool.getResource(Pool.java:53)
at redis.clients.jedis.JedisPool.getResource(JedisPool.java:234)
at com.til.ibeat.connection.RedisConnection.getconnection(RedisConnection.java:52)
at com.til.ibeat.service.impl.RedisCacheServiceImpl.pushToRedisSet(RedisCacheServiceImpl.java:188)
at com.til.ibeat.service.impl.MessageEnrichService.getVisitorType(MessageEnrichService.java:541)
at com.til.ibeat.service.impl.MessageEnrichService.populateVisitorType(MessageEnrichService.java:439)
at com.til.ibeat.service.impl.IbeatEventLogService.process(IbeatEventLogService.java:111)
at com.til.ibeat.service.impl.IbeatEventLogService$2.call(IbeatEventLogService.java:70)
at com.til.ibeat.service.impl.IbeatEventLogService$2.call(IbeatEventLogService.java:67)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.util.NoSuchElementException: Pool exhausted
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:452)
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:361)
at redis.clients.jedis.util.Pool.getResource(Pool.java:50)
... 12 common frames omitted
Following is our configuration:
<bean id="redisPool2" class="redis.clients.jedis.JedisPool">
<constructor-arg index="0" type="org.apache.commons.pool2.impl.GenericObjectPoolConfig" ref="poolConfig2"/>
<constructor-arg index="1" type="java.lang.String" value="${jedis2.host}" />
<constructor-arg index="2" type="int" value="${jedis2.port:6379}"/>
<constructor-arg index="3" type="int" value="${jedis2.timeout.millis:200}"/>
<constructor-arg index="4" type="java.lang.String" value="${jedis2.password}" />
</bean>
<bean id="poolConfig2" class="org.apache.commons.pool2.impl.GenericObjectPoolConfig">
<property name="maxTotal" value="${jedis2.max.total:-1}" />
<property name="maxIdle" value="${jedis2.max.idle:50}" />
<property name="minIdle" value="${jedis2.min.idle:3}" />
<property name="testOnBorrow" value="${jedis2.test.on.borrow:true}" />
<property name="testOnReturn" value="${jedis2.test.on.return:false}" />
<property name="testWhileIdle" value="${jedis2.test.while.idle:false}" />
<property name="minEvictableIdleTimeMillis" value="${jedis2.min.evictable.idle.time.millis:2000}" />
<property name="timeBetweenEvictionRunsMillis" value="${jedis2.time.between.eviction.runs:30000}" />
<property name="numTestsPerEvictionRun" value="${jedis2.tests.per.eviction.run:10}" />
<property name="blockWhenExhausted" value="${jedis2.block.when.exhausted:false}" />
<property name="jmxEnabled" value="${jedis2.jmx.enabled:true}"/>
<property name="jmxNamePrefix" value="${jedis2.host}"/>
</bean>

Apache Ignite data loss when one node goes down

I'm new with Ignite and I'm trying to test data quality and availability of Ignite cluster.
I use the below xml configuration for setting cluster,
<property name="discoverySpi">
<bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
<property name="socketTimeout" value="50000" />
<property name="networkTimeout" value="50000" />
<property name="reconnectCount" value="5" />
<property name="ipFinder">
<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">
<property name="addresses">
<list>
<value>x.x.x.1:47500..47509</value>
<value>x.x.x.2:47500..47509</value>
</list>
</property>
</bean>
</property>
</bean>
</property>
</bean>
Also and jthe CacheConfiguration is,
<bean id="cache-template-bean" class="org.apache.ignite.configuration.CacheConfiguration">
<property name="name" value="CACHE_TEMPLATE*"/>
<property name="cacheMode" value="PARTITIONED" />
<property name="backups" value="1" />
<!-- <property name="backups" value="2" />
<property name="backups" value="3" /> -->
<property name="atomicityMode" value="TRANSACTIONAL" />
<property name="writeSynchronizationMode" value="PRIMARY_SYNC" />
<property name="rebalanceBatchSize" value="#{4 * 1024 * 1024}" />
<property name="rebalanceMode" value="ASYNC" />
<property name="statisticsEnabled" value="true" />
<property name="rebalanceBatchesPrefetchCount" value="4" />
<property name="defaultLockTimeout" value="5000" />
<property name="readFromBackup" value="true" />
<property name="queryParallelism" value="6" />
<property name="nodeFilter">
<bean class="org.apache.ignite.util.AttributeNodeFilter">
<constructor-arg>
<map>
<entry key="ROLE" value="data.compute"/>
</map>
</constructor-arg>
</bean>
</property>
</bean>
My scenarios are,
Loaded the 5 million data when all the 3 nodes
Bring one node down
The count shows 3.75 million. (Data loss)
Bringing the node up counts 5 million again.
I tried backup 1,2,3 all resulted in the same data loss. As per Ignite documents, appears the data loss should not happen. If this fixed, I can try adding data when the node is down and check how it behaves.
Any suggestions, please?
Ash
The main idea of the baseline topology and persistence is to prevent unnecessary rebalance and store data only in specified server nodes. When a baseline node stopped, it is expected that one will back soon and the rebalance process is not triggered. You could exclude the node from the baseline using api or control.sh utility.
IgniteCache.size() returns the number of primary entries. So when a baseline node is stopped, size() shows a smaller number indicating that a number of primary entries is not accessible.
In your case the data is not lost by two reasons:
1. The data is persisted in backup entries on alive baseline nodes.
2. The primary and backup entries located on the stopped node will back to the cluster after the node started.
[1] https://apacheignite.readme.io/docs/baseline-topology

how to create read only user in activeMQ web console

I'm trying to create a read only user in activeMQ console, I found this and this too. the second post from stackoverflow is not helpful because it deployed the web console to an external server. The second page from pivotal looks promising and I tried with activeMQ version 5.14.1 but it didn't work too. activeMQ didn't even start whenever I try accessing the console with the user/password specified for read only user I get !role error.
Any ideas?
Thanks in advance!
found the answer in here I had to change class="org.eclipse.jetty.http.security.Constraint" to class="org.eclipse.jetty.util.security.Constraint" in step number 1
Links to Pivotal are dead. For those who want a simple solution you can change these lines from jetty.xml :
<bean id="securityConstraintMapping" class="org.eclipse.jetty.security.ConstraintMapping">
<property name="constraint" ref="securityConstraint" />
<property name="pathSpec" value="/api/*,/admin/*,*.jsp" />
</bean>
<bean id="adminSecurityConstraintMapping" class="org.eclipse.jetty.security.ConstraintMapping">
<property name="constraint" ref="adminSecurityConstraint" />
<property name="pathSpec" value="*.action" />
</bean>
to
<bean id="securityConstraintMapping" class="org.eclipse.jetty.security.ConstraintMapping">
<property name="constraint" ref="securityConstraint" />
<property name="pathSpec" value="/api/*,*.jsp,*.html,*.png,*.css,/admin/js/*" />
</bean>
<bean id="adminSecurityConstraintMapping" class="org.eclipse.jetty.security.ConstraintMapping">
<property name="constraint" ref="adminSecurityConstraint" />
<property name="pathSpec" value="*.action" />
</bean>

Code Expire in CAS SSO Server

I deployed my CAS server with OAuth protocol support
I've added this code to my deployerConfigContext.xml
<bean class="org.jasig.cas.services.RegisteredServiceImpl">
<property name="id" value="1"/>
<property name="name" value="the_key"/>
<property name="description" value="the_secret"/>
<property name="theme" value="my great webapp for OAuth"/>
<property name="serviceId" value="http://localhost:8080/cas/login"/>
<property name="evaluationOrder" value="10000001"/>
<property name="allowedAttributes">
<list>
<!-- facebook -->
<value>the_key</value>
<value>the_secret</value>
</list>
</property>
</bean>
and
<bean id="ticketRegistry" class="org.jasig.cas.ticket.registry.DefaultTicketRegistry">
<constructor-arg index="0" value="1000"/>
<constructor-arg index="1" value="1"/>
<constructor-arg index="2" value="16"/>
</bean>
to define my ticketRegistry
So my OAuth client secret code key is the_secret and the_key
but when I load this URL http://localhost:8080/cas/oauth2.0/accessToken?client_secret=the_secret&grant_type=refresh_token&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fcas%2Flogin&code=0&client_id=the_key to test my OAuth protocol, I've got this exception
<Code Expired 0>
Why and how could I fix it?
You need to define two CAS services :
one for internal mechanism of OAuth server support (with CASservice.serviceId = http://localhost:8080/cas/oauth2.0/callbackAuthorize)
one for the each client OAuth application you want to authorize (with oauthclient.key = CASservice.name, oauthclient.secret = CASservice.description, oauthclient.redirect_uri should start with CASservice.serviceId).
The documentation : https://wiki.jasig.org/display/CASUM/OAuth+server+support, part 3...

How to Configure SSL over Database in Spring?

I want to add SSL security in the Database layer. I am using Struts2.1.6, Spring 2.5, JBOSS 5.0 and Informix 11.5. Any idea how to do this?
I have researched through a lot on the internet but could not find any solution.
Please suggest!
Here is my datasource and entity manager beans which is working perfect without SSL:
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="INFORMIX" />
<property name="showSql" value="true" />
</bean>
</property>
</bean>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.informix.jdbc.IfxDriver" />
<property name="url"
value="jdbc:informix-sqli://SERVER_NAME:9088/DB_NAME:INFORMIXSERVER=SERVER_NAME;DELIMIDENT=y;" />
<property name="username" value="username" />
<property name="password" value="password" />
<property name="minIdle" value="2" />
</bean>
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean" lazy-init="false">
<property name="targetObject" ref="dataSource" />
<property name="targetMethod" value="addConnectionProperty" />
<property name="arguments">
<list>
<value>characterEncoding</value>
<value>UTF-8</value>
</list>
</property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" scope="prototype">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
Thankyou very much for your suggestion. So basically I need to set something like this in my applicationContext.xml, Please correct me if I am wrong:
<property name="username" value="username" />
<property name="password" value="password" />
**<property name="sslConnection" value="true" />**
<property name="minIdle" value="2" />
But how do I set the SSL certificate in java runtime. The link which you have provided is good but for some reason I am not able to follow. Please put your suggestion.
Using SSL for the communication between an application and a database is something that has to be supported by the database server (and the JDBC driver).
According to the documentation, this is supported by Informix Dynamic Server (IDS) since version 11.50.
You can use SSL support in your Java applications if you use IBM Data Server Driver for JDBC and SQLJ type 4 connectivity to DB2® for z/OS® Version 9 or later, to DB2 Database for Linux®, UNIX®, and Windows® Version 9.1, Fix Pack 2 or later, or to IBM Informix® Dynamic Server (IDS) Version 11.50 or later.
(...)
To use SSL connections, you need to:
Configure connections to the data source to use SSL. (link)
Configure your Java Runtime Environment to use SSL. (link)
The documentation should help.
If you're using a version of IDS prior to 11.50, then I'm afraid you'll have to use SSH tunneling.