共计 4604 个字符,预计需要花费 12 分钟才能阅读完成。
全量 SQL(所有拜访数据库的 SQL)能够无效地帮忙平安进行数据库审计,帮忙业务疾速排查性能问题。个别可通过开启 genlog 日志或者启动 MySQL 审计插件形式来进行获取,而美团选用了一种非侵入式的旁路抓包计划,应用 Go 语言实现。无论采纳哪种计划,都须要重点关注它对数据库的性能损耗。本文介绍了美团根底研发平台抓包计划在数据库审计实际中遇到的性能问题以及优化实际,心愿能对大家有所帮忙或启发。
1 背景
数据库安全始终是美团信息安全团队和数据库团队十分重视的畛域,但因为历史起因,对数据库的拜访只具备采样审计能力,导致对于一些攻打事件无奈疾速地发现、定损和优化。平安团队依据历史教训,发现攻打拜访数据库基本上都存在着某些特色,常常会应用一些特定 SQL,咱们心愿通过对 MySQL 拜访流量进行全量分析,辨认出习用 SQL,在数据库安全性上做到对症下药。
2 现状及挑战
下图是采样 MySQL 审计零碎的架构图,数据采集端基于 pcap 抓包形式实现,数据处理端选用美团大数据中心的日志接入计划。所有 MySQL 实例都部署了用于采集 MySQL 相干数据的 rds-agent、日志收集的 log-agent。rds-agent 抓取到 MySQL 拜访数据,通过 log-agent 上报到日志接收端,为了缩小延时,上报端与接收端间做了同机房调度优化。日志接收端把数据写入到约定的 Kafka 中,平安团队通过 Storm 实时生产 Kafka 剖析出攻打事件,并定期拉数据长久化到 Hive 中。
咱们发现,通常被攻打的都是一些外围 MySQL 集群。经统计发现,这些集群单机最大 QPS 的 9995 线约 5 万次左右。rds-agent 作为 MySQL 机器上的一个寄生过程,为了宿主稳定性,资源管制也极为重要。为了评估 rds-agent 在高 QPS 下的体现,咱们用 Sysbench 对 MySQL 进行压测,察看在不同 QPS 下 rds-agent 抓取的数据失落率和 CPU 耗费状况,从上面的压测数据来看后果比拟蹩脚:
QPS | 失落率 | CPU 利用率 |
---|---|---|
10368.72 | 1.03% | 307.35% |
17172.61 | 7.23% | 599.90% |
29005.51 | 28.75% | 662.39% |
42697.05 | 51.73% | 622.34% |
50833.50 | 63.95% | 601.39% |
如何在高 QPS 下保障较低的失落率与 CPU 耗费?曾经成为以后零碎的一个亟待解决的难题与挑战。
3 剖析及优化
上面次要介绍围绕失落率与 CPU 耗费这一问题,咱们对数据采集端在流程、调度、垃圾回收和协定方面做的剖析与改良。
3.1 数据采集端介绍
首先,简要介绍一下数据采集端 rds-agent,它是一个 MySQL 实例上的过程,采纳 Go 语言编写,基于开源的 MysqlProbe 的 Agent 革新。通过监听网卡上 MySQL 端口的流量,剖析出客户端的拜访工夫、起源 IP、用户名、SQL、指标数据库和指标 IP 等审计信息。上面是其架构图,次要分为 5 大功能模块:
1. probe
probe 意为探针,采纳了 gopacket 作为抓包计划,它是谷歌开源的一个 Go 抓包库,封装了 pcap。probe 把抓取到原始的数据链路层帧封装成 TCP 层的数据包。通过变种的 Fowler-Noll-Vo 算法哈希源和目标 IP port 字段,疾速实现把数据库连贯打散到不同的 worker 中,该算法保障了同一连贯的来包与回包的哈希值一样。
2. watcher
登录用户名对于审计来说极其重要,客户端往往都是通过长连贯拜访 MySQL,而登录信息仅呈现在 MySQL 通信协议的认证握手阶段,仅通过抓包容易错过。
watcher 通过定时执行 show processlist 获取以后数据库的所有连贯数据,通过比照 Host 字段与以后包的客户端 ip port,弥补错过的用户名信息。
3. worker
不同的 worker 负责管理不同数据库连贯的生命周期,一个 worker 治理多个连贯。通过定期比对 worker 的以后连贯列表与 watcher 中的连贯列表,及时发现过期的连贯,敞开并开释相干资源,避免内存透露。
4. connStream
整个数据采集端的外围逻辑,负责依据 MySQL 协定解析 TCP 数据包并辨认出特定 SQL,一个连贯对应一个 connStream Goroutine。因为 SQL 中可能蕴含敏感数据,connStream 还负责对 SQL 进行脱敏,具体的特定 SQL 辨认策略,因为平安方面起因,这里不再进行开展。
5. sender
负责数据上报逻辑,通过 thrift 协定将 connStream 解析出的审计数据上报给 log-agent。
3.2 根底性能测试
抓包库 gopacket 的性能间接决定了零碎性能下限,为了探索问题是否出在 gopacket 上,咱们编写了繁难的 tcp-client 和 tcp-server,独自对 gopacket 在数据流向图中波及到的前三个步骤(如下图所示)进行了性能测试,从上面的测试后果数据上看,性能瓶颈点不在 gopacket。
QPS | pcap 缓冲区 | 失落率 | CPU 利用率 |
---|---|---|---|
100000 | 100MB | 0% | 144.9% |
3.3 CPU 画像剖析
失落率与 CPU 耗费二者密不可分,为了探索如此高 CPU 耗费的起因,咱们用 Go 自带的 pprof 工具对过程的 CPU 耗费进行了画像剖析,从上面火焰图的调用函数能够演绎出几个大头:SQL 脱敏、解包、GC 和 Goroutine 调度。上面次要介绍一下围绕它们做的优化工作。
3.4 脱敏剖析及改良
因为 SQL 中可能蕴含敏感信息,出于平安思考,rds-agent 会对每一条 SQL 进行脱敏解决。
脱敏操作应用了 pingcap 的 SQL 解析器对 SQL 进行模板化:即把 SQL 中的值全副替换成“?”来达到目标,该操作须要解析出 SQL 的形象语法树,代价较高。以后只有采样和抓取特定 SQL 的需要,没有必要在解析阶段对每条 SQL 进行脱敏。这里在流程上进行了优化,把脱敏下沉到上报模块,只对最终发送进来的样本脱敏。
这个优化获得的成果如下:
比照项 | QPS | 失落率 | CPU 利用率 |
---|---|---|---|
改良前 | 50833.50 | 63.95% | 601.39% |
改良后 | 51246.47 | <font color=##FF0000>31.95%</font> | <font color=##FF0000>259.59%</font> |
3.5 调度剖析及改良
从上面的数据流向图能够看出整个链路比拟长,容易呈现性能瓶颈点。同时存在泛滥高频运行的 Goroutine(红色局部),因为数量多,Go 须要常常在这些 Goroutine 间进行调度切换,切换对于咱们这种 CPU 密集型的程序来说无疑是一种累赘。
针对该问题,咱们做了如下优化:
- 缩短链路 :分流、worker、解析 SQL 等模块合并成一个 Goroutine 解析器。
- 升高切换频率 :解析器每 5ms 从网络协议包的队列中取一次,相当于手动触发切换。(5ms 也是一个屡次测试后的折中数据,太小会耗费更多的 CPU,太大会引起数据失落)
这个优化获得的成果如下:
比照项 | QPS | 失落率 | CPU 利用率 |
---|---|---|---|
改良前 | 51246.47 | 31.95% | 259.59% |
改良后 | 51229.54 | <font color=##FF0000>0%</font> | <font color=##FF0000>206.87%</font> |
3.6 垃圾回收压力剖析及改良
下图为 rds-agent 抓包 30 秒,已调配指针对象的火焰图。能够看出曾经调配了 4 千多万个对象,GC 压力可想而知。对于 GC,咱们理解到如下两种优化计划:
- 池化 :Go 的规范库中提供了一个 sync.Pool 对象池,可通过复用对象来缩小对象调配,从而升高 GC 压力。
- 手动治理内存 :通过零碎调用 mmap 间接向 OS 申请内存,绕过 GC,实现内存的手动治理。
然而,计划 2 容易呈现内存透露。从稳定性的角度思考,咱们最终抉择了计划 1 来治理高频调用函数里创立的指针对象,这个优化获得的成果如下:
比照项 | QPS | 失落率 | CPU 利用率 |
---|---|---|---|
改良前 | 51229.54 | 0% | 206.87% |
改良后 | 51275.11 | 0% | <font color=##FF0000>153.32%</font> |
3.7 解包剖析及改良
MySQL 是基于 TCP 协定之上的,在性能调试过程中,咱们发现了很多空包。从上面的 MySQL 客户端 - 服务端数据的交互图能够看出:当客户端发送一条 SQL 命令,服务端响应后果,因为 TCP 的音讯确认机制,客户端会发送一个空的 ack 包来确认音讯,而且空包在整个流程中的比例较大,它们会穿透到解析环节,在高 QPS 下对于 Goroutine 调度和 GC 来说无疑是一个累赘。
下图是 MySQL 数据包的惟一格局,通过剖析,咱们察看到以下特点:
- 一个残缺的 MySQL 数据包长度 >=4Byte
- 客户端新发送命令的 sequence id 都是为 0 或者 1
而 pcap 反对设置过滤规定,让咱们能够在内核层将空包排除掉,上面是上述特点对应的两条过滤规定:
特点 1:ip[2:2] - ((ip[0] & 0x0f) << 2) - ((tcp[12:1] & 0xf0) >> 2) >= 4
特点 2:(dst host {localIP} and dst port 3306 and (tcp[(((tcp[12:1] & 0xf0) >> 2) + 3)] <= 0x01))
这个优化获得的成果如下:
比照项 | QPS | 失落率 | CPU 利用率 |
---|---|---|---|
改良前 | 51275.11 | 0% | 153.32% |
改良后 | 51246.02 | 0% | <font color=##FF0000>142.58%</font> |
基于上述教训,咱们对数据采集端进行性能代码重构,同时还进行一些其它优化。
4 最终成绩
上面是优化前后的数据比照,失落率从最高 60% 降落到了 0%, CPU 耗费从最高占用 6 个核降落到了 1 个核。
为了探索抓包性能对 MySQL 性能损耗,咱们用 Sysbench 做了一个性能比照测试。从上面的后果数据能够看出性能对 MySQL 的 TPS、QPS 和响应工夫 99 线指标最高大概有 6% 的损耗。
5 将来布局
尽管咱们对抓包计划进行了各种优化,但对于一些提早敏感的业务来说性能损耗还是偏大,而且该计划对一些非凡场景反对较差:如 TCP 协定层产生丢包、重传、乱序时,MySQL 协定层应用压缩、传输大 SQL 时。而业界广泛采纳了间接革新 MySQL 内核的形式来输入全量 SQL,同时也反对输入更多的指标数据。目前,数据库内核团队也实现了该计划开发,正在线上灰度替换抓包计划中。另外,对于线上全量 SQL 端到端失落率指标的缺失,咱们也将陆续进行补齐。
本文作者
粟含,来自于美团根底研发平台 / 根底技术部 / 数据库技术核心。
招聘信息
美团根底技术部 - 数据库技术核心诚招高级、资深技术专家,Base 上海、北京。美团关系数据库规模大,每年疾速的增长,每天承载数千亿的拜访流量。在这里能够体验高并发、高可用、高可扩展性的业务挑战,能够紧跟并开辟业界前沿技术,领会到技术提高带来的生产力晋升,欢送投递简历至:suhan03@meituan.com。
浏览美团技术团队更多技术文章合集
前端 | 算法 | 后端 | 数据 | 平安 | 运维 | iOS | Android | 测试
| 在公众号菜单栏对话框回复【2021 年货】、【2020 年货】、【2019 年货】、【2018 年货】、【2017 年货】等关键词,可查看美团技术团队历年技术文章合集。
| 本文系美团技术团队出品,著作权归属美团。欢送出于分享和交换等非商业目标转载或应用本文内容,敬请注明“内容转载自美团技术团队”。本文未经许可,不得进行商业性转载或者应用。任何商用行为,请发送邮件至 tech@meituan.com 申请受权。