起因
最近零信任系统终于做完了,能休息一下了 ~_~ 呼~
在做的这个零信任系统里面,有一部分是需要对大量的日志进行采集,分析出用户登录的实时信息,幻化成一条条链接(或者叫会话)。其实叫什么也好,目的就是要在大量的日志中得到用户和IP地址的映射关系。
当然,本文并不是想讲关于零信任怎么做或者是用户链接怎么获得。这些东西我日后应该会写一些文章来具体记录。本文更加偏向于在一些日志收集分析系统中,如何更好的处理并发,如何保证高可靠,如何做的更易扩展等方面的一些思考。
本文所述的系统使用了大部分的开源方案,他们包括但不限于:
1、FileBeat https://www.elastic.co/products/beats/filebeat
2、Logstash https://www.elastic.co/products/logstash
3、RabbitMQ https://www.rabbitmq.com/
4、proc_stream https://github.com/cinjoseph/proc_stream
架构的进化
最初的想法特别简单,就是想收集上来数据做一些简单的处理。所以最初的框架大概是下图这个样子
(图中没有画logstash,是因为Logstash只是为了接收beat上传的数据,然后转给MQ,在本系统中,他们其实逻辑上是一个节点)

但是如此简单的系统肯定是不能拿来线上用的。即使我们这个不是一个对外业务,但是多少也得注意一些并发和可用性的问题。上图中,很明显的两个点是RMQ和Processer都是单点,如果任意一个故障,都会导致系统不可用。
所以对此架构做一些小小的修改

我把MQ和Processer都增加一个,让所有Beat都轮训往这两个MQ上面发送。
这样修改后单点的问题不但解决了,而且还解决了一部分的并发问题。等于是所有的日志处理都有两个人来承担。以前一个processer可能要单秒处理100条,现在只要处理50条就足矣。
但是这个架构依旧有一部分小问题,因为从mq开始,后面都是串联的。如果任何一个节点出问题,还是会导致一串节点都嗝屁。
遵循有资源就不能浪费的原则,我们要把这个小架构改成任何一个节点down机不会导致其他的节点只能等待down机几点恢复,而是可以帮助其他处理流程去处理。
这样改也很简单,因为Processer一般情况都是自研,只要一个Processer同时监听多个MQ的消息即可。
如果只是处理简单的日志还好,但是如果处理几条日志之间是有关联的,就有可能出现日志1被采集到了左边的MQ,日志2的日志被采集到了右边。这样的话处理一定会出问题,两边可能会一直等待着另一条日志的到来。
所以,在这种架构上,为了数据同步,我们还需要一个缓存,来同步各个processer中的状态和数据。
架构此时演变成了这样:

剩下的只是横向扩展
其实这个架构,不用纠结于每个节点是不是足够健壮。因为这个其实只是逻辑图。每一个节点可能不只是一个单机,而是一个多机器,多地分布的集群。
如何保证在节点宕机数据不会丢失
其实现在很多中间组件都会有ACK的确认,RabbitMQ就有这种功能。开启之后,只有收到ACK后才认为该条数据被消费掉,否则会等待ACK,直到消费者断开链接或者超时后,讲该条数据重新放入队列中供消费者消费。
这中间的层层确认,以及每一层对数据的检查,都是保证数据不丢的一个前提。
“每一层对数据的检查” 这个应该有很多门道,之后研究研究专门再写一篇。
哈希缓存
目前这个架构已经演变的较为完善。看着下面三层都可以横向扩展了,但是还有一层仍然是单点,就是缓存层。
所以我想,可以根据数据相互之间关联的唯一字段的去做哈希结构,分布式的存储这些数据,来解决缓存的压力。
有必要吗?当然有的!
试想一下,我们现在有10个Beat用来收集数据,每一个beat 10000条/s, 那我们的数据汇总后就是10w条每秒
采集层可以轮训的分发这些数据。
队列层也可以部署很多很多节点来分布缓存。
处理层甚至可以部署更多的节点,来分担处理的压力。
以上三个层都有个共同点,就是不需要数据之前的同步或关联。
但是从处理层往后,就需要数据关联了。所以如果只有一个缓存的话,那所有数据汇总之后对单个缓存的访问是10w+/s
当然可以部署缓存集群,但是如果访问量再大呢?缓存集群之间的数据同步本身就是一个很大的开销。
所以,我们不如把数据之间的逻辑和存储关系下放至处理层,
让处理根据一些唯一的值来算一个唯一的哈希,在根据哈希的值去做一个分布式的存储和查找。
这样的话,缓存的压力也就解决了。
最后,任何一个节点,都可以扩展了
就成了如下的样子:
