流量收集、分析架构(初步)

流量收集、分析架构(初步)

本篇仅作流量收集、分析设计方案的分享,不涉及具体的实现。

收集

第 N 代收集程序

收集程序迭代了超多个版本,在过滤器、存储方式、TCP流重组等等方面都做过不同的尝试,但不变的是 pf_ringgopacket 的组合。

在不断变化的收集目标中,曾对过滤器、存储格式提出了若干要求,比如:

  • 过滤出来符合某个 host 列表中的流量的请求条目元信息(请求方法、请求头等,无需重组TCP流)
  • 过滤出 URL 符合某个 pattern 的流量的请求、响应的全部内容(头信息、body信息等,需重组TCP流)
  • 过滤出来 Content-Type 是 *** 的流量条目的 body 内容(需重组TCP流)
  • .....

之前的策略是来一个需求就修改一下程序,当所需要尝试的需求比较少时,还可以愉快的收集和分析。当需求日渐复杂,面对不同程序的存储格式不尽相同(有的只需要存储头信息、有的还有存储 TCP 流),分析脚本写起来就日渐头大。

最后,在众多方案的取舍权衡中,最终版本收集程序会具有以下功能:

  • 使用 BPF 过滤出来往于 80 端口的流量,通过重组 TCP 片段还原 所有 TCP 流。
  • 解析并记录 HTTP 请求 以及 响应的全部元信息(头信息、URI、请求方法、响应码)和文本类型的 Body 信息 ( content-type = text/* , application/json )

在开发时间和运行效率之间的利弊权衡中,选择了节约开发时间,毕竟就我一个人的在写代码 😭

重组并还原所有 TCP 流,代价是很高的。

  • 受限于流量收集服务器的网卡上限带宽小于实际网络接入带宽,丢包是避免不了的,就会导致某些 TCP 流根本无法还原,而程序还以为在未来的某些时刻那些包接收进来,占用内存无法回收。
  • 一次 HTTP 请求&响应 其实是两个流(一个发送、一个接收),而 HTTP 1.1 中建立一次链接是可复用的,也就是一个流中可能有多个请求或多个响应报文,这是从 TCP 流中重组 HTTP 请求&响应报文所需处理的额外复杂度。

我排查了许久,依然无法解决内存泄漏问题,眼睁睁的看着程序逐渐蚕食了服务器的内存然后被杀死了。最后,解决方式是,定时, GC,定时,重启程序。

Append-Only 最简单的记录方式

之前尝试过,写入 influx 时序数据库,但似乎有最大条目限制,放不下;尝试过写入 postgres 数据库,当数据库行数很大时,插入的耗时过长,影响收集程序;尝试过写入 ElasticSearch 但没有集群吃不消......

这里的权衡是,如果记录比较简单迅速(以日志的形式写入文件),那么查询分析的时候,就会很慢,或者分析脚本就会很难写;但如果记录的时候比较完善(比如插入数据库)那么查询的时候就会很方便(使用 SQL )。

一个能实现👆收集功能不因处理不过来丢包的程序,只能采用最简单的记录方式,写入日志文件。

并且,这里还采用了效率相对较低的 JSON 编码方式,以 newline-delimited JSON 的格式写入日志文件。

这里的权衡是,节约开发时间。毕竟需要找一个 Go 语言和 Spark 都方便处理的中间格式( 为什么要让 Spark 方便处理后面讲 ),虽然这里 Go 语言结构体编码为 JSON 格式使用了反射,很慢很低效,但事实证明,这样的方案是可行的,可以实现上面的收集功能,这就足够了。

分析

收集不是目的,存储也不是目的,验证一些有意思的想法💡,分析出来一些有趣的结论,才是目的。

python 脚本

在之前作 Prefetch & Cache 的时候,大量地使用 Python 脚本做数据分析,当时经常性的晚上开始跑脚本,早上起来看结论。

其弊端很明显,无法简易的利用多个 CPU 核心作分析,同时 Python 解释型执行、同步工作的特性,也不适用于 CPU 密集的任务。

spark

Spark 一般用于集群上,但其实单机使用也很不错,用户仅需要描述运算的逻辑,然后交给 Spark 进行并行计算,便可得到结果。

  • 简单分析 Spark SQL

    Spark SQL 简直是生产力,大部分验证性质的分析写一个 SQL 查询就能验证是否不可行了,如果 SQL 查询的结果符合预期,可以使用 Scala 写比较复杂的分析程序,进一步验证。

  • 复杂分析 Dataframe & RDD

行存储 → 列存储

要想 Spark 跑得快,就得转换一下存储的方式。为什么列存储更合适分析呢 👇

之所以要使用 JSON lines 存储日志记录,方便 Spark 读取,是因为 行存储 -> 列存储 的转换脚本是使用 Scala + Spark 写的。核心很简单,但实现起来也需要诸多考量 ( NullPointerException 😭 ) ,甚是复杂。

Zepplin

Zepplin 可以称为是为 Spark Scala Script 准备的 jupyter notebook。用起来的画面 👇

比如想看看谁最喜欢给拼多多做广告呢?

下一步

打算尝试一下这个 JB 家的这个工具,看起来很有吸引力呢。毕竟 Zepplin 的补全太菜了,也没有语法错误检测,并且 Scala 的语法特性过于丰富,提交执行代码块的时候才发现自己写错了。

打算逐步把各个部分的工具代码整理一下开源出来,再写一些文字 😁

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×