• 2021-05-30

    数据库内核的并发控制

    Views: 851 | No Comments

    大部分程序员最先接触并发编程, 一般是从编程语言里的多线程和锁开始. 但是, 并发控制是一种广义的技术思想, 千万不可将眼光局限于编程语言所提供的锁. 将编程语言里的并发控制技术推广, 就能得到任何层面的并发控制技术.

    以操作一个文件为例, 如果不做并发控制, 就会遇到数据完整性问题. 例如, 我们写入的一项数据, 对应着现实对象, 如果不做并发控制, 那么可能读到的是两项数据的混合体, 或者只读到一项数据的部分.

    互斥锁

    互斥锁是最简单的并发控制技术, 无论读还是写, 通通进行排队, 一次只处理一个请求(读或者写). 这种技术实现起来简单, 不容易出 bug, 如果为了快速实现, 可以采用此技术. 但是, 因为涉及到排队串行化, 所以在很多实际场景中, 这种技术会非常低效.

    以操作一个文件为例, 给文件加一把互斥锁(任何层面的锁, 未必和编程语言或者操作系统所提供的锁对应). 当想要往文件中写入数据时, 先获取锁, 然后写入. 同样, 想要从文件中读取数据时, 先获取锁, 然后读.
    Continue reading »

    Posted by ideawu at 2021-05-30 00:36:26
  • 2021-05-28

    分布式系统升级所遇到的问题

    Views: 955 | No Comments

    常规的单机软件升级, 一般认为是一个原子操作, 也就是说, 软件会在"瞬间"完成升级, 即使不能在"瞬间"完成升级, 也要中断服务, 等升级完成后再提供服务.

    对于需要中断服务的情况, 在分布式系统中是不能接受的. 同时, 分布式系统的升级永远不可能在"瞬间"完成. 因此, 分布式系统升级会面临一个长时间的中间态, 新旧版本的软件同时运行, 这就涉及到兼容性问题.

    假如, 新版本的软件的数据格式改变了, 那么, 新版本写入的数据就无法被旧版本识别, 旧版本就会报错. 因为, 新版本的软件很容易做到向后兼容(新的兼容旧的), 但是, 向前兼容(旧的兼容新的)依赖预见性, 不可能预见全部未来.

    如果分布式系统无法做到向前兼容, 这时候, 应该怎么办呢? 难道要停服升级?

    一个常用的解决方案是在旧版本和新版本之间插入一个中间版本. 这个中间版本的主要特点是不写入新格式的数据, 但能识别新格式的数据.

    我们先逐步把旧版本替换为中间版本, 在这个过程中, 因为没有新格式的数据产生, 所以没有兼容问题. 等旧版本全部替换完毕后, 逐步升级为新版本, 在这个过程中, 虽然新旧格式的数据都有, 但新版本都能识别, 也没有兼容问题

    Posted by ideawu at 2021-05-28 21:09:45
  • 2021-05-21

    Raft 为什么不能直接 commit 前任的日志?

    Views: 1259 | No Comments

    有一些文章, 包括 Raft 协议的论文, 已经从反例的角度解释了为什么不允许 Leader 直接 commit 前任的日志, 而是必须追加本任期的一条日志, 以达到隐式地 commit 前任的日志. 我想从 Raft 的几项原则的角度, 在逻辑上解释这个问题.

    Raft 策略1: 节点的日志一旦 commit 便不可撤销

    某个节点的一条日志, 一旦 commit 它, 那么就会对状态机造成不可逆的改变. 也许某些状态机有回滚功能, 但在 Raft 的架构中, 假设状态机不可回滚. 因此, 日志一旦 commit, 便不可撤销.

    注意, 这里用的是"策略"一词, 表明这是人为规定的规则, 不是客观存在的定理.
    Continue reading »

    Posted by ideawu at 2021-05-21 23:07:29 Tags:
  • 2021-05-08

    Binlog, Redolog 在分布式数据库系统中的应用

    Views: 1240 | No Comments

    系统结构

           request
    client -------> server
    

    在一个系统中, 有 client 和 server 两个角色, client 向 server 发起请求(request), 这里的请求指写数据请求, 例如某条类似 "update table set a=1" 这样的 SQL 语句. 我们把 server 进行拆分, 得到下面这个更细化一些的系统结构:

           request         write
    client -------> server -----> database
    

    Server 的内部其实有一个数据库存储引擎, 例如可以使用 sqlite, 或者 LevelDB. 这个结构还可以继续拆分, 在分布式数据库, 需要有多副本, 所以会引入 binlog 技术(日志复制状态机), 把用户的请求保存下来(持久化), 然后复制到其它机器上. 因此, 系统的架构就变成:
    Continue reading »

    Posted by ideawu at 2021-05-08 22:42:19
  • 2021-05-08

    Raft 协议和区块链

    Views: 1150 | No Comments

    我还没有发现有人把 Raft 协议和区块链关联到一起讨论, 但是经过仔细分析, 穿透问题的本质之后, Raft 和区块链技术具有非常多的共同点. 可以整理出一个表格:

    Raft 区块链 通用
    日志 区块 Entry, Node, 节点, 记录
    日志序列 区块链 Chain, 链表(前向指针)
    选举: Leader 可产生日志 算力: 任意节点付出成本产生区块 Leader
    Term 分叉 Branch
    基于 Quorum 立即 Commit 立即相信最长的链条 Consensus, 共识
    一经 Commit, 不可撤销 随时转而相信新的最长的链条 Commit, Rollback

    Raft 和区块链的不同概念, 其实往往对应到通用技术里面的一个共同的概念.
    Continue reading »

    Posted by ideawu at 22:19:31 Tags:
  • 2021-05-02

    数据库事务ACID和锁

    Views: 1214 | No Comments

    数据库事务功能非常重要, 任何应用只要操作的多个对象之间有依赖(约束)关系, 都会不约而同地想到使用事务, 例如银行转账功能, 社交 App 中的粉丝关注功能, 购物网站下订单功能. 任何一个数据库系统, 如果不提供事务功能, 就不能减少用户(应用开发者)的某些麻烦, 因为用户不得不自己在应用层去实现类似事务的代码逻辑.

    从用户的角度看, 如果数据库不提供事务, 他就要多写代码, 这让他很不爽. 所以, 即使是 KV 数据库, 也应该提供事务功能. 但是, 不仅事务功能的实现是有成本的, 使用也有成本. 比如, 很多用户不能准确地理解事务的特点和作用.

    抽丝剥茧, 我们来分析一下数据库事务的本质是什么? 用户对事务功能的需求的本质是什么?

    先从 ACID(Atomicity, Consistency, Isolation, Durability)说起.

    • Durability(持久化), 这不是事务的特性, 而是数据库系统的本能特性, 没有持久化的数据库是"伪数据库", 是缓存系统. 所以, 没有啥可讨论的.
    • Consistency(一致性), 一致性用于解决多副本不相同, 和解决数据依赖(约束)级联更新问题. 多副本和数据依赖, 本质上都是多处数据更新时间差的问题, 因为多处数据绝对不可能立即同时更新. 一致性本质上是原子性(Atomicity)问题.
    • Isolation(隔离性), 隔离性本质上也是受多数数据不能"立即同时"更新所限而产生的. 因为多数数据不能立即同时更新, 所以看到更新的先后顺序会对业务的因果关系(数据依赖)产生影响. 不同的隔离级别产生不同的影响.
    • Atomicity(原子性), 原子性是数据库事务的最重要特性, 也是用户的目的(本质). 用户之所以使用事务, 是因为用户追求的正是原子性

    数据库事务常常和锁一起使用, 无论是用户的意图, 或者是数据库系统的实现原理, 事务都和锁紧密联系在一起. 大部分的事务都涉及到单一资源的争抢.
    Continue reading »

    Posted by ideawu at 2021-05-02 13:30:21
|<<<123456789>>>| 4/136 Pages, 812 Results.