Spring Redis template with Jedis connection factory , Redis standalone configuration and multi-threading - multithreading

I am using Spring Redis template in a multi-threaded environment. One thread saves the data into Redis and other one (the scheduler) fetches the data from it. JedisConnectionFactory is used in redis template. Following is the code snippet for obtaining redis connection:
JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory jedisConnectionFactory = null;
try {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(hostName,
port);
jedisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration);
} catch (RedisConnectionFailureException e) {
LOGGER.error("Connection break with redis " + e.getMessage());
}
return jedisConnectionFactory;
}
/**
* Redis template.
*
* #return the redis template
*/
#Bean
public RedisTemplate<String, Object> redisTemplate() {
final RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(jedisConnectionFactory());
template.setValueSerializer(new GenericToStringSerializer<Object>(Object.class));
template.setEnableTransactionSupport(true);
return template;
}
The instance of redis template is obtained using constructor auto-wiring as follows:
#Autowired
public A(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
I am getting an exception while fetching data from Redis using "findAll()" method of redis template:
org.springframework.data.redis.RedisConnectionFailureException: java.net.SocketException: Connection reset by peer: socket write error; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketException: Connection reset by peer: socket write error
Below are my findings:
connection reset by peer exception occurs when TCP socket is to be "closing" and your code to not have yet been notified. (the thread for findAll has not been notified for the closed connection).
Redis template is thread safe (only if connection pool is used) and handles connection management on its own. It may happen that when thread saved data into redis and closed the connection and during that only, the fetch operation occured and demanded data. In that case, the server might have issued RST command but fetch operation might have not obtained it.
Jedis pool config can be used; but there are depreciated methods in this that can later cause upgradation issues.
Please suggest best method to handle multi-threading with "JedisConnectionFactory", "RedisStandAloneConfiguration" and "RedisTemplate".

The cause of this problem was :
Redis Template is thread safe but only when it uses connection pooling; If connection pool is not used then the simultaneous connection calls result in RST signal from either (server / client) side and thus 'connection reset by peer' exception is thrown. SO, if we need to use Redis template then create a connection pool and set 'maxIdle' and 'maxTotal' for the pool config. Also, make sure that the system should not goes down (sleep) in any case.
Code that worked correctly:
#Bean
JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory jedisConnectionFactory = null;
try {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(hostName,
port);
jedisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration);
jedisConnectionFactory.getPoolConfig().setMaxTotal(50);
jedisConnectionFactory.getPoolConfig().setMaxIdle(50);
} catch (RedisConnectionFailureException e) {
e.getMessage();
}
return jedisConnectionFactory;
}
#Bean
public RedisTemplate<String, Object> redisTemplate() {
final RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(jedisConnectionFactory());
template.setValueSerializer(new GenericToStringSerializer<Object>(Object.class));
template.setEnableTransactionSupport(true);
return template;
}

Related

how to pass cassandra cluster connection from one bolt to another bolt

Storm Topology reads data from kafka and write into cassandra tables
In Storm i am creating cassandra cluster connection and session in prepare method.
cassandraCluster = Cluster.builder().withoutJMXReporting().withoutMetrics()
.addContactPoints(nodes)
.withRetryPolicy(DowngradingConsistencyRetryPolicy.INSTANCE)
.withReconnectionPolicy(new ExponentialReconnectionPolicy(100L,
TimeUnit.MINUTES.toMillis(5)))
.withLoadBalancingPolicy(
new TokenAwarePolicy(new RoundRobinPolicy()))
.build();
session = cassandraCluster.connect(keyspace);
In execute method i can process the tuple and save it in cassandra table
Suppose if i want to write data from single tuple into multiple table
Writing separate bolt for each table will be good choice. But i have to create cluster connection and session each table in each bolt.
But in this link single connection per cluster will be a good idea for performance
http://www.datastax.com/dev/blog/4-simple-rules-when-using-the-datastax-drivers-for-cassandra
Did any of you have any idea on creating cluster connection in one bolt and use this connection in other bolt?
It depends on how storm allocates the bolts and spouts to the workers. You can't assume that you can can share connections between bolts because they might be running in different workers (read: JVMs) or on different nodes entirely.
See my answer here: Mongo connection pooling for Storm topology
Might look something like this pseudocode:
public class CassandraBolt extends BaseRichBolt {
private static final long serialVersionUID = 1L;
private static Logger LOG = LoggerFactory.getLogger(CassandraBolt.class);
OutputCollector _collector;
// whatever your cassandra session is
// has to be transient because session is not serializable
protected transient CassandraSession _session;
#SuppressWarnings("rawtypes")
#Override
public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
_collector = collector;
// maybe get properties from stormConf instead of hard coding them
cassandraCluster = Cluster.builder().withoutJMXReporting().withoutMetrics()
.addContactPoints(nodes)
.withRetryPolicy(DowngradingConsistencyRetryPolicy.INSTANCE)
.withReconnectionPolicy(new ExponentialReconnectionPolicy(100L,
TimeUnit.MINUTES.toMillis(5)))
.withLoadBalancingPolicy(
new TokenAwarePolicy(new RoundRobinPolicy()))
.build();
_session = cassandraCluster.connect(keyspace);
}
#Override
public void execute(Tuple input) {
try {
// use _session to talk to cassandra
} catch (Exception e) {
LOG.error("CassandraBolt error", e);
_collector.reportError(e);
}
}
#Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
// TODO Auto-generated method stub
}
}

HornetQ allows only one session per connection

I am using HornetQ in distributed transaction environment with MDBs. I read from the JMS documentation that we should not create Connection instance frequently, rather we should reuse the connection and create JMS sessions as and when required. So I wrote a code which creates JMS connection and then reuse it. But I have encountered the following exception while reusing the JMS connection object.
Could not create a session: Only allowed one session per connection.
See the J2EE spec, e.g. J2EE1.4 Section 6.6
I read few blogs on this but they all are specific to seam framework.
Here is my code
public class DefaultService implements IMessageService {
private static final long serialVersionUID = 1L;
private static final Logger logger = LogManager.getLogger(DefaultService.class);
private static final String connectionFactoryJndiName = "java:/JmsXA";
private static volatile Connection connection = null;
private Session session = null;
#Override
public void sendMessage(String destinationStr, Serializable object) {
try {
Destination destination = jmsServiceLocator.getDestination(destinationStr);
ObjectMessage message = session.createObjectMessage();
message.setObject(object);
MessageProducer messageProducer = session.createProducer(destination);
messageProducer.send(destination, message);
messageProducer.close();
logger.trace("Sent JMS Messagae for: " + object.getClass().getName());
}
catch (NamingException e) {
throw new RuntimeException("Couldn't send jms message", e);
}
catch (JMSException e) {
throw new RuntimeException("Couldn't send jms message", e);
}
}
#Override
public void close() {
try {
if (session != null) {
session.close();
}
}
catch (Exception e) {
logger.error("Couldn't close session", e);
}
}
}
I am using JBoss EAP 6.
Did I miss any settings here?
On JCA connection (i.e. connection where you used the PooledConnectionFactory) you are supposed to create one Session only per connection. That is part of the EE specification. (It has always been).
This is because these connections are pooled and it would be impossible to put them back on the pool if you were using more than one session per connection.
If you switch for non pooled connection factories (the ones that are meant for remote clients) you would have it working the way you wanted but then you would miss pooling from the application server. EE components are usually short lived and opening / closing JMS Connections (any connection to be more precise) it's an expensive operation.

Netty 4 multithreaded DefaultEventExecutorGroup

I started a netty4 nio server with multiple business threads for handling long-term businesses
like below
public void start(int listenPort, final ExecutorService ignore)
throws Exception {
...
bossGroup = new NioEventLoopGroup();
ioGroup = new NioEventLoopGroup();
businessGroup = new DefaultEventExecutorGroup(businessThreads);
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, ioGroup).channel(NioServerSocketChannel.class)
.childOption(ChannelOption.TCP_NODELAY,
Boolean.parseBoolean(System.getProperty(
"nfs.rpc.tcp.nodelay", "true")))
.childOption(ChannelOption.SO_REUSEADDR,
Boolean.parseBoolean(System.getProperty(
"nfs.rpc.tcp.reuseaddress", "true")))
.childHandler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch)
throws Exception {
ch.pipeline().addLast("decoder",
new Netty4ProtocolDecoder());
ch.pipeline().addLast("encoder",
new Netty4ProtocolEncoder());
ch.pipeline().addLast(businessGroup, "handler",
new Netty4ServerHandler());
}
});
b.bind(listenPort).sync();
LOGGER.warn("Server started,listen at: " + listenPort + ", businessThreads is " + businessThreads);
}
I found that there was only one thread working when the server accepted one connection.
How can I bootstrap a server that can start multiple business threads for only one connection?
Thanks,
Mins
Netty will always use the same thread for one connection. It's by design. If you would like to change this you may be able to implement a custom EventExecutorGroup and pass it in when adding your ChannelHandler to the ChannelPipeline.
Be aware this may result in messed up order of packets.

Netty OrderedMemoryAwareThreadPoolExecutor not creating multiple threads

I use Netty for a multithreaded TCP server and a single client persistent connection.
The client sends many binary messages (10000 in my use case) and is supposed to receive an answer for each message. I added an OrderedMemoryAwareThreadPoolExecutor to the pipeline to handle the execution of DB calls on multiple threads.
If I run a DB call in the method messageReceived() (or simulate it with Thread.currentThread().sleep(50)) then all events are handled by a single thread.
5 count of {main}
1 count of {New
10000 count of {pool-3-thread-4}
For a simple implementation of messageReceived() the server creates many executor threads as expected.
How should I configure the ExecutionHandler to get multiple threads executors for the business logic, please?
Here is my code:
public class MyServer {
public void run() {
OrderedMemoryAwareThreadPoolExecutor eventExecutor = new OrderedMemoryAwareThreadPoolExecutor(16, 1048576L, 1048576L, 1000, TimeUnit.MILLISECONDS, Executors.defaultThreadFactory());
ExecutionHandler executionHandler = new ExecutionHandler(eventExecutor);
bootstrap.setPipelineFactory(new ServerChannelPipelineFactory(executionHandler));
}
}
public class ServerChannelPipelineFactory implements ChannelPipelineFactory {
public ChannelPipeline getPipeline() throws Exception {
pipeline.addLast("encoder", new MyProtocolEncoder());
pipeline.addLast("decoder", new MyProtocolDecoder());
pipeline.addLast("executor", executionHandler);
pipeline.addLast("myHandler", new MyServerHandler(dataSource));
}
}
public class MyServerHandler extends SimpleChannelHandler {
public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e) throws DBException {
// long running DB call simulation
try {
Thread.currentThread().sleep(50);
} catch (InterruptedException ex) {
}
// a simple message
final MyMessage answerMsg = new MyMessage();
if (e.getChannel().isWritable()) {
e.getChannel().write(answerMsg);
}
}
}
OrderedMemoryAwareThreadPoolExecutor guarantees that events from a single channel are processed in order. You can think of it as binding a channel to a specific thread in the pool and then processing all events on that thread - although it's a bit more complex than that, so don't depend on a channel always being processed by the same thread.
If you start up a second client you'll see it (most likely) being processed on another thread from the pool. If you really can process a single client's requests in parallel then you probably want MemoryAwareThreadPoolExecutor but be aware that this offers no guarantees on the order of channel events.

JDBC auto commit for connection shared across threads

I have a servlet where I get a Connection object which is then handed to two worker threads for various activities. I now need to add a transaction on one thread.
If I start a transaction like this:
connection.setAutoCommit(false);
would that impact both threads? I think it would.
Do I have to get a separate connection of each thread?
Thanks
I think what you are doing is very bad practice. You can't share a JDBC connection among threads.
If you are running under an application server (like TOMCAT/JBoss/WebSphere/WebLogic) use a proper DataSource to get your connections as you need them.
Look at your Application Server documentation to get information on how to do that.
You will have something like this in your servlet:
public void doGet(HttpServletRequest req, HttpServletResponse resp)
{
Connection c = null;
try {
c = ...; /* preferred way of getting a connection in your AppServer
// do what you need with your JDBC connection
} catch (Exception e) {
// handle errors
} finally {
c.close(); /* you will need another TRY/CATCH here */
}
}
Similarly, your worker threads will have something like:
public void run()
{
Connection c = null;
try {
c = ...; /* preferred way of getting a connection in your AppServer
// do what you need with your JDBC connection
} catch (Exception e) {
// handle errors
} finally {
c.close(); /* you will need another TRY/CATCH here */
}
}
Eventually, you could set auto commit to whatever you need on separate connection objects.

Resources