本文环境:
jedis 2.1.0
redis 2.8.13
Redis无响应
我们的各个子系统均使用Jedis作为Redis的Java Client读写数据。
Jedis底层使用Apache的Common Pool,每个Jedis对象在底层都视为一个Object。
当释放连接失败后,我们的做法只是输出错误日志,这会导致该连接无法回收再利用,最终服务器的连接池会被拖垮,现象就是我们遇到的无响应、重启就好。
此前我们分析过,现在得出的结论是:这不是服务器操作系统连接数的问题,也不是数据频繁读写的问题,而是释放资源时遇到异常时,我们没有将该连接直接断掉、丢弃。
如下是AEnv代码的相关变更情况,仅做参考:
高效读写调研
常用的Jedis读写方式包括:set/get、hset/hget和mset/mget,分别用作基本读写、hash读写和批量读写。
对此,我进行了一次性能测试(见下图)。
从结果上看,批量读写的优势是非常明显的,如果子系统有类似业务逻辑,希望考虑这种形式。对于hash读写,在数据量聚集在某个特殊范围内时,其效率是比基本读写要高的。
另外,Jedis的单点是线程不安全的,通过Apache的Common Pool获取的Jedis实例是线程安全的,因此不建议子系统使用new一个实例的方式。
Master-Slave调研
Redis的主从环境,我已经使用Docker搭建好,参见[[Docker系列·10] 搭建Redis服务器](http://www.atatech.org/articles/21551)
本次调研的目的是:观察主从复制、读写分离是否可以提高读写效率(虽然主从模式会提供高可用性,但目前子系统更关注的是速度)。
测试采用两个Jedis线程池一主一辅,主写、辅读。
单线程的测试结果如读写性能并不高。
100个线程的测试情况如下。从图中可以看出,数据量增到10000条的时候是个拐点,读写分离在此处开始呈现优势。不管是否读写分离,单次SET永远不是高效的写入方式。
HSET在5万条数据的单机读写时出现过读超时,怀疑在做rehash(表中红色条目)。
附:
Docker Redis示意图:
![2014_08_27_redis_master_slave]
(http://img1.tbcdn.cn/L1/461/1/519d6d0663bda5dbd512829b3da221f1e0872743)