Page 85 - 《软件学报》2021年第5期
P. 85

尤勇  等:一种监控系统的链路跟踪型日志数据的存储设计                                                     1309


                 中被监控集群中的第 1 台机器的日志指定上报到存储集群中的第 1 台机器上.对于大量微服务运行的情况,由
                 于扩缩容、资源利用等因素,导致某个微服务实例在不同时间点上分配了相同 ip,而实际运行的机器已经发生
                 了改变,对于此类基础设施方面的变动,同样会被记录在路由信息中,即,同样能够使用 id 根据路由信息找到微
                 服务实例变化之前该 id 所对应的文件存放机器.
                 3.1.2    存储集群
                    在日志存储集群的机器上,针对上报的日志信息生成对应的数据文件与索引文件,以小时粒度分别进行存
                 储,即,把 1 个小时内所有来自某个指定应用服务的所有机器的日志数据存储在同一组数据文件、索引文件中.
                 总的来说,则是将日志存储成文件后,通过多级文件夹路径、文件名来区分日志数据源.
                    •   一级路径:日期,标识不同年月日的日志数据.
                    •   二级路径:小时,标识在哪 1 个小时内的日志数据.
                    •   文件名,标识应用名.
                    反过来,在知道某个 LogView 的 id 时,根据第 1.2.2 节中介绍的 id 设计,可以从以下几个步骤定位到具体的
                 数据文件与日志文件.
                    (1)  根据 id 值获取到被监控机器 ip.
                    (2)  根据 ip 与路由信息得知该条日志具体上报到了日志存储集群的哪一台机器上.
                    (3)  由 id 值解析出该条日志对应的文件的文件路径、文件名.
                    (4)  读取索引文件与数据文件解析真实的日志数据.
                    当前,采用配置路由信息的方式指定日志数据应该上报的对应机器,设计思路更易理解、实现也更便捷,只
                 需要拉取一次路由信息即可.相对于直接使用 HDFS 技术搭建分布式文件系统,查询性能显著优于 HDFS 集群,
                 但是固定的配置信息也存在局限性:存在某些机器的负载会很高、某些会很低的情形,会导致存储集群的整体
                 性能并不稳定,可以通过周期性修改路由信息的方式(负载均衡)使得存储集群的性能更加稳定.

                 3.2   日志写入设计
                    日志在写入磁盘时,按照不同应用、不同小时存储成对应的一组日志文件,分成数据文件与索引文件:数据
                 文件({domain}-{ip}.dat)用于存储日志数据,索引文件({domain}-{ip}.idx)用于记录每条 LogView 在数据文件中
                 的位置信息(磁盘地址).
                    在往数据文件中写入数据时,针对海量的上报日志,采取批处理的方式能够大幅减少磁盘的 IO 操作,有效
                 地提高存储效率.所以存储方案设计了“内存块”模式,以块为单位进行磁盘 IO 操作.此外,采用了当前主流的
                 Snappy 压缩算法,将原始日志数据压缩成字节数据再存储到数据文件中,能够节省较多的磁盘空间.
                 3.2.1    内存块
                    创建数据文件后,在往文件中写入 LogView 数据时,为了减少磁盘的 IO 操作,会在内存中维护一定大小的
                 块,将每一条 LogView 的数据压缩后添加到内存块中.当内存块满后,会自动扩容内存块大小,然后将内存块持久
                 化到文件中.在实际中,该内存块大小设置为 256KB,因为 32 位和 64 位的系统的页大小为 4K,8K,取两个数的倍
                 数较好.一方面,为了尽可能减少磁盘写入次数,块的设置越大越好;另一方面,为了兼顾内存容量以及数据丢失
                 的风险,内存块的设置不宜过大.之后,基于真实环境的多次实验与 LogView 的数据特征,确定了 256KB 更合适.
                    每条 LogView 的字节量大小不一致,所以在对一条 LogView 使用压缩算法压缩后,需要记录字节量的大小
                 logSize,并且在添加到内存块中时,需要首先添加 logSize 值到内存块中,设计使用 4 字节空间存储 logSize 值.在
                 内存块将写入数据文件时,同样也需要添加内存块实际的字节量大小 blockSize 到数据文件中,并且需要记录下
                 该条日志在块中的偏移量 offset.如果添加最新的 LogView 后数据块大小大于 256KB,内存块会自动扩充到容纳
                 下当前 LogView 的大小,并在此时将内存块所有数据写入数据文件中.内存块中包含多条日志压缩后的数据以
                 及对应的 logSize、内存块大小 blockSize 这 3 类数据,并且在内存块写入数据文件后,需要记录下内存块在数据
                 文件中的首地址 headAddress.如图 5 所示,内存块字节量大小(blockSize)、日志字节量大小(logSize)与 LogView
                 日志压缩数据这 3 种数据会写入数据文件中,而内存块首地址(headAddress)、日志偏移量(offset)会与 id 值通过
   80   81   82   83   84   85   86   87   88   89   90