在之前的文章《日志服务(原sls)新功能发布(1)--支持保序写入和消费》中,我们提到了shard支持key映射的特性,通过这个特性能够支持对序有需求的应用场景。今天我们给大家介绍一个在削峰填谷或流量突增情况下的功能:弹性伸缩。在生产中我们往往会面临峰值和低值的情况,也会遇到因业务层映射不均衡,导致某一个分区(shard)有非常大流量的场景,弹性伸缩(merge/split)就是为此设计的利器。
用户a是一个视频类网站,晚8点-22点是一天的高峰,会产生大量的点击和访问日志。小a使用日志服务一个logstore进行点击日志收集与消费。
在白天时使用一个shard(shard0)分区(写5mb/s、读10mb/s)
当晚间高峰时对该分区进行分裂(split),分区变为2个分区shard1,shard2服务能力(写10mb/s,读20mb/s)
当高峰期过后,通过合并(merge)将两个分区调整一个分区的服务能力(shard3),以控制成本
用户b是一位程序员,通过日志服务logstore采集数据库节点日志。小b管理的数据库有大有小,大的每分钟产生1mb/s 数据,小的也就0.5 kb。由于数据库日志是需要保序处理的,因此小b通过hash方式将各数据库映射到唯一的shard上,在消费时保证保序列。
根据映射规则,db1-db3被 hash到 shard1上,db4-5被映射到shard2,相安无事
有一天数据库实例db2, db3流量突然产生的变化,突破了shard1处理能力(写5mb/s,读10mb/s)
小b通过分析,决定把db2,db3进行拆分,于是根据映射hash方式调整了shard1,变成2个新的shard(shard3, shard4),shard3 服务db1,db3, shard4 服务db2,流量终于均衡了
值得一提的是,伸缩操作都是ms级完成,并且过程是对用户服务是没有任何影响。
logstore下分为若干个分区,每个分区由两个md5组成的左闭右开的区间组成,每个区间的范围不会相互覆盖,并且所有的区间的范围合并起来就是md5的整个取值范围。logstore的日志必定保存在某一个分区上。
以图为例,为了简化说明,这里假设md5的取值范围是00 到ff。这个logstore共有4个分区,范围分别是[00,40),[40,80),[80,c0),[c0,ff)。当写入日志时,用户指定一个md5的key是5f,那么这个请求会落在第1号分区上;如果用户指定md5是8c,那么该请求的数据会落到第2号shard上。
分区的状态有两种,一种是readwrite,可以读写;另一种是readonly,只能读数据,不能写数据。
分区的范围如何划分。创建logstore时,指定分区个数,会自动平均划分整个md5的范围。之后可以通过分裂和合并操作来扩容和缩容分区个数。
根据logstore实际的流量,每个分区能够处理5m/s的写数据,和10m/s的读数据。根据流量计算出来需要多少个分区。
当写入的api持续报错403或者500错误时,通过logstore云监控查看流量,判断是否需要增加分区。
当流量变小时,为了节约企业成本,可以通过合并操作减少分区。
分裂操作是把一个readwrite的分区分裂成两个readwrite的分区,同时自己变成readonly的分区。分裂操作是扩容logstore流量的手段。
以图为例,1号分区原来的范围是[40,80),指定以60为分界点,把整个范围分成了两份[40,60),[60,80),形成两个新的分区4号分区和5号分区。1号分区变成红色的readonly状态。 在分裂之前写到1号分区上的数据仍然留在1号分区上可供读取,分裂完成后,1号分区不再接收数据,落到40到80之间的数据会选择性的落到4号分区或者5号分区,比如5f这个md5,会写入到4号分区上。
合并操作和分裂操作相反,是把两个相邻的readwrite的分区合并成一个readwrite分区,同时原来的两个分区变成readonly状态。
通过api或sdk:split, merge
通过管理控制台
对上游没有任何影响,透明
对下游消费者而言需要感知shard数目变化,我们推荐使用我们提供storm spout,spark stream library或client library(java、python等用户),client library会根据消费实例数目与shard数目做负载均衡,过程不丢不重数据