日志服务在上周新上线的版本,支持数据的保序写入和消费,shard的split和merge, server端consumer group的原生支持(除去对mysql的依赖),数据自动同步至oss等一些列新功能。本文主要介绍数据的保序写入和消费的功能。
每个logstore对应一类日志,对于同一个logstore下的数据,所有处理逻辑相同(索引方式、导入odps、oss等配置)
每个logstore由一个或多个shard组成,用于支持数据写入水平扩展
每个shard提供 5mb/sec的写入和10mb/sec的读取吞吐
每个shard的属性:唯一的shard id,当前状态(只读、读写),以及一个左闭右开的区间(取值范围00000000000000000000000000000000~ffffffffffffffffffffffffffffffff,可由md5计算获得)
现在日志服务对于每个logstore,提供两种写入模式:
在这种模式下,数据写入logstore,由服务后端随机选择一个当前可用的shard写入数据。在这种模式下,数据写入有非常高的可靠性,任意的进程crash,机器宕机,只要还有一个shard正常运行,就不影响数据的写入。
写入的时候,根据需要将部分数据写入同一个shard以实现数据的保序,例如,同一个机器上的日志,写入同一个shard。
在这种模式下,通过传入的hash_key, server端会找到range包含这个key的shard,并将数据写入该shard,数据按照shard接收顺序依次写入,这样,同一个shard内的数据是有序的。使用hashkey的模式,有以下注意事项:
对于hash key的选择尽量做到均衡,避免某个shard写入数据量过大
不可以使用时间(如精确到小时)作为hash_key的计算,以防止任意时刻,只有一个shard提供服务
hash_key模式下,系统可用性没有负载均衡模式高,当出现宕机等情况,shard可能会出现短暂不可用的情况,需要在写入端进行重试等处理
使用日志服务的批量消费接口,从指定shard中批量拉取数据,数据以fifo的模式顺序读取,可以保证同一个shard内,日志数据的消费顺序和日志产生顺序相同。
单机日志保序消费。一个java应用部署在多个机器上处理用户请求,根据用户id的不同,每个用户的请求会落到特定的机器上进行处理,而对于用户的每个请求,都有如下记录:
用户id
操作类型
时间
详细信息
为了安全审计、监控等需求,需要将所有用户的操作日志保存下来,进行实时分析。同时要求分析用户操作行为是安格按照用户操作顺序进行的,即对于每个用户id产生的日志,读取顺序和日志产生顺序相同,不能发生错乱。 如某个用户依次进行了如下三个操作:
创建一个资源文件
更新该资源文件
删除资源文件
每个操作分别产生了一条日志,为了保障分析程序的正确运行,也必须依次读取创建、更新、删除操作产生的日志。
为了达到这个目的,java应用在产生日志的时候,可以将同一个机器上的日志写入到同一个shard中,这样分析从每个shard中读取的各个用户的操作日志必定和用户操作顺序完全相同。
整个java app程序日志如理逻辑设计如下:
java app内主要操作如下:
每个用户的请求,产生一条操作日志,追加到内存中的"操作日志队列"
java app后台存在一个日志发送线程,调用日志服务sdk的putlogs接口,负责将日志批量发送至日志服务,并将md5(machine_ip)作为 hash_key,确保同一个机器的日志发送至相同的shard
后台线程处于无限循环状态,空闲的时候,处于sleep状态,只要“操作日志队列" 中日志超过100条,或者已经sleep了1秒,该线程就会被唤醒,检查是否需要将队列中缓存的日志发送出去
使用保序的特性主要适用于对日志产生的先后顺序有严格依赖的场景:
用户操作行为记录日志
数据库执行query日志
单机程序打印日志
以上介绍了日志服务提供的shard保序写入和消费的特性,当单个shard写入数据超过其处理能力之后,可以通过shard的split操作来增加shard,关于shard split/merge以及其他新功能介绍,我们后续会更新至论坛。