Skip to content

Commit

Permalink
Update ch11.md
Browse files Browse the repository at this point in the history
  • Loading branch information
songpengwei authored Mar 26, 2024
1 parent 6df7f28 commit bc4facb
Showing 1 changed file with 5 additions and 5 deletions.
10 changes: 5 additions & 5 deletions ch11.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@

- **UDP 多播**。UDP 多播广泛用在金融系统的数据流中,如对时延要求很高的股票市场中的大盘动态。尽管 UDP 本身是不可靠的,但是可以在应用层增加可靠性算法(类似在应用层实现 TCP 的一些算法),对丢失的信息进行恢复(生产者需要记住所有已发送的消息,才可以按需进行重传)。
- **无 broker 的消息队列**。像 ZeroMQ 和 nanomsg 等不使用消息 broker 的以库形式提供的消息队列,依赖 TCP 或者 IP 多播等方式实现了支持发布订阅的消息队列。
- **StatsD 和 Brubeck**。这两个系统底层依赖 UDP 协议进行传递消息,以监控所有机器、并收集相关数据指标。(在 **StatsD协议中,只有事件都收到,counter 相关指标才会正确;使用 UDP 就意味者使用一种**尽可能正确**的保证)。
- **StatsD 和 Brubeck**。这两个系统底层依赖 UDP 协议进行传递消息,以监控所有机器、并收集相关数据指标。(在 **StatsD**协议中,只有事件都收到,counter 相关指标才会正确;使用 UDP 就意味者使用一种**尽可能正确**的保证)。
- **Webhooks**。如果消费者在网络上暴露出了一个服务,则生产者可以通过 HTTP 或者 RPC 请求(参见[经由服务的数据流:REST 和 RPC](https://ddia.qtmuniao.com/#/ch04?id=%e7%bb%8f%e7%94%b1%e6%9c%8d%e5%8a%a1%e7%9a%84%e6%95%b0%e6%8d%ae%e6%b5%81%ef%bc%9arest-%e5%92%8c-rpc))来将数据打到消费者中。这就是 webhooks 背后的思想:一个服务会向另一个服务进行注册,并在有事件产生时向该服务发送一个请求。

这种直接消息系统在其目标场景中通常能够工作的很好,但需要应用层代码自己承担、处理消息丢失的可能性。此外,这些系统能够进行的容错很有限:虽然这些系统在检测到丢包后会进行重传,但它们通常会假设**生产者和消费者都一直在线**(这是一个很强的假设)。
Expand Down Expand Up @@ -231,9 +231,9 @@ Apache Kafka,Amazon Kinesis Streams 和 Twitter 的 DistributedLog 背后都

除非你使用了某些并发检测机制(参见[并发写入检测](https://ddia.qtmuniao.com/#/ch05?id=%e5%b9%b6%e5%8f%91%e5%86%99%e5%85%a5%e6%a3%80%e6%b5%8b)),否则你可能根本注意不到并发写的发生——一个值就这样悄悄的被其他值覆盖了。

双写的另一个重要问题是:一个系统中的写入成功了而往另外一个系统中的写入却失败了。当然,这本质上是一个容错问题而非并发写问题,但仍然会导致两个数据系统处于不一致的状态。想要保证两个系统的写入“要么都成功、要么都失败”是一个原子提交问题(参见[原子提交和两阶段提交](https://ddia.qtmuniao.com/#/ch09?id=%e5%8e%9f%e5%ad%90%e6%8f%90%e4%ba%a4%e5%92%8c%e4%b8%a4%e9%98%b6%e6%ae%b5%e6%8f%90%e4%ba%a4)**),解决这个问题的代价十分高昂(两阶段提交代价很大)。
双写的另一个重要问题是:一个系统中的写入成功了而往另外一个系统中的写入却失败了。当然,这本质上是一个容错问题而非并发写问题,但仍然会导致两个数据系统处于不一致的状态。想要保证两个系统的写入“要么都成功、要么都失败”是一个原子提交问题(参见[原子提交和两阶段提交](https://ddia.qtmuniao.com/#/ch09?id=%e5%8e%9f%e5%ad%90%e6%8f%90%e4%ba%a4%e5%92%8c%e4%b8%a4%e9%98%b6%e6%ae%b5%e6%8f%90%e4%ba%a4)),解决这个问题的代价十分高昂(两阶段提交代价很大)。

在使用单主模型的数据库中,主节点会决定写入的顺序,从节点会跟随主节点,最终数据库中所有节点的状态机都会收敛到相同的状态。但在上图中,并没有一个跨系统的、全局的主节点:数据库和搜索引擎都会**独立地**接受写入(主节点本质上就是一个对外的数据接收点,而如果有多个写入接收点,本质上是多主),而互不跟随,因此很容易发生冲突(参见[多主模型](https://ddia.qtmuniao.com/#/ch05?id=%e5%a4%9a%e4%b8%bb%e6%a8%a1%e5%9e%8b)**)。
在使用单主模型的数据库中,主节点会决定写入的顺序,从节点会跟随主节点,最终数据库中所有节点的状态机都会收敛到相同的状态。但在上图中,并没有一个跨系统的、全局的主节点:数据库和搜索引擎都会**独立地**接受写入(主节点本质上就是一个对外的数据接收点,而如果有多个写入接收点,本质上是多主),而互不跟随,因此很容易发生冲突(参见[多主模型](https://ddia.qtmuniao.com/#/ch05?id=%e5%a4%9a%e4%b8%bb%e6%a8%a1%e5%9e%8b))。

如果我们对于多个系统真正的只有一个主节点,让其他系统跟随这个主节点,这种情况才会被解决。比如,在上面的例子中,让数据库充当主节点,让存储引擎成为数据库的从节点跟,跟随其写入。但在实践中,这可能吗?

Expand All @@ -255,7 +255,7 @@ Apache Kafka,Amazon Kinesis Streams 和 Twitter 的 DistributedLog 背后都

本质上,CDC 实现了我们上面提到的,让数据库成为领导者(事件捕获的源头),让其他系统成为跟随者。由于对消息的保序性,基于日志的消息代理非常适合将 CDC 的事件流导给其他数据系统。

数据库的触发器可以用来实现 CDC(参考[基于触发器的复制](https://ddia.qtmuniao.com/#/ch05?id=%e5%9f%ba%e4%ba%8e%e8%a7%a6%e5%8f%91%e5%99%a8%e7%9a%84%e5%a4%8d%e5%88%b6)**)。具体来说,可以注册一些触发器来监听所有数据库表的变更,然后将变更统一写入 changelog 表。然而,这种方式容错性很低且有性能问题。需要用比较鲁棒的方式来解析复制日志,尽管可能会遇到一些问题,比如处理模式变更。
数据库的触发器可以用来实现 CDC(参考[基于触发器的复制](https://ddia.qtmuniao.com/#/ch05?id=%e5%9f%ba%e4%ba%8e%e8%a7%a6%e5%8f%91%e5%99%a8%e7%9a%84%e5%a4%8d%e5%88%b6))。具体来说,可以注册一些触发器来监听所有数据库表的变更,然后将变更统一写入 changelog 表。然而,这种方式容错性很低且有性能问题。需要用比较鲁棒的方式来解析复制日志,尽管可能会遇到一些问题,比如处理模式变更。

在工业界中,LinkedIn 的 Databus,Facebook 的 Wormhole 和 Yahoo 的 Sherpa 就大规模的使用了这种思想。Bottled Water 依托解析 PostgreSQL 的 WAL 实现了 CDC,Maxwell 和 Debezium 通过解析 MySQL 的 binlog 实现的 CDC,Mongoriver 通过读取 MongoDB 的 oplog 实现 CDC,GoldenGate 也针对 Oracle 实现了类似的功能。

Expand Down Expand Up @@ -465,7 +465,7 @@ CEP 系统常使用偏高层的描述式查询语言,如 SQL 或者图形用

### 管理物化视图

我们在数据库和流处理(TODO: link)一节中提到过,数据库的变更流可以用来维护一些衍生数据系统,如缓存、搜索索引和数据仓库。这些衍生数据系统可以看做物化视图(参见[聚合:数据立方和物化视图](https://ddia.qtmuniao.com/#/ch03?id=%e8%81%9a%e5%90%88%ef%bc%9a%e6%95%b0%e6%8d%ae%e7%ab%8b%e6%96%b9%e5%92%8c%e7%89%a9%e5%8c%96%e8%a7%86%e5%9b%be)**)的一些特例:**构造一个面向某种查询优化的视图,并将新到来的更改不断更新到该视图上。
我们在数据库和流处理(TODO: link)一节中提到过,数据库的变更流可以用来维护一些衍生数据系统,如缓存、搜索索引和数据仓库。这些衍生数据系统可以看做物化视图(参见[聚合:数据立方和物化视图](https://ddia.qtmuniao.com/#/ch03?id=%e8%81%9a%e5%90%88%ef%bc%9a%e6%95%b0%e6%8d%ae%e7%ab%8b%e6%96%b9%e5%92%8c%e7%89%a9%e5%8c%96%e8%a7%86%e5%9b%be))的一些特例:**构造一个面向某种查询优化的视图,并将新到来的更改不断更新到该视图上。

类似的,在事件溯源系统中,应用层的状态也是通过持续应用事件日志来维持的;这里的应用层的状态本质上也是一种物化视图。但和**数据流分析**场景不同,在**物化视图**场景中仅考虑固定的时间窗口内的状态是不够的——物化视图通常需要将所有时间以来的事件进行叠加应用,除非,有些过时日志已经通过日志紧缩(TODO: link)被删掉了。如果仍然用时间窗口来解释的话,就是——在物化视图的场景中,你需要一个足够长的、一直延伸到事件流起点的时间窗口。

Expand Down

0 comments on commit bc4facb

Please sign in to comment.