我正在尝试使用 sentinal redis 从 redis 获取/设置 key 。我试图用大约 2000 个并发请求对我的设置进行压力测试。
我用哨兵把一个键放在redis上,然后我从redis执行了1000个并发的get请求。
但底层绝地武士使用我的哨兵阻止调用 getResource()(池大小为 500),我实现的总体平均响应时间约为 500 毫秒,但我的目标约为 10 毫秒。
我在这里附上 jvisualvm 快照的示例
redis.clients.jedis.JedisSentinelPool.getResource() 98.02227 4.0845232601E7 ms 4779
redis.clients.jedis.BinaryJedis.get() 1.6894469 703981.381 ms 141
org.apache.catalina.core.ApplicationFilterChain.doFilter() 0.12820946 53424.035 ms 6875
org.springframework.core.serializer.support.DeserializingConverter.convert() 0.046286926 19287.457 ms 4
redis.clients.jedis.JedisSentinelPool.returnResource() 0.04444578 18520.263 ms 4
org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept() 0.035538 14808.45 ms 11430
有人可以帮助进一步调试问题吗?
最佳答案
来自 Jedis 源 (2.6.2) 的 getResource() 的 JedisSentinelPool 实现:
@Override
public Jedis getResource() {
while (true) {
Jedis jedis = super.getResource();
jedis.setDataSource(this);
// get a reference because it can change concurrently
final HostAndPort master = currentHostMaster;
final HostAndPort connection = new HostAndPort(jedis.getClient().getHost(), jedis.getClient()
.getPort());
if (master.equals(connection)) {
// connected to the correct master
return jedis;
} else {
returnBrokenResource(jedis);
}
}
}
注意while(true)
和returnBrokenResource(jedis)
,这意味着它试图从确实连接到正确的主人,如果不是好的,请重试。这是一个脏检查,也是一个阻塞调用。
super.getResource()
调用指的是 JedisPool 传统实现,它实际上基于 Apache Commons Pool (2.0)。从池中获取对象有很多作用,我认为它甚至可以修复失败的连接。由于您的池中有很多争用,可能在您的压力测试中,从池中获取资源可能需要很多时间,只是为了查看它是否连接到正确的主服务器,所以您最终调用它再次,增加争用,减慢获取资源等...
您应该检查池中的所有 jedis 实例,看看是否存在大量“不良”连接。
也许你应该放弃使用公共(public)池进行压力测试(只创建手动连接到正确节点的 Jedis 实例,并很好地关闭它们),或者设置多个实例以减轻寻找“脏”未经检查的 jedis 的成本资源。
还有一个包含 500 个 jedis 实例的池,您无法模拟 1000 个并发查询,您至少需要 1000 个。
关于redis - Jedis getResource() 正在花费大量时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30370027/