疫情之下:大数据的洞察力
|
RocksDB 和 Cassandra 等数据库都使用 LSM 树,而 MongoDB 以及其他的数据库都会使用 B 树和它的变种。虽然这两者设计在过去都有着优异的表现,不过这两种设计在 NVMe SSD 这种较新的硬件上表现地并不好,CPU 成为了瓶颈并导致严重的性能波动。 LSM 树
LSM 树是为写密集型负载特别优化的数据结构,在 LSM 树中,我们使用内存缓存接收所有的写操作并将变更批量写入磁盘,内存缓存中的数据会被后台线程合并到持久存储里的树形结构中。 磁盘性能和特性的演进使得在过去很多键值存储成立的设计变得无效,例如:随机 I/O 的速度远远慢于顺序 I/O,很多数据库为了减少随机 I/O 的次数会使用特定的数据结构并牺牲一些 CPU 计算资源,但是在最新的硬件上已经没有太多的必要了。 KVell 的论文中不止提到了目前主流键值存储在新存储设备上各种问题,还给出了最新的设计原则、实现方式以及对性能的评估。我们在这里不会面面俱到的介绍论文中全部的内容,主要会分析主流键值存储的问题以及最新的设计原则,其余的内容各位读者可以在论文中自行探索。 实现问题 目前的大多数的键值存储系统都会使用 LSM 树或者 B 树作为主要的数据结构存储数据,这两种不同的数据结构适合用于不同类型的工作负载: LSM 树:适合写密集型的负载;
B 树:适合读密集型的负载; 在消息被消费之前的前半部分流程中,生产者可以利用唯一的消息id和ACK机制来做消息被重复投递的保证工作,但是这样会大大降低生产者业务的性能,一般情况下生产者都需要异步的来发送MQ消息,如果在发送的时候还需要检查消息是否被发送过,这无疑不是一个好的设计,而且你这样做的检查效果,只为命中很渺小的一部分数据,得不偿失,所以在生产者很少有人主动去做消息的重复投递检查工作。 至于在MQ的内部,有的MQ确实会提供幂等性的存储设计,比如Kafka引入了Producer ID(即PID)和Sequence Number。
Broker端在缓存中保存了这seqnumber,对于接收的每条消息,如果其序号比Broker缓存中序号大于1则接受它,否则将其丢弃。这样就可以实现了消息重复提交了。但是,只能保证单个Producer对于同一个的Exactly Once语义。不能保证同一个Producer一个topic不同的partion幂等。 然而这些都不是我们今天要说的重点,实际的业务中,消息的幂等性消费也更倾向于在消费端做,在消息的终点彻底解决问题,无论是在系统设计,还是在可扩展性上无疑都是最好的。 刚才也提到,消息既然要做到幂等性消费,必须要提供一个用于判断重复的标识,可以是自定义的消息ID,也可以是消息中几个字段联合起来的类似数据表中的主键,目前主流的做法是在生产方根据业务特点生成消息id,例如:给用户添加因为下单而赠送积分的消息id,就可以根据userid_orderId_积分数量来生成唯一的消息id。
有了唯一的消息id,消费者就可以把已经消费的消息id,本地存储下来用于过滤重复消息,当然如果数据量比较大的话,很早之前的历史数据完全可以删除或者转移到其他的备份表,毕竟同一个消息不可能过了很长时间再次被投递。以下是一个本地消息表的例子: (编辑:淮南站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |


