一个可用的复杂系统总是从可用的简单系统演进来的。反过来这话也是正确的:从零开始设计的复杂系统从来都用不了,也没办法把它变成可用。

——John Gal,《系统学》(1975)

发送事件流

消息系统

发送事件通知的常用方式。

  • 如果生产者发送消息的速度快于消费者处理,会发生什么?
  • 如果节点崩溃或暂时离线,是否会有消息丢失?

生产者与消费者直接消息传递

即无代理的方式。这种方式当消费者离线时会丢失消息。

常见场景:

  • UDP组播广泛应用在金融行业,比如股票市场等低延迟场景。
  • 无代理的消息库,如ZeroMQ和nanomsg,通过TCP或IP多播实现发布/订阅消息传递。
  • StatsD和Brubeck使用UDP手机网络中所有机器的指标并进行监控。
  • 网络上公开服务,生产者直接发出HTTP或RPC请求将消息推送给消费者。

消息代理(无日志)

本质上是一种针对消息流处理而优化的数据库。常见产品Rabbit MQ、ActiveMQ等。

只能消费订阅之后的消息,也就是历史的消息已经不能消费了。

基于日志的消息存储

将历史的消息存储为日志形式。代表产品Kafka、Twitter DistrbutedLog。

数据库与流

事件是成功的命令。一个请求到来时最初是一个命令,它可能失败,或违反某种约束。一旦它成功,它就是一个事件了。

变更数据捕获(changed data capture,CDC)是一种设计理念。不是记录数据的当前状态,而是数据变化的过程。

事件溯源(event source)是一种强大的数据建模技术,是对CDC思想的一种应用。事件溯源使得应用程序随着时间的推移更容易演化,更安全,杜绝了直接覆盖数据的情形,更容易理解发生了什么来帮助调试分析。比如用户加购一个商品后又删除,使用事件溯源就会捕获到更多的细节,用户可能将来会买,或者找到了替代品。

流处理

流处理的使用场景

复杂事件处理(Complex Event Processing,CEP)可以在流中搜索特定的模式,类似于正则表达式。查询和数据的关系在CEP和普通数据库是反过来的。在普通数据库中,数据是长期存储的,查询是临时的,一旦查询完,查询就没了。而在CEP中,查询是长期的,输入流中的事件不断流过匹配查询。常见实现Esper、IBM Info Sphere Streams、Apama等。

流分析与CEP界限有些模糊。作为一般规则,分析往往不太关心找到特定的事件序列,而更多地面向大量事件的累积效果和统计指标。例如:

  • 测量某种类型事件的速率。
  • 计算一段时间内某个值的滚动平均值。
  • 将当前的统计数据与之前的时间间隔进行比较。

流分析有时使用概率算法,比如布隆过滤器,基数统计的HyperLogLog,但是流不等于就是概率的,不精确的。

Actor与流:

  • Actor是管理通信模块的并发和分布式执行的机制,而流处理是数据管理技术。
  • Actor之间交流往往是短暂的,并且一对一,而事件日志是持久的,多用户的。
  • Actor可以以任意方式进行通信(包括循环请求/响应模式),但流处理器通常设置在非循环流水线中,其中每个流是一个特定作业的输出,并且从一组定义明确的输入流派生而来。

流的时间问题

事件时间与处理时间

使用事件时间得确定什么时候结束,使用处理事件可能导致事件错乱,处理事件的顺序和事件时间不一样。

窗口类型:

  • 轮转窗口

    长度固定,每个事件都属于一个窗口。比如一个一分钟窗口,10:03:00~10:03:59分到一个窗口,10:04:00~10:04:59是下一个窗口。

  • 跳跃窗口

    也具有固定长度,但是允许重叠。例如一个五分钟窗口,设定跳跃值为一分钟,10:03:00~10:07:59为一个窗口,下一个窗口为10:04:00~10:08:59,以此类推。

  • 滑动窗口

    包含某个间隔内发生地所有事件。例如,一个五分钟的滑动窗口将包括10:03:39~10:08:12的事件,因为他们相距不到五分钟。可以通过保留按时间排序的事件缓冲区并从移除旧事件来实现。

  • 会话窗口

    没有固定的持续时间,而是通过将同一用户在时间上紧密相关的所有事件分组在一起而定义的,一旦用户在一段事件内处于非活动状态,则窗口结束。

流式join

  • 流和流join
  • 流和表join
  • 表和表join