作者简介 微信存储QuorumKV是一个分布式的存储系统,覆盖但不限于微信后台核心业务:账号/用户信息/关系链/朋友圈,等等。 背景 微信内存云,目前有2千多台机器:单机内存64GB,存储盘为机械盘。作为核心存储之一,内存云承载了基础账号、消息计数等核心数据的存储,保障微信登录、消息收发等微信基础功能。内存云每天服务峰值请求十多亿/分钟,读写比约为3.3:1。基于QuourmKV的内存云具体架构如图1所示: 微信QuourmKV陪伴内存云走过了数次扩容,经历元旦、春晚等例行节日请求爆发增长的洗礼,也沉淀着不少故障处理经验(不限内存云)。本文主要描述新架构如何根本性地改善QuorumKV的容灾能力(即CAP中,保证C的前提下增强A),在不牺牲性能的前提下,消灭部分故障场景下的最终失败和人为介入。 QuorumKV本质上是一个NWR协议(N为3,W/R为2)的分布式存储,和其他NWR协议不同的地方在于:QuorumKV将NWR应用在版本上,当且仅当版本达成一致的情况下读写单机数据,从而保证强一致性。但是这里引入了2个问题:
不要小看了这2个问题,这是目前QuorumKV的绝大部分日常故障导致失败的根源,特别是对写量大的模块而言:
明确问题的根源是QuorumKV采用的NWR分布式协议,那么在保证强一致性的前提下可行的解决方案为Paxos/Raft分布式协议。表2列出了我们在协议选择上的一些考量:采用无租约的方式使得系统在保证强一致性的前提下达到最大的可用性;相对而言,租约的方式必然引入主备切换导致的不可用。 在对比调研过一些业界方案(etcd/megastore等)后,我们最终确定新架构协议方案是:无租约版Paxos分布式协议(如图3所示)。 面向挑战 接下来需要做的事情是,基于Paxos分布式协议在机械盘上搭建一套稳定高性能的分布式存储。 我们在谈及Paxos算法时,通常会提及Leslie Lamport大神的Paxos Made Simple;但基于Paxos算法的分布式协议不止与此,图4列出一个完整协议涉及的3个层次。 在构建PaxosLog(简称为PLog)时,我们针对Key-Value存储做了2项优化。 普通青年的通常做法是PLog和DB分离:增量更新记录在PLog中,并在Chosen之后顺序应用到DB中。这里的问题在于:
进步青年思考了下得出PLog as DB方案:我们希望Key和PLog保持1:1的对应关系,从而达到最大的并发性能,同时又不引入重复写。 作为PLog as DB的延伸,既然每个最新LogEntry包含全量的数据,那么物理上保留连续的PLog就没有必要了。 简单轻便的PLog结构,带来的优势还有:
强一致性读协议本身和Paxos算法没有太大关系,要点是多数派:广播的方式获取集群中多数机器(包含自身)的PLog状态,即最新的LogEntry位置和对应LogEntry处于Pending/Chosen状态。
强一致性写协议的大多数问题来自Paxos算法本身,这里我们主要做了3项优化(或者说解决3个问题)。
上述文字摘抄自MegaStore: FastWrites部分,描述:LogEntry i-1值的归属者可以在写LogEntry i时跳过Paxos算法的Prepare阶段直接进行Accept阶段。基于这段迷一样的文字,我们实现Paxos优化写算法:减少1次写盘、2次协议消息发送、2次协议消息接收;最终实现了写耗时和失败的降低,如图8所示。 Paxos算法只保证LogEntry i确定唯一值,但在多个Proposer的条件下(即A/B机均可发起强一致写),只有确定值的归属者可以返回成功。这里我们复用了etcd中requestid的方案。 其中member_id用于区分不同的Proposer,timestamp为毫秒级别的时间戳,req_cnt随写请求单调递增。基于requestid方案可以满足单机25w/s的写请求,足够了。 备注:requestid只需要在单个plog纬度上保证唯一即可。 Paxos算法本身不保证终止性,当出现写冲突时算法可能永远终结不了,即存在活锁问题;因此在实际工程中我们需要进行一些权衡:
我们目前使用了Prepare次数限制策略,从现网监控来看由写冲突导致的失败比例极小: 我们在新架构上采用DirectIO的方案实现了一套保证数据安全落盘的存储组件,DirectIO方案与其他两种写盘方案的对比如表格11所示。 然而仅仅保证数据安全落盘还不够,我们还要做到稳定:基于Bitcask写模型搭建的存储,需要定期的整理磁盘文件(我们称之为Merge),以重复利用磁盘空间,其中涉及操作有:Merge新文件写盘、旧文件删除,对外表现为:Merge写和正常写竞争、文件删除引起系统卡顿。为克服这2个问题,我们做了以下优化。
单次磁盘退化导致磁盘写操作耗时和失败率升高,通常情况下被Paxos协议本身的多数派所容忍;但是本机作为Proposer主动发起写时,写盘失败带来的就是单次写请求失败,前端会自动跳转对机重试,此时问题来了:磁盘退化者写失败之前将LogEntry置于Pending,对机重试的最终结果将Pending推成Chosen,但此时requestid表明Chosen值源于磁盘退化者,对机写被抢占,返回最终失败。 简单的说,磁盘退化期间写最终失败较高:通过将requestid前传到对机,让对机用已有的requestid重试可以将写最终失败降低1个数量级。 PLog对齐 当单机包含kw级别的PLog时,保持系统中所有PLog均处于对齐状态就变得很困难;但只有在所有PLog均处于对齐状态时,系统才能保持最大化的可用性。经历一番权衡后,我们的系统中挂载了以下逻辑(按时效性排序)来保证PLog对齐:
LeanerOnly模式 机器重启后发现文件丢失,数据被回退了怎么办?Paxos协议保证了绝大部分情况下强一致性和可用性,但不是全部。 某LogEntry承诺机器A的Paxos请求后,因为数据回退状态清空,重新上线后承诺机器B的Paxos请求,但是前后2次承诺相互矛盾,从而导致数据不一致。 上述描述的是拜占庭失败导致的数据不一致,这种失败违反了Paxos协议的假设前提;但现网运营中确实又需要处理这种情况,从而有了LeanerOnly模式的引入。
假设进入LeanerOnly模式2小时后,系统中旧LogEntry处于Pending状态的可能性可以忽略不计,那么该机可以解除LeanerOnly模式。 成果 除了上文描述的优化外,我们还定制了一套本地迁移的方案用于新旧架构的平滑切换,由于篇幅限制,在此就不一一展开了。最终我们实现上千台机器安全无故障的从QuorumKV架构切换到新架构,下面同步下新架构的性能数据和容灾能力。 压力测试条件:Value约为120B,读写3.3 : 1。 压力测试机型:64GB内存,机械盘。 具体数据如表13所示,可以看出在请求量相当的条件下,新架构在平均耗时和最终失败上都优与旧架构;并且新架构只需要6台机器。 备注:新架构部署上少了3台机器,带来单机约50%的内存和磁盘增长(容纳3份数据)。 实例1:网络故障期间可用性对比 小结 今日荐文 点击下方图片即可阅读 1024程序员节撩妹之余,看程序员如何优雅地撩生活
|
|
来自: openlabzeng > 《待分类》