比较难理解. 是指事务完成后, 结果必须和预期一致, 不能产生非期望的后果. 例如, 期望将某个数据修改为 1, 但最后得到的结果却是 30, 不符合预期, 和预期不一致.
结果是可预测的, 唯一的. 无论重放多少次, 结果都一样.
比较难理解. 是指事务完成后, 结果必须和预期一致, 不能产生非期望的后果. 例如, 期望将某个数据修改为 1, 但最后得到的结果却是 30, 不符合预期, 和预期不一致.
结果是可预测的, 唯一的. 无论重放多少次, 结果都一样.
如果事务异常中断, 那么正常的读取流程读取到任意一个参与者时, 开始检测圆环. 若能检测到, 便能判断出事务的状态(Committed). 若圆环断开, 则事务处于 Aborted 状态.
两阶段提交有一个优点, 那便是 Prepare 的成本比较高, 资源执行时间较长, 失败概率较高. 而读流程遇到 Prepared 状态的资源, 需要向单点(Commit Point)查询求证资源的真实状态, 极大的拖慢了读流程.
第1步, 要求所有资源进入 Preparing 状态, 同时关联变更操作, 对于该状态, 读流程不需要向单点查询求证.
第2步, 要求所有资源进入 Prepared 状态, 这个操作成本极小.
第3步, 要求各资源清理状态.
分布式事务架构中, 存在一个独立于参与者之外协调者单点(Commit Point), 当参与者存在未决(In-Doubt)事务时, 需要向单点求证. 所以, 在两阶段(2PC)事务处理流程中, 除了写单点之外, 还必须保证参与者也有 Commit Point. 否则, 如果参与者缺失 Commit Point, 而此时协调者的 Commit Point 已经丢失, 在参与者进行日志回放时, 便无法处理 In-Doubt 事务.
因此, 有几个要点:
写 C++ 的程序员, 特别是那种只写 C++ 的程序员, 尤其是只写 C++, 还有点擅长的程序员, 会有很多思维误区.
例如, 抽象能力不足.
在做系统设计时, C++ 程序员往往在形式化上面进行抽象, 就跟 C++ 语言一样, 主要在语法层面提供特性, 因为 C++ 就是要在编译时解决问题. 但 Java 程序员, 或者使用其它面向对象编程语言的程序员, 一般是在本质层面进行抽象.
不是说, 关注本质的程序员就更好. 只是, 很悲哀的, C++ 程序员往往"浮于表面"而不自知, 反而认为自己专注底层, 做的是核心, 实则太过于追求形式化.
有很多软件假借分布式之名, 是伪分布式, 造成这个现象很大的原因是分布式系统的定义模糊不清. 我尝试定义分布式系统:
share nothing, 系统中存在多个独立的节点, 互相不知道其它节点. 某个节点可能知道存在着其它的节点, 但它不知道其它节点在哪, 有多少个. 即使知道在哪, 数量多少, 也不知道其它节点的内容.
co-operate, 协作. 节点之间遵循某种规则, 一起完成一项大的任务. 例如分布式数据库的 sharding, 不同的节点存在不同的数据, 它们数据之和成为一个整体.
根据这两项原则, etcd 不是分布式数据库, 只是一个多机多副本的单实例数据库, 也许可以称为单机数据库, 但它又确实使用了多机. etcd 的每一个节点都知道, 其它的节点的数据和自己的数据是完全相同的(应该如此). 所以, etcd 是伪分布式系统.
日志(LOG, Journal)是持久化的核心, 是基础, 是必须.
根据日志的用途, 可以分成两类:
WAL 在理想情况下, 单次写的延迟较小, 但有写放大问题, 因为必须有"转存"步骤.
WBL 单次写延迟大, 因为每一次写请求涉及两次持久化, 但没有写放大问题.
-bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory
修改 Mac 的 .bash_profile
export LC_ALL="en_US.UTF-8"