• 如何处理单一日志文件太大不好清理的问题?
  • 发布于 1周前
  • 31 热度
    0 评论
单一的日志文件随着日志的不断增加变得异常庞大,最后会成为性能瓶颈。当然你可以说定期清理不就行了?但是对一个超大的单个文件执行清理操作在实现上较为困难。

单个日志被分割成多个片段。当日志文件达到特定大小限制时,会滚动日志文件。通过日志分割,需要有一种简便的方法来映射逻辑日志偏移量(或日志序列号)到日志分段文件上。这可以通过以下两种方式实现:
1.每个日志分段的名称由某个已知前缀和基础偏移量(或日志序列号)生成。这意味着可以通过检查日志分段的名称直接推断出它对应于哪个日志序列号。

2.每个日志序列号被拆分为两部分,一部分用于确定文件名,另一部分代表事务内部偏移量。这样,可以根据文件名部分找到相应的日志分段文件,并结合事务偏移量在该文件内定位具体的记录位置。

凭借这些信息,读取操作包含两个步骤。对于给定的偏移量(或事务 ID),首先识别出对应的日志分段,然后从该分段及其后续的所有日志分段中读取所有日志记录。

例子
Kafka
Kafka 的基本存储单元是分区副本。当创建 topic 时,Kafka 首先决定如何在代理之间分配分区,目标是将副本均匀地分散在各个代理上。

Kafka 代理会将每个分区进一步划分为多个分段(segment)。每个分段都会存储在与代理相连磁盘上的单个数据文件中。默认情况下,每个分段包含的数据量为 1GB 或者一周的数据,以最先达到的限制为准。当 Kafka 代理接收到分区的数据时,一旦达到分段的大小限制,便会关闭当前文件并开始写入新的文件。在任何时刻,只有一个分段处于活跃状态——即正在进行数据写入的那个分段。一个分段只有在其事先被关闭后才能被删除。分段的大小由两个 Broker 配置参数控制(这些参数也可以在主题级别进行修改):
log.segment.bytes:单个分段的最大大小,单位为字节(默认值为 1GB);
log.segment.ms:如果分段未满,Kafka 等待多久之后提交该分段(默认值为 1 周)。

Kafka 允许消费者从任意可用的偏移量开始获取消息。为了帮助代理快速定位给定偏移量对应的消息,Kafka 为每个分段维护了两个索引:
1.到位置索引的偏移量 - 它帮助 Kafka 了解要查找某个消息时应该读取分段的哪一部分。
2.到偏移量索引的时间戳 - 它使 Kafka 能够根据特定时间戳找到相应消息。

如前图所示,每个分片都有自己所覆盖的偏移量范围和时间戳范围。

Etcd
etcd 的 wal 文件也是分段的。基本上有一致性算法实现,诸如 Raft,都使用了日志分割技术。在 etcd 的存放 wal 文件夹中你会看到一系列文件,每个文件代表着 WAL 的一部分。这些文件捕获了 etcd 集群中交易的快照,保存了变更历史记录,如果需要的话,可以用来重建 etcd 的状态。

您可能还会注意到一个.tmp临时文件。这个临时文件在写入过程中发挥作用。当 etcd 写入条目时,首先将其写入这个临时文件中。一旦写入操作成功完成,临时文件就会被原子性地重命名,并成为 WAL 的下一个分段。通过这种方式,etcd 确保主要的 WAL 文件只包含完整且有效的条目,为防止潜在的数据损坏提供了额外的保护层。

MySQL binlog
MySQL 的二进制日志(Binary Log)是一种重要的数据库日志文件,它记录了 MySQL 数据库上所有的数据更改操作,包括数据的插入(INSERT)、更新(UPDATE)、删除(DELETE)以及 DDL(Data Definition Language,如 CREATE TABLE、ALTER TABLE 等结构变更)语句。这些更改操作按照发生的顺序被记录为一系列可读的事件,每个事件都包含了重建数据库更改所需的所有信息。

实际上,二进制日志由多个文件(分段文件)组成,如图下图所示,这些文件共同构成了二进制日志。

下面是查询 mysql 日志文件的一个例子:
master> **`SHOW BINLOG EVENTS IN 'master-bin.000042' FROM 269\G`**
*************************** 1. row ***************************
   Log_name: master-bin.000042
        Pos: 269
 Event_type: Begin_load_query
  Server_id: 1
End_log_pos: 16676
       Info: ;file_id=1;block_len=16384
*************************** 2. row ***************************
   Log_name: master-bin.000042
        Pos: 16676
 Event_type: Append_block
  Server_id: 1
End_log_pos: 33083
       Info: ;file_id=1;block_len=16384
*************************** 3. row ***************************
   Log_name: master-bin.000042
        Pos: 33083
 Event_type: Append_block
  Server_id: 1
End_log_pos: 33633
       Info: ;file_id=1;block_len=527
*************************** 4. row ***************************
   Log_name: master-bin.000042
        Pos: 33633
 Event_type: Execute_load_query
  Server_id: 1
End_log_pos: 33756
       Info: use `test`; LOAD DATA INFILE 'foo.dat' INTO...;file_id=1
4 rows in set (0.00 sec)


用户评论