• 2020-05-10

    我所理解的分布式系统

    Views: 8603 | 1 Comment

    分布式系统要义

    多副本(Replica)

    • 高可靠(数据)
    • 高可用(系统)
    • 高性能(系统)
      • 读性能
      • 写性能(降低)

    分区(Sharding)

    • 突破单机物理限制
      • 多副本: 容量 = MIN(replica)
      • 分区: 容量 = SUM(replica)
    • 提高读和写性能
    • 提高存储容量

    弹性

    • 增加减少副本数量
    • 合并分裂分区

    协作

    • 多副本协作
    • 多分区协作
    • 无协作不分布式

    常见的伪分布式

    • 无分区(争议)
      • 只有多副本算不算分布式?
    • 无协作
      • 全世界独立运行的 MySQL 组成了一个分布式关系数据库集群吗?
      • 有人说 World Wide Web 是一个分布式系统
    • 客户端自己分布式就是伪分布式
      • DBA 部署了2个独立的 Redis, 宣称是分布式 Redis 集群, 但要求业务部门自己把数据写到不同的实例…
      • DBA 部署了4个独立的 Redis, 除了要求业务部门自己拆分数据, 还要求业务部门自己写两个副本…
    • 真分布式和伪分布式之间有模糊地带
    Posted by ideawu at 2020-05-10 14:34:14
  • 2020-05-10

    关于从客户端的角度去理解一致性可能产生的误区

    Views: 7369 | No Comments

    很多人从客户端并发的角度去讨论一致性, 这其实是一个错误的方向. 并不是说客户端与一致性无关, 相反, 客户端正是要求一致性的需求者.

    一致性协议不负责客户端的并发协调. 例如抢红包, 防超卖, 秒杀这类业务需求, 不是 Paxos/Raft 能解决的.

    首先, 我们需要定义先后, 何为"先", 何为"后"?

          q1          r1          q2          r2
    ------+-----------+-----------+-----------+-----
    

    如图, q 是指客户端发起请求的时间点, r 是指客户端收到响应的时间点, 两个请求用 1, 2 来表示. 很显然, 两个请求的先后顺序没有争论.

    如果是并发呢? 先后就变得让人迷惑了.

          q1          r1 
    ------+-----------+-----------
             q2          r2
    ---------+-----------+-----------
    

    你说, 哪个请求先哪个请求后? 一般认为, 请求 1 先于请求 2. 这个一般也不会有争论.

    接着, 是最让人迷惑的地方了.

          q1          r1 
    ------+-----------+-----------
             q2    r2
    ---------+-----+-----------
    

    你说, 请求 1 在先还是请求 2 在先? 争论不休吧? 所以, 讨论一个一致性的系统, 必须要求观察者的行为是瞬时的, 不能是并发的.

    观察者(客户端)当然可以并发, 但是, 如果客户端自己都不能分清先后的话, 去预期系统(服务端)的执行结果是没有意义的.

    一个强一致性的系统(服务端)当然可以处理并发请求, 而且请求的处理也不是瞬时, 这没关系. 我们讨论的是服务器在并发处理这些请求时的一致性可预期的行为, 而不是从客户端的角度看客户端并发时的系统的行为, 这里一定要注意.

    事实上, 一个一致性的系统, 只关注行为完成时点的先后的关系, 并不关注行为的发起是什么先后顺序. 所以, 请求到达服务器的时间先后关系没有任何意义.

    一致性, 讨论的是完成时, 不关心发起时.

    Posted by ideawu at 14:30:01
  • 2020-05-01

    一种区分读写操作的对工程实践友好的分布式一致性协议

    Views: 9042 | No Comments

    一种区分读写操作的对工程实践友好的分布式一致性协议

    摘要

    流行的共识算法如 Paxos[1] 和 Raft[2] 被广泛地应用于分布式系统中, 用于实现一致性. 但是, 这些算法本质上并不区别读和写操作, 因而给工程实践带来了极大的困扰. 这种困扰导致在具体实现时, 开发者往往基于性能优化方面的考虑, 对这些算法做没有经过理论验证的更改.

    我想在区分读写操作的前提下, 设计一种对工程实践友好的分布式一致性协议, 能适应读多写少或者读少写多等不同场景的需求. 这个分布式协议基于 Quorum 机制, 采用 2PC 策略和复制状态机模型, 适用于有强一致性要求的分布式数据库系统和其它分布式系统.

    Continue reading »

    Posted by ideawu at 2020-05-01 13:12:06 Tags: ,
  • 2020-04-28

    分布式一致性算法的全部内涵

    Views: 9154 | 1 Comment

    第一步, 查询集群的状态;

    第二步, 根据状态判断如果没有不一致就返回, 有的话要么主动修复, 要么等待别人修复;

    这是一致性的基础, 也是一致性的全部. 注意, 某些类型的不一致可以不修复. 怎么写? 当然是尝试全写, 过半数正面确认就"成功"返回给客户端, 过半数在"准备阶段"拒绝就是"失败", 否则就是"未知".

    Paxos 是怎么做的? 甭管有没有不一致, 先修复再说.

    [完]

    Posted by ideawu at 2020-04-28 11:32:31
  • 2020-04-28

    Paxos什么都包含, 也什么都不是

    Views: 9571 | No Comments

    初学 Paxos, 你会觉得 Paxos 非常高深隐晦, 接着会觉得没什么难的, 最后估计会觉得 Paxos 什么都不是, 就跟空气一样既是基础, 又不算什么.

    你说写多数派或者全写, 这是谁都知道的道理, 不是 Paxos 独创.

    你说读多数派, 显然这是错误的, 必须全读. 读多数派得出的结论, 和读全部节点得出的结论, 很可能是不同的, 甚至两次读不同的多数派也可能得出不同的结论, 所以不是一致性的.

    所以, 要么全读, 要么"读修复 read-repair", 也就是在读的时候修复数据, 这就是 Paxos 所谓的 phase 2 - 产生新的共识. 读修复就是 Paxos 的基础.

    这些读和写策略, 都不是 Paxos 独创, 可以算 Paxos 头上, 也可以不算. 你可以说我在用 Paxos, 也可以说我用的不是 Paxos. Paxos 非常强大, 又什么都不是.

    你优化来优化去, 读的时候不修复(非一致性 quorum read), 或者先等一等别人修复(read index), 都丢失了 Paxos 的基础, 那还算 Paxos 吗?

    Posted by ideawu at 11:07:22 Tags:
  • 2020-04-27

    Raft Read Index 的实现

    Views: 9160 | No Comments

    首先, 获取"集群"的 ReadIndex. 注意, 不是某个节点上面的某个状态, 而集群的多个节点共同确定的一个变量. 这个变量如何获取, 下面说明.

    func GetClusterReadIndex(){
        foreach(peers as peer){
            i = peer.rpc_GetLastIndex();
            ret = max(ret, i);
            if(recv_majority){
                break;
            }
        }
        return ret;
    }
    

    获取至少半数以上成员的 LastIndex, 也就是每个节点持久化的最新一条日志的 index. 一条日志只要在一个节点上被持久化, 那么这条日志要么被集群 commit, 要么被覆盖之后再 commit, 没有其它的选项.

    由此可见, ReadIndex 不一定已经被 commit, 但一定会被 commit, 最终也将会 apply. 所以, 拿到集群的 ReadIndex 之后, 我们只需要等, 等它被任意一个节点 apply 即可.

    ReadIndex = cluster.GetReadIndex();
    while(1){
        foreach(peers as peer){
            if(ReadIndex <= peer.LastApplied()){
                return peer.GetValue();
            }
        }
    }
    

    不断地重复轮询全部节点, 如果谁 apply 了, 就以谁的值为准. 还有一种方案, 那就是等本地的状态机 apply, 这样避免网络传输.

    ReadIndex = cluster.GetReadIndex();
    while(1){
        if(ReadIndex <= self.LastApplied()){
            return self.GetValue();
        }
    }
    

    还有一种优化方案, 是客户端判断. 客户端请求多数节点, 获取 max pending 和 max committed, 如果 committed 大于等于 pending, 那么取对应的 value. 如果 pending 大于 committed, 说明集群中有"脏写"(未决的数据), 客户端要做的就是等待. 如果不等待, 那就做 Paxos phase 2 所讲的"读修复".

    没什么玄幻的, 道理非常简单: 第一步, 查询集群的状态; 第二步, 根据状态判断没有脏数据就返回, 有的话要么主动修复, 要么等待; 这是一致性的基础, 也是一致性的全部.

    Posted by ideawu at 2020-04-27 19:22:40 Tags:
|<<<123>>>| 1/3 Pages, 18 Results.