您的位置:首页 > 其它

CODIS2.x原理 之 CODIS-PROXY实现原理

2016-07-25 15:43 295 查看
作者:邹祁峰

邮箱:Qifeng.zou.job@hotmail.com

博客:http://blog.csdn.net/qifengzou

日期:2016.08.02 18:48:39

转载请注明来自”祁峰”的CSDN博客

程序codis-proxy是连接client与codis-server之间的桥梁,且其主要处理流程充分体现了codis设计思想。要想深入理解codis原理,必须首先弄清楚codis-proxy各主要处理流程。

1 总体时序

Codis-proxy最主要的作用就是接收客户端提交的redis命令,并将命令分发到后端codis-server集群,再收集各命令的执行结果,最终将执行结果返回给客户端。其大体处理时序图如下:



功能简介:

1.客户端:Redis命令的发起方

2.SN-接收协程:用于接收来自客户端的请求

3.SN-发送协程:用于发送请求处理结果至客户端

4.BC-发送协程:用于将客户端的请求转发到后端某codis-server服务

5.BC-接收协程:用于接收来自某codis-server服务的应答

6.REDIS服务:某codis-server服务

2 处理流程

2.1 接收客户端连接

Codis-proxy完成初始化之后,将会启动一个协程专门用来帧听端口,并接收来自客户端的连接请求。



一旦收到客户端的连接请求,帧听协程将tcp连接对象放入连接队列,另一个协程将会从连接队列中取出该连接,并为之创建Session对象,再为该Session对象新建一个SN-接收协程和SN-发送协程。其中SN-接收协程负责接收来自客户端的操作请求; SN-发送协程负责将发送操作应答给客户端。

2.2 接收客户端请求

SN-接收协程用于接收来自客户端的请求。如果命令类型是QUIT、AUTH、SELECT、PING时, 则不用再转发到后端服务。如果是MGET、MSET、DEL这种支持同时操作多个键的命令,则需要将该命令按照操作键的个数N拆散成N个操作,再分发到不同的后端发送队列,某请求每分发一次,其等待计数加1。再将整个操作请求放入tasks队列,交给SN-发送协程等待应答完成。



注意事项:

1.Codis只支持通过select选择0分区,选择其他分区均会报错。

2.如果pipeline中的命令个数超过tasks队列的长度,可能会出现执行结果较长时间未返回的现象。

3.某请求每分发一次,其等待计数加1。

2.3 应答客户端请求

SN-发送协程用于将请求处理结果发送给客户端。SN-发送协程首先从tasks中获取到客户端提交的操作请求,之后直接阻塞等待应答,直到等待计数减为0时,则认为该请求的应答全部收到,再合并应答结果,并最终发送结果给客户端。



2.4 客户端请求分发

请求分发的目的是将操作请求发送到正确的codis-server服务。



注意事项:

1.通过crc32(KEY)%1024计算被操作的KEY属于哪个slot对象。

2.如果正要被操作的KEY属于被迁移的slot对象,则在放入bc.input队列前,codis-proxy会给对应的codis-server发送迁移某KEY的指令,并阻塞等待迁移的结果。如果迁移成功,则再将本次的操作请求放入对应的bc.input队列; 如果迁移失败,则返回错误给客户端。

2.5 转发请求至后端

BC-发送协程的主要职责是将bc.input队列中的数据发送到某codis-server服务。



2.6 接收后端的应答

BC-接收协程的主要职责接收来自某codis-server的应答数据。每完成一次应答的接收,BC-接收协程就会发送应答完成信号,以此告知SN-发送协程完成一次应答接收。



注意事项:

1.SN-发送协程每收到一次应答完成信号,其等待次数将会减1。如果等待次数减为0时,SN-发送协程则认为所有应答都已收到,可进行后续处理。

2.7 处理来自ZK事件

Codis使用zk存储各结点的状态,各结点通过zk的订阅功能感知各结点状态的变化并作出相应的处理,以此达到增强集群扩展性和集群容灾性的目的。



3 注意事项

3.1 配置相关

配置字段: session_max_timeout

作用说明:当客户端与PROXY之间的连接超过此时间未发送有效操作命令时,PROXY端将主动关闭此连接。

问题描述:将此值配置为非0时,可能出现的客户端进行REDIS操作时出现EOF的错误。

问题原因:由于很多客户端SDK使用的是同步等待Redis请求应答的机制,而非事件触发机制管理与PROXY端的连接。这就出现PROXY端主动关闭连接后,客户端并未感知关闭事件。待客户端从连接池获取的连接时,可能获取的连接对象实际已被PROXY端关闭,致使客户端进行REDIS操作时出现EOF的错误。

解决方案:将此值设置为0,即:PROXY端永远不超时。例如:codis后续版本reborn就已经取消了此值的配置。

配置字段: session_max_pipeline

作用说明:用于指定每次提交的PIPELINE中命令最大数。

问题描述:如果某此提交的PIPELINE中命令数超过此值,将可能导致PROXY发生阻塞,故客户端也因此而阻塞。

问题原因:由于SN-接收协程会将PIPELINE中的请求拆分成N个命令,并依次放入tasks队列中。而tasks队列的长度与session_max_pipeline一致。

解决方案: 1. 控制客户端提交的各PIPELINE中命令个数 2. 适当增大该值。

3.2 其他事项

问题描述:客户端与PROXY端通信时,必须全部接收来自PROXY端的数据。特别是PIPELINE操作时一定需要遵守此原则。否则可能出现PROXY进程“偶尔”异常退出,而zk报的异常却是:”session expired”。

解决方案:严格遵循“必须接收所有请求的应答”

问题描述:可通过控制域名的方式,使zk管理多个codis集群。但是codis-proxy、codis-server、codis-cconfig、codis-ha等无法复用。即:codis集群只可以复用zk集群。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: