6.824-lecture8

6.824 讲座8:Zookeeper案例研究

阅读:“ ZooKeeper:互联网级系统的无等待协调”,Patrick
亨特,马哈德夫·科纳尔,弗拉维奥·P·琼奎拉,本杰明·里德。2010年会议论文集
USENIX年度技术会议。

我们为什么要阅读这篇论文?
广泛使用的复制状态机服务
受Chubby(Google的全局锁定服务)启发
最初在Yahoo !,现在也在外部(Mesos,HBase等)
开源的
作为Apache项目(http://zookeeper.apache.org/)
给Paxos / ZAB / Raft库的构建复制服务的案例研究
实验3中也出现了类似的问题
API支持广泛的用例
需要容错“主”的应用程序不需要自己滚动
Zookeeper非常通用,因此他们应该能够使用Zookeeper
高性能
与实验3的复制键/值服务不同

动机:数据中心集群中的许多应用程序需要协调
示例:GFS
主服务器具有每个块的块服务器列表
主服务器决定哪个块服务器是重要的
等等
其他示例:YMB,Crawler等
YMB需要掌握分片主题
爬网程序需要掌握命令页面获取的主机
(例如,有点像mapreduce中的master)
应用程序也需要互相查找
MapReduce需要了解GFS主站的IP:PORT
负载平衡器需要知道Web服务器在哪里
通常用于此目的的协调服务

动机:性能-实验3
raft为主
考虑3节点raft
在返回客户之前,Raft会执行
领导者坚持记录日志
同时,领导者向关注者发送消息
每个关注者的持久日志条目
每个关注者的回应
-> 2次磁盘写入和一次往返
如果磁盘:2 * 10msec = 50 msg / sec
如果SSD:2 * 2msec + 1msec = 200 msg / sec
Zookeeper执行21,000 msg / sec
异步调用
允许流水线

替代方案:为每个应用程序开发容错主机
通过DNS宣布位置
好的,如果编写母版并不复杂
但是,主人通常需要:
容错
每个应用程序如何使用Raft?
高性能
每个应用程序都如何使“读取”操作快速进行?
DNS传播缓慢
故障转移将花费很长时间!
某些应用程序解决单点故障
例如,GFS和MapReduce
不太理想

Zookeeper:通用协调服务
设计挑战:
什么API?
如何使主站容错?
如何获得良好的表现?
挑战互动
良好的性能可能会影响API
例如,异步接口允许流水线化

Zookeeper API概述
[图:ZooKeeper,客户端会话,ZAB层]
复制状态机
多个服务器实施该服务
操作以全局顺序执行
如果一致性不重要,则有一些例外
复制的对象是:znodes
znode的层次结构
以路径名命名
znodes包含应用程序的* metadata *
配置信息
参与应用程序的机器
哪台机器是主要的
时间戳记
版本号
znode的类型:
定期
外围的
顺序:名称+ seqno
如果n是新的znode,p是父znode,则序列
n的值永远不小于任何其他名称中的值
在p下创建的顺序znode。

会议
客户登录zk
会话允许客户端故障转移到另一个Zookeeper服务
客户知道最后完成的操作的术语和索引(zxid)
根据每个请求发送
服务仅在赶上客户所见的情况下才能执行操作
会话可能会超时
客户必须持续刷新会话
向服务器发送心跳(例如租约)
如果没有听到客户的声音,ZooKeeper认为该客户“死了”
客户端可能会继续做事(例如,网络分区)
但无法在该会话中执行其他ZooKeeper操作
Raft + Lab 3 KV商店中没有与此类似的产品

znodes上的操作
创建(路径,数据,标志)
删除(路径,版本)
如果znode.version =版本,则删除
存在(路径,观看)
getData(路径,观看)
setData(路径,数据,版本)
如果znode.version =版本,则更新
getChildren(路径,观看)
同步()
以上操作是“异步的”
每个客户端的所有操作均按FIFO顺序排序
sync等待,直到所有“前面的操作”都“传播”为止

检查:我们可以使用实验3的KV服务来做到这一点吗?
有缺陷的计划:启动时GFS主站会执行Put(“ gfs-master”,my-ip:port)
其他应用程序+ GFS节点执行Get(“ gfs-master”)
问题:如果两个主要候选人的Put()比赛怎么办?
稍后Put()获胜
每个假定的母带需要读取密钥,以查看它是否实际上是母带
我们何时可以确保没有延迟的Put()打击我们?
每个其他客户都必须看过我们的Put()-难以保证
问题:当主服务器发生故障时,谁决定删除/更新KV商店条目?
需要某种超时
因此主服务器必须存储(my-ip:port,timestamp)的元组
并连续Put()刷新时间戳
其他人轮询条目以查看时间戳是否停止更改
大量的投票+不清楚的种族行为-复杂
ZooKeeper API有一个更好的故事:观看,会话,原子znode创建
+只有一个创造可以成功-没有Put()竞赛
+会话使超时变得容易-无需存储和刷新明确的时间戳
+手表是延迟通知-避免提交大量轮询读取

订购保证
所有写操作都是完全有序的
如果写操作是由ZooKeeper执行的,则以后其他客户端的写操作可以看到它
例如,两个客户端创建一个znode,ZooKeeper以某种总顺序执行它们
每个客户端的所有操作均按FIFO顺序排序
含义:
读取观察到来自同一客户端的较早写入的结果
读操作会观察到写操作的某些前缀,也许不包括最新的写操作
->读取可以返回过时的数据
如果读取遵循写入的某些前缀,则稍后读取也遵循该前缀

示例“就绪” znode:
发生故障
主服务器将写入流发送到Zookeeper
W1 … Wn C(就绪)
最终写更新准备就绪znode
->所有先前的写入都是可见的
最终写入会导致手表在备份时熄灭
备份问题R(就绪)R1 … Rn
但是,它将观察所有写入,因为Zookeeper将延迟读取直到
节点已查看观察到的所有txn
可以说在R1期间发生了故障…Rn,例如在将Rj返回给客户端之后
主要删除准备就绪的文件->手表熄灭
监视警报已发送给客户端
客户知道必须发出新的R(ready)R1 … Rn
好的特性:高性能
管道写入和读取
可以从任何 Zookeeper节点读取

用法示例1:缓慢锁定
获取锁:
重试:
r = create(“ app / lock”,“”,empheral)
如果r:
返回
其他:
getData(“ app / lock”,watch = True)

​ watch_event:
​ 转到重试

释放锁:(自愿或会话超时)
删除(“应用/锁定”)

用法示例2:“票证”锁
获取锁:
n = create(“ app / lock / request-”,“”,empheral | sequential)
重试:
请求= getChildren(l,false)
如果n是请求中最低的znode:
返回
p =“ request-%d”%n-1
如果存在(p,watch = True)
转到重试

​ watch_event:
​ 转到重试

问:可以在锁定轮到客户之前轮到观看甚至射击
答:是的
锁/请求10 <-当前锁持有人
锁定/请求11 <-下一个
锁定/请求12 <-我的请求

​ 如果与request-11关联的客户端在获得锁之前死亡,则
​ 手表甚至会开火,但现在轮到我了。

使用锁
并非直截了当:失败可能会导致您的锁被吊销
客户端1获得锁
开始做它的东西
网络分区
Zookeeper宣布客户端1死亡(但不是)
客户端2获得了锁,但是客户端1仍然认为它拥有它
可以通过正确设置超时来避免
在临时节点消失之前,需要断开客户端1会话的连接
需要将会话心跳复制到大多数
注意:论文没有讨论这个
在某些情况下,锁是一种性能优化
例如,客户端1锁定了对某些网址的爬网
客户现在会做2次,但这很好
在其他情况下,锁是一个基本要素
例如,应用程序使用它来构建事务
交易全有或全无
我们将在素馨花纸中看到一个例子

Zookeeper简化了构建应用程序,但不是端到端解决方案
大量艰苦的问题留待申请处理
考虑在GFS中使用Zookeeper
即,用Zookeeper替换主人
应用程序/ GFS仍然需要GFS的所有其他部分
块的主要/备份计划
块上的版本号
处理主要故障转移的协议
等等
使用Zookeeper,至少主服务器具有容错能力
并且,不会遇到裂脑问题
即使它已复制服务器

实施概述
与实验3相似(请参阅上一讲)
两层:
ZooKeeper服务(K / V服务)
ZAB层(筏层)
Start()在底层插入操作
稍后,操作会弹出每个副本的底层
这些操作按照弹出的顺序提交
在练习3中的应用频道上
ZAB中的abdeliver()调用

挑战:重复客户要求
情境
主服务器收到客户端请求,失败
客户端将客户端请求重新发送到新的主服务器
实验3:
用于检测重复项的表
局限性:每位客户一项出色的操作
问题问题:无法管道客户端请求
动物园管理员:
一些操作是幂等时期
一些操作很容易成为幂等
测试版本然后进行操作
例如,在setDataTXN中包含时间戳和版本

挑战:读取操作
许多操作都是读取操作
他们不修改复制状态
他们是否必须通过ZAB /筏?
任何副本都可以执行读取操作吗?
如果读取操作通过Raft,则性能会降低

问题:如果只有主控执行,读取可能会返回陈旧数据
主数据库可能不知道它不再是主数据库
网络分区导致另一个节点成为主节点
该分区可能已处理了写操作
如果旧的主服务器具有读取操作,则不会看到那些写入操作
=>读取将返回陈旧数据

Zookeeper解决方案:不承诺非过期数据(默认情况下)
允许读取以返回陈旧数据
读取可以由任何副本执行
读取吞吐量随着服务器数量的增加而增加
读取返回它看到的最后一个zxid
这样,新的主服务器就可以在读取服务之前赶上zxid
避免从过去读
仅sync-read()保证数据不陈旧

同步优化:避免ZAB层进行同步读取
必须确保读取遵守最后提交的txn
领导者将同步放在它和副本之间的队列中
如果操作在队列中提前提交,则领导者必须是领导者
否则,发出空交易
本着同样的精神在筏纸上阅读优化
参见筏纸的第8部分

表现(见表1)
读便宜
问:随着服务器的增加,为什么会有更多读取?
写贵
问:为什么随着服务器数量的增加而变慢?
快速故障恢复(图8)
即使发生故障也能保持体面

参考文献:
ZAB:http://dl.acm.org/citation.cfm?id=2056409
https://zookeeper.apache.org/
https://cs.brown.edu/~mph/Herlihy91/p124-herlihy.pdf(免费等待,通用
对象等)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值