问题
带着问题撸源码系列-zookeeper-客户端发读请求给follower,是转发给leader读还是读自己?
猜测
读自己就行了吧。不过可能要考虑当前有没有在写之类的。
读源码
参考写请求的分析
还把断点打在消费queue消息这儿
设置条件断点,如果是ping(request.type==11)请求咱就不断点了。
发送一个请求 ls /
request.type=12, getChildren,没有命中这里的命令。说明是别的地方处理的
找到这里其实卡住了,因为不知道server是从哪接收客户端收入的,思考了大概一个小时没想到办法找到入口,只好上网找资料看了。
这个问题的解答在:不同的RequestProcessor之间的顺序和协调是怎样的
答案是,使用了责任链模式,对于Follower而言,请求的处理顺序是:FollowerRequestProcessor -》 commitProcessor -》 FinalRequestProcesoor
当前是FollowerRequestProcessor
,没有相关处理逻辑,所以我们应该在下一个CommitProcessor
中继续寻找答案
先加入到本地的queuedRequest
中,然后根据当前请求是不是需要提交needCommit
,如果是,加到queuedWriteRequest
然后找到消费QueuedRequest的地方:
遇到注释先解读注释:
接下来的这个循环,每次循环我们最多处理
queuedRequest
中requestsToProcess
个请求,我们必须限制数量,因为可能无休止地从queuedRequests
中取出请求,这样会导致那些不是本地提交的请求被“饿死"
因为请求在发给leader前是排好队的,如果
commitIsWaiting=true
,这个commit属于queuedRequest
的第一个更新操作,或者是从客户端到另一个server的请求。所以接下来这两行的代码顺序很重要!
这个代码挺多细节的其实。
请求首先被分为 需要提交的请求 和 不需要提交的请求
Map<Long, Deque<Request>> pendingRequests
是一个map,保存每个session提交的请求,key是sessionid,value是这个session的请求队列
我们这个问题的请求不是写请求,不需要提交,所以一般情况下走的else逻辑。但是!如果是当前这个读请求在一个写请求后面!他就会走if逻辑!if逻辑比较复杂,本次先不讨论,留待:一个客户端,先发写请求,后发读请求,能一定读到写的内容吗?为什么?
下面我们只从else逻辑分析。
于是又会让下一个RequestProcessor来处理:FinalRequestProcessor
我们在这里打好断点,然后再进入FinalRequestProcessor
继续看
终于找到了相应的代码处理逻辑,从本地读出数据。在这里也打个断点。
断点调试
上面所述的断点打好了之后,我们使用客户端发请求 ls /
首先来到了 FollowerRequestProcessor
他会发给下一个Processor
来到了CommitProcessor
,他又发给下一个Processor
最终来到了我们的FinalRequestProcessor
,读到了DataNode
完美验证!
回答问题
一个读请求发到Follower,他会按照责任链,经过FollowerRequestProcessor
、 CommitProcessor
、 FinalRequestProcessor
最终来到本地获取数据,然后返回。
所以到底是否需要经过leader呢?
本文在读源码的过程中,发现如果读请求前面没有写请求,可以肯定只读本地就可以了。但是如果读请求前面有写请求,具体的情况我们在分析。