将多线程与 Redis 一起使用,使用 jedis 连接池



我读到redis是每个用户/客户端的单线程。

是否可以使用 jedis 连接池来实现多线程行为?

基本上,不同的 jedis 客户端请求将使用从 jedis 连接池中遵守的不同连接,以向一个 redis 服务器发送它们的命令。

由于客户端请求使用不同的连接,因此一个 redis 应该是服务器多个请求并行的,对吗?

是否可以使用 jedis 连接池来实现多线程行为?

虽然你使用多个连接或线程或处理来与 redis 通信,但这些命令都放在一个队列上,redis 会一个接一个地获取并逐个执行。每个命令都是原子的。所以这仍然是 redis 方面的单线程行为。

由于客户端请求使用不同的连接,因此一个 redis 应该是服务器多个请求并行的,对吗?

并非总是如此,来自不同客户端的命令可能会以任意顺序到达 redis,因此如果这些命令具有某种数据关系,就会发生危险的事情。

考虑这个简单的场景,如果 Redis 有一个计数器 S,如果所有客户端都执行 INCR 命令,那么没关系,因为每个命令都是原子执行的,但是如果某个客户端的代码是这样的:

s = get S
t = s + 10
set S t

那么事情就不对了。您应该使用 Multi/exec 命令来确保多命令是原子的,而不仅仅是一个命令。有关 redis 交易的更多信息,您可以参考此页面。它很详细。

我在这里回答了类似的问题,您可以查看详细信息。

TL/DR:Redis 本身仍将是单线程的,但在宏大的计划中,Redis 用来回答的时间比网络使用的时间少几个数量级。是的,您将从多线程中受益。

编辑:沿着请求管道,您将有3个点按顺序处理请求。当数据包通过一条线(您只有一条线,但来自不同请求的数据包将被混合(向前和向后发送时,以及当 Redis 为您的请求提供服务时。但Redis本身也不傻。您的请求将来自网络套接字,并将经过预处理并写入客户端缓冲区。这部分是并行处理的。然后 Redis 的主循环将从队列中挑选您的命令,处理并将响应写入客户端缓冲区。这部分是按顺序完成的。然后,来自客户端缓冲区的响应将被打包并通过线路发送回给您。这也是同时进行的。

这在我的(基于 Web(多线程环境中工作正常。

确保 RedisInterface 实例在类中是静态的。

public class RedisInterface implements Closeable
{   
/*      
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>   
*/
private JedisPool jedisPool =  null;
private synchronized void initializePool()
{
if(jedisPool!=null) return;
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(Integer.parseInt(AppConfig.REDIS_MAX_CONN)); //max conn count
poolConfig.setMaxIdle(Integer.parseInt(AppConfig.REDIS_MAX_IDLE_CONN)); //max idle conn count
poolConfig.setMaxWaitMillis(Long.parseLong(AppConfig.REDIS_MAX_WAIT_TIME)); // max wait time for new connection (before throwing exception)
jedisPool = new JedisPool(poolConfig, 
AppConfig.REDIS_IP, 
Integer.parseInt(AppConfig.REDIS_PORT),
Integer.parseInt(AppConfig.REDIS_CONN_TIMEOUT));
}
//not synchronized after testing thread safety of jedisPool.getResource()
protected Jedis getJedis()
{               
if(jedisPool==null)
initializePool();
Jedis jedis = jedisPool.getResource();
return jedis;     
}

public Long set(final byte[] key, final byte[] field, final byte[] value)
{
Jedis redis = null; 
Long ret =0L;
try
{
redis = getJedis();
ret = redis.hset(key, field, value);            
redis.expire(key, Integer.parseInt(AppConfig.REDIS_EXPIRE_MIN)*60); //      
}
finally
{
if(redis!=null)         
redis.close();
}
return ret;
}
public byte[] get(final byte[] key, final byte[] field) {
Jedis redis = null ;
byte[] valueBytes = null;
try
{
redis = getJedis();
valueBytes = redis.hget(key, field);
}
finally
{       
if(redis!=null)             
redis.close();
}
return valueBytes;
}
@Override
public void close() throws IOException {
if(jedisPool!=null)     
jedisPool.close();      
}
}

最新更新