客端日志的收集、存储和分析(一)

5,470 阅读7分钟

前言

客端用户行为日志向来以量大著称,每日几亿,几十亿甚至几百亿也是司空见惯,谈到客端日志的收集,就需要谈到日志收集的时效性和准确性两个课题。对于海量日志数据的存储,常见的hadoop体系和最近流行起来的ClickHouse都是不错的选择,其中的优缺点也是我们讨论的重点。对于海量数据的分析更是一个永恒的话题,在这方面,ClickHouse似乎给出了近乎完美的方案,但是事实是,如果你想在项目中使用它,那对它特点的全面了解,是实现目标的大前提。在接下来的文章中,我们来一起学习下这方面的课题。


一、如何做到海量日志的快速收集

想实现海量数据的快速存储,首先要解决高并发,高吞吐量情况下,数据的落地;在这方面,Nginx是最好的选择。主流配置的服务器单台Nginx处理能力就能轻松达到达到10000+/s;按照这样的处理能力,单台服务器单日可处理: 3600s24h10000 = 将近10亿数据。之后的处理还需要用到什么技术,下面我们来具体分析。

1.架构分析

在这里插入图片描述

2. Nginx能做什么

——反向代理

——负载均衡

——HTTP服务器(动静分离)

——正向代理 这些是他的主流作用,在日志收集中,我们能用它来做什么呢?

答案是:缓存数据文件。 只要经过简单的配置,就可以将接口中传入的数据以文件的形式落地到服务器的磁盘上,在加上Nginx本身的高处理能力,我们就很轻松的完成了海量日志收集的第一步。

3. Nginx落地的文件我们怎么处理

现在的互联网技术中,谈到大数据很难不谈到kafka,在数据进入到kafka之后,我们对数据的处理就变成了顺利成章的事情。在这里,我们借助著名的FileBeta,将Nginx收集到的数据文件中的数据准实时的发送至kafka。接下来的方案似乎都变得顺利起来了。

二、ClickHouse在数据存储中的应用

1. ClickHouse数据写入

1.MergeTree 表引擎:对于这种表引擎,是ClickHouse最强大的表引擎,没有之一。但是它并不是一个单独的个体,它是一个系列。被称为MergeTree系列。

2.MergeTree表引擎特点

MergeTree 引擎系列的基本理念:

(1)批量写入。

(2)数据片段在后台按照一定规则合并。

主要特点:

(1)存储的数据按主键排序。

(2)自动创建快速检索数据的稀疏索引。

(3)允许分区(需要指定了分区键)。

(4)在相同数据集和相同结果集的情况下 ClickHouse 中某些带分区的操作会比普通操作更快。

(5)查询中指定了分区键时 ClickHouse 会自动截取分区数据,增加了查询性能。

针对这些特点,我们清晰的知道在存储数据时,需要批量写入,那每次写入多少合适:答案是越多越好吗?这又是为什么呢?

Clickhouse支持查询(select)和增加(insert),但是不直接支持更新(update)和删除(delete)。

插入:MergeTree不是LSM树,因为它不包含“memtable”和“log”:插入的数据直接写入文件系统。这使得它仅适用于批量插入数据,而不是非常频繁地插入单行; 每秒一次插入很好,但是每秒一千次不行。如果有大量内容想要插入,可以使用Buffer引擎,Buffer引擎做的是把缓冲数据写入RAM,定期将其刷新到另一个表。

所以我们每次插入多少合适呢,这取决于我们每秒钟生产多少数据,对于ClickHouse而言,我们不能频繁的进行写入操作就可以有效的提高ClickHouse的性能。

例如我们每秒钟要生产10万条数据,那我们就把它一次性插入就对了。如果我们每秒钟只生产一条数据(那我们可能就不需要ClickHouse了。。。(: !)

2. ClickHouse数据更新

上小结我们明确表示ClickHouse的MergeTree表引擎不支持更新,那我们确实有更新的需求应该怎么办呢?

1. Clickhouse通过ALTER的变种实现了UPDATE和DELETE。

Mutations(突变)是一种ALTER查询变体,允许更改或删除表中的行。突变适用于更改表中许多行的操作(单行操作也是可以的)。

该功能处于测试阶段,从1.1.54388版本开始提供。 Mutations的更新功能是版本18.12.14开始提供的,目前MergeTree引擎支持Mutations。 现有表已准备好按原样进行突变(无需转换),但在将第一个突变应用于表后,其元数据格式将与先前的服务器版本不兼容,并且回退到先前版本变得不可能。

命令如下: ALTER TABLE [db.]table DELETE WHERE filter_expr;

ALTER TABLE [db.]table UPDATE column1 = expr1 [, …] WHERE filter_expr;

注意:更新功能不支持更新有关主键或分区键的列。

对于 MergeTree表,通过重写整个数据部分来执行突变。此操作没有原子性 , 一旦完成准备就会替换突变部分,并且在突变开始执行后,SELECT的查询将看到来自已经突变的部分的数据以及尚未突变的部分的数据。 突变按其创建顺序排序,并按顺序应用于每个部分。

INSERT也部分地进行了突变 - 在提交突变之前插入表中的数据将被突变,之后插入的数据将不会被突变。请注意,突变不会以任何方式阻止INSERT。

突变本身使用系统配置文件设置异步执行。要跟踪突变的进度,您可以使用system.mutations表。即使ClickHouse服务器重新启动,成功提交的突变也将继续执行。一旦提交突变,就无法回滚突变,但如果突变由于某种原因而被卡住,则可以通过KILL MUTATION取消突变。

已完成突变的条目不会立即删除,保留条目的数量由finished_mutations_to_keep存储引擎参数确定。 旧的突变条目会被删除。

突变的具体实现过程是先使用where条件找到需要修改的parts(分区),然后重建每个part,用新的part替换旧的part。对于有大的part的表进行重建会很耗费时间(默认一个part最大大小为150G )。突变在每个小的part是原子性的。

对于这部分内容,不做展开介绍,因为在实际的项目中,很难用这种方式实现我们通常意义下的更新操作,因为项目中的更新时不定时的零碎的进行的,这有别于Mutations的设计原则。

2. 如果不想使用突变,毕竟突变不是原子性,而且开销较大,另外一个比较好的选择是使用ReplacingMergeTree替代MergeTree。

除了具有MergeTree本身的特点,ReplacingMergeTree最主要的特点是,可以按照主键自动清除老版本的数据,保留表中新版本的数据。这正是我们项目中更新操作得到的最终结果。

例如: (1)创建表:

CREATE TABLE event_log.users (

`id` Int64,

`first_id` String,

`second_id` String,

`insert_date` DateTime DEFAULT now()

) ENGINE = ReplacingMergeTree(insert_date)

PRIMARY KEY id

ORDER BY id

SETTINGS index_granularity = 8192;

在这个表中插入两条id 相同的数据,ClickHouse会在自动执行optimize 操作时,将按照insert_date,将先插入的一条数据清除掉,只保留后插入的数据。

(2)更新表操作:

在新的数据需要更新主键相同的旧数据时,我们首先用select 。。。where id = fix_id(固定的主键id)查询出来老的数据信息,按照新数据传入的新字段更新查询结果,并执行insert 语句。接下来等待optimize自动执行就可以了。

(3)如果需要确保查询出来的数据为新数据,可以再查询中增加 FINAL ;但是这会降低查询的效率,我们再项目应用中,可以酌情使用。

总结

我们本文章介绍了海量用户行为数据在收集和存储方面的知识,这是一个永恒的话题,数据存储是手段,目的是进行数据分析,为公司业务的运营和发展提供有力的数据支撑。那么在数据分析中,我们应该注意什么呢,在存储时如何为数据分析做充分的准备呢,在接下来的文章中,我们会继续分享。