因为redis是单线程,请求都是串行,所以协议的设计很简单(陋),client也假定数据库是单线程所以也比较简单,比如有了pipeline后完全没有搞异步接口的必要,其他语言不知道,Java的jedis应该是没有的,全是同步阻塞的。
但一旦扩展成多线程,比如codis,一个client在一个业务逻辑内一次读多个key,在基于当前的redis client的接口的情况下,因为协议串行导致必须按顺序返回给客户端,又因为proxy的下层是多个slot、多个redis,不能用pipeline,所以按照目前的实现,client直接mget多个key,或者pipeline连某个proxy,只能串行分发到下面处理,网络ping-pong的次数显著增加,很可能会导致反而比单redis还慢。当然,redis官方的cluster,直接把pipeline屏蔽掉了,因为要直接在client算slot请求对应节点。
所以只要client没有自行搞出异步的接口,无论codis还是官方cluster在同时请求多个key的时候都是个悲剧。对codis来说,目前的解决方案只能是自行搞异步接口,请求N个key由client分在M个connection去请求,M越多甚至可能M=N时最快,但client就需要开很多个connection了。
如果改codis的proxy,也是可以搞的。最简单的实现方式就是每个connection的每个请求无视顺序都发给redis,同时搞个list存每个请求的WaitGroup,时刻阻塞等待链表头的wg,保证回复response时按照request的顺序,只要下一个请求没返回也没超时就一直等着。这里改成纯异步的之后,用mget和pipeline的性能会好不少甚至可能因为多个redis而远超单机性能。不过一些一致性的问题可能也需要考虑,比如pipeline纯异步后一旦中间某个请求挂了,后面是无法不执行的,需要用户承受这一点。
发表回复