怎样理解 ZooKeeper 一致性保证中的 Single System Image?

官方描述:
Single System Image:A client will see the same view of the service regardless of the server that it connects to.翻译成大白话就是:一个client无论其链接到哪个节点(即使中间切换了链接的节点),其读取的数据永远都不会比之前读到的旧,也就是一旦一个client看到版本为3的数据,那么就不会再读到比版本3更低的数据,只会读到和版本3或者比版本3更高版本的数据。
具体实现:
zookeeper的每个client和节点建立链接了之后,实际上就是创建了一个session,那么每次read都会从此节点read数据,那么自然读到的数据不会出现版本反转,这里关键是如何应对节点宕机或者失联,一旦client发现某节点可能下线,那么它会尝试去连接其他节点,但是它会携带上它已经最新的事务id:zxid,如果对端的最新zxid比client已知的新,那么建立连接,否则拒绝,这样保证了client不会链接到比自己状态旧的节点上。实际上每次server返回client请求的时候,都会将自己最新的zkid携带返回给client。(具体实现可以参照源码)

【怎样理解 ZooKeeper 一致性保证中的 Single System Image?】 总结思考:
实际上对于zookeeper来说:
update:实现的是线性一致性更新,zab协议实现了原子广播保证了这一点,类似raft,同参考文献的说法,但是官方说法描述这里的时候是确实用的Sequential Consistencyread: 实现的是顺序一致性(Sequential Consistency),这一点也就是上面的Single System Image,当然zookeeper实现了线性一致性read,其通过增加一个sync操作来保证从follower read的时候会去leader上read最新的数据然后返回给follower,在返回给client。这里其实就是相当于将read转发给了leader处理,和etcd的follower read处理方法一致zookeeper到底实现是什么一致性?其实就我们目前来看,update线性一致性,read顺序一致性,但是组合之后并没法实现顺序一致性,考虑一种情况client update操作成功返回,client能read到此次update的结果吗?好像zookeeper并没有保证,因为如果client当前链接在follower上,那么update实际上转发给leader完成的,但是client再次read的时候,确不一定能保证read到自己的这次update的结果,那么这样看又是不满足顺序一致的了。所以read满足了顺序一致性,但是整体来看一个client,其并不满足顺序一致性。(这个结论也是自己非常疑惑的,因为非深度研究过zookeeper,所以由错误还请不吝赐教,这也是今天回答这个问题的另一个原因,希望得到指点,非常感谢)(当然这里想要实现顺序一致性并不难,每次read带上最新的zxid下去read就好,但是简单看了zookeeper代码,其好像并没有这么做)既然zookeeper对于单个client端来说没有实现顺序一致性,这样会有问题吗?好像也没有,因为对于实现lock等同步场景,这个好像并没有什么影响
参考文献:
. http://zookeeper-user.578899.n2.nabble.com/Consistency-in-zookeeper-td7578531.html
. zookeeper. https://github.com/apache/zookeeper
. Consistency Guarantees. https://zookeeper.apache.org/doc/r3.3.3/zookeeperProgrammers.html
. Consistency in zookeeper. http://zookeeper-user.578899.n2.nabble.com/Consistency-in-zookeeper-td7578531.html

■网友
Single System Image的含义 @暗淡了乌云 已经说的比较清楚了。
我来补充几点:
zookeeper只实现了linearizable writes,对于read来说,可以说只能保证一种timeline的consistency,也就是看到改变的版本号zxid是单调递增的。对于一个client的write操作而言,对应的sever收到请求后转发给leader,由zab确定commit并且广播到这个server之后,才回复给client,所以就保证了之后的read一定能read到这个write。引自zookeeper paper 4.2 Atomic Broadcast The server that receives the client request responds to the client when it delivers the corresponding state change.3. 如果存在hidden channel,就是说clients除了zookeeper之外,互相之间有其他连接,那么就可能存在违反因果性的事情。比如,client A看到了zookeeper的某个改变告诉了client B,但是client B去read却没有看到,这是因为read是由不同server本地处理的。这种时候就需要linearizable read了,zookeeper里可以使用sync之后再read,sync的作用是把之前的commit数据给同步到当前连接的server再返回。我原本觉得实现就是一个no-op的写。


推荐阅读