我们对于不同时间段应用的期望运行情况可能是不一样的,比如一天当中的几个小时,一星期中的几天或者一年当中的几个月。举个例子来说,淘宝应用在周末两天可能会存在较多的交易从而产生高于平时的吞吐量。一个工资支付应用可能相较于一个月中的其他事件,会在月初和月末产生较大的流量。一个客户管理的应用在周一的营业时间相较于周末来说会有较大的工作负荷压力。
我们在 2.0 的版本开始受制于 Cassandra。
一方面,我们建表的时候,为了某些性能在 Partition Key 内增加了时间戳导致查询的时候必须要提供时间区间。另一方面,沿用的是2年前的 Cassandra 版本,无法像 3.0 之后的版本一样有更丰富的查询方式,比如基于某一列的查询。
其次,在 2.0 之前的版本,每条指标的计算结果,就算是 Normal 都会存入 Cassandra,这是因为 Flink 版本计算的遗留问题。而我们在设计了告警事件的状态变化告警之后,存储 Normal 变为意义不大。
最后,除了告警事件,其他的数据:如规则、策略、行为等配置数据,撑死了也就几十万条,完全没有必要用 Cassandra 来存储。它的使用,反而会增加企业级的部署麻烦。
所以我们进行了变更,用 MySQL 去存储除告警事件之外的数据。告警事件因为有了金字塔模块,所以我们直接写入 Kafka 即可。
为了应对 2.0 版本的接入麻烦,因为构造 SQL、告警通知行为等在 2.0 版本都是外包给业务线自己做的,我们只是打造了一个小而美的 CEP 引擎。所以只有主要的产品 Ai 接入了我们系统。为此,我们把 Ai 中开发的和告警相对于的代码剥离,专门打造了 CEP 上层的告警系统,并要求业务方提供了应用、指标等 API。自行消费处理 Kafka 中的告警事件,触发行为。
其次,做的一个很大改动就是适配了各个业务线的探针数据,直接接受全量数据。
4.0 阶段的告警其实并没有开发,当时主要协作的另一位同事在6月离职,我在8月底完成 3.0 的工作后也离职,但是设计在年初就完成了。
我们在开发金子塔存储的时候,很大的一个问题就是如何流式消费 Kafka 的数据,当时正好 Kafka 提供了 Stream 编程。我们使用了 Akka Stream 去开发了对应的聚合应用 Analytic Store。
同样,我们希望这个单独开发的 CEP 应用,也能变成 Reactive 化。对应的我们将上下行的 Kafka 分别抽象为 Source 和 Sink 层,它们可以使用 Restful API 动态创建,而非现在写死在数据库内。
基于这一思想,我们大概有上述的技术架构(图可能不是很清晰)。
设计目标:
增加CEP处理数据的伸缩性(scalability),水平伸缩以及垂直伸缩
提高CEP引擎的弹性(Resilience),也就是CEP处理引擎的容错能力
设计思路:
在数据源对数据进行分流(分治);在Akka集群里,创建Kafka Conumser Group, Conumser个数与Topic的分区数一样,分布到Akka的不同节点上。这样分布到Akka某个节点到event数据就会大大减少。
在数据源区分Command与Event;把Rule相关到Command与采集到metric event打到不同的topic,这样当Event数据很大时,也不会影响Command的消费,减少Rule管理的延迟。
对Rule Command在Akka中采用singleton RuleDispatcher单独消费,在集群中进行分发,并且把注册ruleId分发到集群中每个EventDispatcher里。因为Rule Command流量相对于Event流量太少,也不会出现系统瓶颈。
因为RuleDispatcher在Akka集群是全局唯一的,容易出现单点故障。因为RuleDispathcer会保存注册后的RuleIds,需要对RuleId进行备份,这个可以采用PersitentActor来
实现
对于RuleDispatcher down掉重启的这段时间内,因为RuleDispatcher分发过RuleId到各个节点的EventDispatcher,因此各个节点事件分发暂时不会受到影响。
在Akka集群里每一个Kafka conumser,对于一个EventDipatcher,负责把事件分发对感兴趣对RuleActor(根据每个RuleId对应感兴趣对告警对象)。
感谢博主,收获很多,个人觉得整个架构重点在关注数据流式处理和存储,为什么不考虑用类似influxdb等时序数据库引擎实现呢?
雨帆大佬,这篇文章写的是非常好啦。小弟还有些不懂的地方,可以求个认识么?邮箱是QQ也是微信。