您好,登录后才能下订单哦!
本篇内容介绍了“OpenFalcon在高并发场景的应对手段有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
OpenFalcon 在高并发场景的 7 种应对手段
数据采集推拉抉择
对于监控系统来说,包含几个核心功能:数据采集、历史数据存储、报警,最后是绘图展示及数据挖掘。
数据采集
这一块我们希望做一个大一统的东西,因此要采集很多监控指标,比如 Linux 本身的监控指标,像 CPU、内存、网卡、IO 等,一些硬件指标,比如风扇的转速、温度等等,再加上一些开源软件如 MySQL,Nginx,OpenStack,HBase 等监控指标。
公司内部有很多产品线,每一个服务运行状况都希望采集到,比如中间层服务开了一些 RPC 端口,每一个 RPC 端口在服务过程中,latency 是多少,QPS 是多少,我们都希望了解到。
所以需要覆盖很多监控指标,监控团队刚开始只有两个人,不可能把所有监控指标都采集到——人力不行、技术水平也达不到。
所以我们需要共建监控数据,让专业的人干专业的事。
DBA 同学对 MySQL 比较熟,那他们去采集 MySQL 相关指标,分布式团队同学去采集 HBase 或 Hadoop 等指标,网络组同学去采集交换机路由器指标。
而作为监控团队要做的,就是制订一个规范。制定一个数据进来的机制,然后公司开发人员和运维人员按照规范去推送数据。
数据收集没有采用拉的方式,因为太多数据源,作为一个 Client 去连接源端,采集数据,再关闭连接,会产生很多 time_wait 状态连接,其吞吐必然是不高,所以要把自己做成 Server 端。现在每个周期有 1 亿多条数据。
这个周期简单解释一下,监控数据是一个持续上报,比如 Linux 一些基本监控项一分钟一次采集之后上报,下一分钟再采集再上报。一些像业务监控有 3 分钟的,有 5 分钟的。
因此周期是指数据量是 5 分钟以内,有上报动作的数据。
中间节点快速转发与容错
数据有很多要 Push 到 Server 端,Server 端最前端组件是 Transfer,Transfer 接收到数据后要把它转发给后面两个组件,一个是 Graph(用来做绘图),一个是 Judge(用来做报警判断)。
首先对每一个后端实例创建一个 Queue 出来,比如 20 个 Graph 实例,60 个 Judge 实例,为每个实例创建一个 Queue,每个 Transfer 内存中有 80 个 Queue,
当一条监控数据过来之后,需要判断数据发到哪一个实例,然后放到这个实例对应 Queue。Transfer 接收数据 RPC 逻辑非常简单,数据拿到后放到 Queue 就立马返回。
Agent 到 transfer,transfer 到 judge,judge 到 Redis,Redis 到 alarm,报警链路比较长,如果希望尽快触发报警,链路每一个环节都希望比较快速处理,用 Queue 方式,Transfer 吞吐特别大,不会拖慢整个链路。
数据放在 Queue 中有一个问题,如果不及时转发,比如后端 load 比较高或者挂了,Queue 数据就会堆积,超过内存就会 crash,所以做了一个简单保护措施,将 Queue 设成定长,超过 Queue 长度,数据就放不进来。
数据 Push 到 Queue 后,有一个专门对 Queue 读入 worker,读到了之后转发。转发这个动作由一堆写 worker 完成,这里 worker 是指 goroutine,如此这般,一堆 goroutine 协同工作,来提高转发性能。
一致性哈希分片提高吞吐容量
一致性哈希分片
这么多数据上来不可能由一台机器处理,因此做了一个数据分片,即一个机器只处理一部分数据,报警数据是由 Judge 做分片,绘图数据由 Graph 做分片,这两个都是使用一致性哈希。
一致性哈希分片有一个问题,就是扩缩容比较麻烦,数据打到某个 judge 之后,就会一直打到这个 judge。
当列表发生变化时候,由于一致性哈希算法,原来打到一台 judge 实例的数据就会打到另外一个 Judge 实例,所以 Judge 一定要保证没有状态,这样才能方便扩缩容。
状态标记
其实说它没有状态也不太合适,judge 内存里也存了几个点。比如某一台机器 cpu.idle 数据上来之后,连续 3 ~ 5 次达到一个特定阀值才去报警,而不是达到阀值立马报警。像 CPU,是一直都忙碌状态才去报警,Judge 判断的时候它是判断多个点。
产生报警之后,还有一些后续处理,比如对这个报警事件做一个判断,上次产生事件是什么状态,他是第几次报警,是不是达到了最大报警次数不能再报了,避免重复报警给处理人员造成干扰。一般大家都设置报警 3 次。
因此报警事件需要记录一个状态,标记是否健康,如果有问题,记录当前是第几次。Judge 状态存在数据库,虽然 1 亿条数据上来,实际上报警数据不多,可能只有 10 万条数据级别,因此可以存入数据库,这样 Judge 就剥离了报警事件状态。
虽然 Judge 内存当中还存一些前面所说数据状态,但也不是一个大问题。因为监控数据是源源不断上来,即使丢掉一些状态,新的 Judge 实例很快就会又填充数据。
扩容
一致性哈希对扩容不是很友好,比如 20 台 Graph 的机器如果变成 40 台,势必有老的 Graph 实例的一部分数据打到新的 Graph 上,因此我们做了一个自动数据迁移。
这个自动迁移是由于一致性哈希造成的问题,如果用映射表做分片,在映射表这统一维护数据和 graph 实例对应关系,扩容就简单很多。
数据与策略快速匹配
当数据上来后,要判断这个数据是不是触发了报警策略,策略有很多种,比如我们现在系统中有几千上万条。
上来一条数据之后,要判断这个数据跟哪一条策略相关,然后再判断阀值是多少,是不是要触发报警。
我们选择去数据库同步所有报警策略列表,因为策略列表整个公司不会特别多,虽然数据量多,但是策略不是特别多,比如只有几千条或者几万条。
在策略数据库做了一个简单索引,方便数据上来之后快速定位策略,然后根据阀值看是否要需要报警处理。
为了加快策略判定,需要知道近期一些历史数据,历史存在 Judge 内存中,这样获取速度相对来说快一些。
第一个版本做测试时没有放到内存中,当时用了 56 个 Redis 实例,每个实例大概有 3,000 QPS,那时上的量不大,仍然达到了一个这么高的 QPS。由于并发高,把数据放到 Redis 中并不是一个很好的解决办法,后来就把它放到了Judge 内存里。这样处理起来就快很多。
报警状态也存在 Judge 内存及 DB。如果每个报警判断都去访问 DB 比较耗时,所以就加载到 Judge 内存,相当与缓存的机制,内存没有再去 DB 加载。在 Judge 重启的时候,内存没有数据,这时报警状态的判断需要去 DB 加载,然后再读到内存里。
数据延迟写入,减少 RRD 文件打开次数
时间序列数据自动归档
报警数据存储采用 RRD,RRD 比较有名。大量开源监控软件存储时间序列数据都选用 RRD。
RRD 最大的优点是自动归档。监控数据有一个特点,不需要关心历史监控数据具体的值,只需知道当时的趋势即可。
最新 6 个小时可能有看原始值需求。但是最近 3 天 及 1 个月原始值的需求就很小。而且那个点特别多,一分钟 1 个点,一天有 1440 个点。如果加载 1 个月浏览器不崩才怪。
由于对历史点只要能看到趋势就行。因此监控数据特别需要归档功能。比如一个小时的数据归档为一个点,RRD 可以帮我们做这个事情。
RRD 优化:延迟合并写入
RRD 默认操作性能比较差,它的逻辑是打开 RRD 文件,然后去 seek,write,seek,write,最后 close 文件句柄。一个监控指标对应一个 RRD 文件,比如这个机器上面处理了大约 200 万个监控指标,实际上就有 200 万个 RRD 的文件。
每次写入数据的时候,打开这个 RRD 文件,读头部信息,包含一些 meta 信息,记录了归档策略、数据类型之类数据,然后去做写入操作。
如果每一个数据上来之后都做这个操作,RRD 读写会造成特别大的 IO。虽然现在磁盘都是 SSD,但由于 IO 居高不下,于是做了一个延迟写入的优化。
现在数据都是 1 分钟上报一次,可能有的数据 10 秒或 30 秒上报一次。并不是上报上来立马打开 RRD 文件写入,而是等 10 分钟或者 30 分钟,在内存中缓存一段时间,缓存 30 个点或者 60 个点,一次性把文件打开,一次性写入再关闭,这样可以减少 RRD 文件打开的次数,让 IO 降低一些。
我们根据缓存的时间,比如缓存半个小时,再按照半个小时时间长度来做数据打散,比如现在半个小时是 1,800 秒,举个例子,1,800 秒把它做成 1,800 个槽位,每个数据上来之后平均分散到 1,800 个槽位当中,写的时候慢慢地写,这样做了一个打散操作,避免让 IO 出现一些峰值。
报警事件按优先级入队列缓冲
报警事件量通常不是特别大,但个别时候会比较大——触发一些大面积报警的时候,比如某一个核心交换机挂掉了,会产生特别大的报警。
比如服务依赖于上游某几个服务,上游服务挂了,所有下游服务都报警。如果核心交换机挂了,很多核心服务都受影响,核心服务受影响之后,下游很多服务就产生报警,这样产生一个大面积报警。但通常情况下,报警量都是一个很平稳的一个量。
当大面积报警出现时,我们仍然是应用 Queue 机制,用 Queue 来抹平峰值。
报警的分级处理
我们将报警进行分级,从 P0、P1 一直到 P5,P0 最高。
基于优先级的分级策略
P0、P1 发短信发邮件,并且是收到报警立即发; P2 这个级别发短信不是立即发,而是做一个报警合并; P3、P4 那些低级别就做报警合并,同时不发短信,只发邮件。
我们对报警事件做一个分级,每一个级别就对应 Redis 里面一个Queue。利用 Redis BRPOP 简单实现按照优先级处理报警事件,即先处理 P0,再处理 P1、P2 顺序。
通过限制 Worker 数目发送接口限流
系统本身可能链路比较长,每个链路都希望能够扛住高并发,实际上在系统开发过程当中,我们依赖于其他基础设施,比如内部有 SMTP 服务器来发送邮件,有短信通道来发送短信,但是这些接口扛不住很大的并发。
当要系统依赖调用几个并发能力较差的接口,最好做一个限流。
有一个专门的模块 Sender 发送报警邮件或者报警短信,它发送时候可以给它配置一个 Worker 数量,大家可以理解成最多有多少个线程来调用发送接口。这样就可以保护后端发送接口,不至于把它打挂。
“OpenFalcon在高并发场景的应对手段有哪些”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。