LSM Tree/MemTable/SSTable基本原理

LSM Tree/MemTable/SSTable基本原理

时光飞逝,截至今天,2018的进度条已经毫不留情的燃烧掉了8.5%。

2017接触了很多新事物,也实践和落地了一些有意思的技术、产品和框架。要想走得快,一个人走,要想走得远,得学会多回头看,多总结。这也是接下来一系列文章的初衷。当然,前提是自己能够坚持写下去,?

是为记。


背景

2017年,做调用链服务的时候,为了存储整个系统的调用事件数据,遇到了一个存储上的问题:数据每天的写入量大概在10亿级别,也就是1.1w rps(record per second), 加上高峰期流量波动和系统冗余,我们把及格线定为3w rps。这是一个典型的写多读少的场景,自然直接放弃了关系型数据库;同时考虑到写入的时序特性,选型基本锁定到基于LSM Tree为存储引擎的数据库上。挑战依然在,但是基于LSM Tree的数据库一大把(HBase, Cassandra, RockDB, LevelDB, SQLite…),解决问题无非是时间问题。

我们先尝试了ssdb,号称可以替代redis, 一些指标上快过redis. 结果被坑得体无完肤:

  1. key不支持过期(2017.04);
  2. 写入性能压测只有2w qps,如果数据记录增大,性能迅速下降;
  3. 翻了下代码实现,虽然很失望,但是感觉因此避开了一个定时炸弹而庆幸?

在同事推荐下,我们尝试了Cassandra. 虽然国内用得不多,但是在《微服务架构》中,看到了奈飞(Netflix)的大规模使用案例,信心还是有的。实际压测结果:单节点写入性能在8w qps,超出预期。此外,系统上线后,同事花了大量时间调优参数,目前线上的单节点性能应该远超8w qps.

基本概念

LSM Tree (Log-structured merge-tree) :这个名称挺容易让人困惑的,因为你看任何一个介绍LSM Tree的文章很难直接将之与树对应起来。事实上,它只是一种分层的组织数据的结构,具体到实际实现上,就是一些按照逻辑分层的有序文件。

MemTable: LSM Tree的树节点可以分为两种,保存在内存中的称之为MemTable, 保存在磁盘上的称之为SSTable. 严格讲,MemTable与SSTable还有很多细节区别,这里不展开讨论。

基本原理

  • 写操作直接作用于MemTable, 因此写入性能接近写内存。
  • 每层SSTable文件到达一定条件后,进行合并操作,然后放置到更高层。合并操作在实现上一般是策略驱动、可插件化的。比如Cassandra的合并策略可以选择SizeTieredCompactionStrategyLeveledCompactionStrategy.

  • Level 0可以认为是MemTable的文件映射内存, 因此每个Level 0的SSTable之间的key range可能会有重叠。其他Level的SSTable key range不存在重叠。
  • Level 0的写入是简单的创建-->顺序写流程,因此理论上,写磁盘的速度可以接近磁盘的理论速度。

  • SSTable合并类似于简单的归并排序:根据key值确定要merge的文件,然后进行合并。因此,合并一个文件到更高层,可能会需要写多个文件。存在一定程度的写放大。是非常昂贵的I/O操作行为。Cassandra除了提供策略进行合并文件的选择,还提供了合并时I/O的限制,以期减少合并操作对上层业务的影响。

  • 读操作优先判断key是否在MemTable, 如果不在的话,则把覆盖该key range的所有SSTable都查找一遍。简单,但是低效。因此,在工程实现上,一般会为SSTable加入索引。可以是一个key-offset索引(类似于kafka的index文件),也可以是布隆过滤器(Bloom Filter)。布隆过滤器有一个特性:如果bloom说一个key不存在,就一定不存在,而当bloom说一个key存在于这个文件,可能是不存在的。实现层面上,布隆过滤器就是key--比特位的映射。理想情况下,当然是一个key对应一个比特实现全映射,但是太消耗内存。因此,一般通过控制假阳性概率来节约内存,代价是牺牲了一定的读性能。对于我们的应用场景,我们将该概率从0.99降低到0.8,布隆过滤器的内存消耗从2GB+下降到了300MB,数据读取速度有所降低,但在感知层面可忽略。

Q&A

  • 基于LSM Tree存储引擎的数据适用于哪些场景?

    (key or key-range), 且key/key-range整体大致有序。

  • LSM Tree自从Google BigTable问世后,如此牛x, 为什么没有替代B Tree呀?

    LSM Tree本质上也是一种二分查找的思想,只是这种二分局限在key的大致有序这个假设上,并充分利用了磁盘顺序写的性能,但是普适性一般。B Tree对于写多读少的场景,大部分代价开销在Tree的维护上,但是具有更强的普适性。

  • 看起来,你们已经将Cassandra玩得很溜了,你们线上用了多大集群支持当前业务?

    其实……还可以吧,主要是队友给力。还有就是国外有独角兽奈飞领头,遇到问题其实还是容易解决的。我们目前线上用了3*(4 core, 16G), 系统冗余还很大。最近奈飞出了一篇关于Cassandra优化的深度博文,如果有对Cassandra有兴趣,可以阅读Scaling Time Series Data Storage.

扩展阅读

IM/XMPP服务器选型

一、IM协议选型


IM协议按照是否公开可以分为私有协议(腾讯QQ)和开放协议(GTalk)。私有IM协议需要从零开始设计和搭建,时间和财力成本极高。而开放协议:1)经过业界的长期研究和验证,在安全性、完备性容、容错性等诸多方面都有保障。2)由于其开放的特性,业界已经有很多优秀的开源IM Server和IM Client,直接基于这些开源组件进行开发,可以在相对短的时间内快速搭建高质量的Chat基础服务。3)开放协议一般具有较高的可扩展性,可以进行协议的扩展和改造,以适应特殊的应用场景和需求。


目前主流的IM协议有XMPP (Extensible Messaging and Presence Protocol), SIMPLE(session initiation protocol for instant messaging and presence leveraging extensions), IMPP (Instant Messaging and Presence Protocol).


IMPP主要定义了必要的协议和数据格式,用来构建一个具有空间接收、发布能力的即时信息系统。到目前为止,这个组织已经出版了三个草案RFC,但主要的有两个:一个是针对站点空间和即时通讯模型的(RFC 2778);另一个是针对即时通讯/空间协议需求条件的(RFC2779)。RFC2778是一个资料性质的草案,定义了所有presence和IM服务的原理。RFC2779定义了IMPP的最小需求条件。另外,这个草案还就presence服务定义了一些条款,如运行的命令、信息的格式,以及presence服务器如何把presence的状态变化通知给客户。


SIMPLE计划利用SIP来发送presence信息。SIP是IETF中为终端制定的协议。SIP一般考虑用在建立语音通话中,一旦连接以后,依靠如实时协议(RTP)来进行实际上的语音发送。但SIP不仅仅能被用在语音中,也可以用于视频。SIMPLE被定义为建立一个IM进程的方法。SIMPLE在2002年夏季得到额外的信任,目前,微软和IBM都致力于在它们的即时通讯系统中实现这个协议。 SIMPLE小组致力于进程模式的操作,这将提升运行效率,使基于SIP的机制能够进行会议和三方电话交谈控制,也考虑到能和未来提供的许多新特性实现兼容并提升表现能力。有了进程模式,SIMPLE使用SIP来建立一次进程,再利用SDP(进程描述协议)来实际传输IM数据。


XMPP是基于可扩展标记语言(XML)的协议,它用于即时消息(IM)以及在线现场探测。这个协议可能最终允许因特网用户向因特网上的其他任何人发送即时消息,即使其操作系统和浏览器不同。它继承了在XML环境中灵活的发展性。因此,基于XMPP的应用具有超强的可扩展性。经过扩展以后的XMPP可以通过发送扩展的信息来处理用户的需求,以及在XMPP的顶端建立如内容发布系统和基于地址的服务等应用程序。而且,XMPP包含了针对服务器端的软件协议,使之能与另一个服务器进行通话,这使得开发者更容易建立客户应用程序或给一个配好系统添加功能。


XMPP应用广泛,国内外已有众多大规模的应用案例,参见表1。基本上,除了商业公司私有化的聊天协议,XMPP已经成为事实上的标准IM协议。


表1 XMPP应用一览表

公司

产品

Google

Hangouts (前身是GTalk)

Apple

Apple Push Notification Service

iMessage

WhatsApp Inc

WhatsApp (customized)

腾讯

微信 (参考XMPP+ActiveSync)

小米

米聊

深圳市和讯华谷

极光推送

环信

环信


基于XMPP的方案拥有大量的Server端、Client端以及类库实现,可以快速搭建满足业务需求的应用。


XMPP去中心化的设计具有天生的scale out扩展性,同时支持server-2-server通信,可以与其他XMPP服务器进行连接,实现帐号的跨域聊天。XMPP的这种特性非常适合应用于提供IM基础服务的平台。


综上所诉,XMPP是以上几个协议中最完善、可扩展性最好、应用最广、组件支持最多的一个协议。因此,Chat Service选用XMPP作为Chat Service的IM协议。


二、XMPP Server选型


XMPP Server拥有众多的实现方案,参见表2.


表2 XMPP Server实现方案


Name

Platform(s)

License

Details

Latest Release

Apache Vysper

Windows / Linux

Apache License Version 2.0

mina.apache.org

2011-02-23

Citadel

Linux

GPL3

citadel.org

2013-08-14

CommuniGate Pro

Linux / Mac OS X / Windows

Commercial

communigate.com

2013-09-10

Coversant SoapBox Server

Windows

Commercial

coversant.com

unknown

djabberd

Linux

GPL3

danga.com

2011-06-13

ejabberd

Linux / Mac OS X / Solaris / Windows

GPL2

process-one.net

2013-06-28

IceWarp

Linux / Windows

Commercial

icewarp.com

2012-12-11

iChat Server

Mac OS X

Commercial

apple.com

2012-07-25

in.jabberd

Linux

GPL2

inetdxtra.sourceforge.net

2013-05-16

Isode M-Link

Linux / Solaris / Windows

Commercial

isode.com

2013-06-24

jabberd 1.x

Linux

GPL2

jabberd.org

2012-06-28

jabberd 2.x

Linux / Solaris / Windows

GPL2

jabberd2.org

2012-08-26

Jabber XCP

Linux / Solaris / Windows

Commercial

cisco.com

2008-10-31

Jerry Messenger

Linux / Windows

Commercial

j-livesupport.com

unknown

Kwickserver

Windows

GPL

kwickserver.info

2010-10-15

Metronome IM

Linux / Mac OS X

ISC/MIT

lightwitch.org/metronome

2013-10-02

MongooseIM

Linux / Mac OS X

GPL2

erlang-solutions.com

2013-05-23

Openfire

Linux / Mac OS X / Solaris / Windows

Apache

igniterealtime.org

2013-05-28

Oracle Communications Instant Messaging Server

Linux / Solaris / Windows

Commercial

oracle.com

2013-05-07

Prosody IM

Linux / Mac OS X / Windows

MIT/X11

prosody.im

2013-09-10

psyced

Linux / Mac OS X / Windows

GPL2

psyced.org

2011-11-22

Siemens OpenScape

Linux

Commercial

siemens-enterprise.com

2011-12-15

Tigase

Linux / Solaris / Mac OS X / Windows

AGPL

tigase.org

2013-04-24

Vines

Linux / Mac OS X

MIT

getvines.com

2013-06-22

Wokkel

Linux / Solaris / Mac OS X

MIT

wokkel.ik.nu

2013-01-12

其中,较为成熟,且使用广泛的是ejabberd, jabberd 2.x, Openfire, Tigase(蓝底标出). 这几个Server的详细比较可以参考这两篇文章:Choosing An XMPP Server, Android Push 开源方案解析. 以上两篇文章的结论如下:

  1. Jabberd 2.x 使用C语言实现,但是,存在着数据库事务的滥用、内存泄露、不一致的非阻塞设计等问题,最重要的是该server已经很长时间没有人维护;因此,chesspark在使用jabberd 2.x三年后,转用ejabberd。无独有偶,Jabber.org也在2010年淘汰Jabberd, 转为使用ejabberd.

  2. Openfire以及Tigase都是基于JAVA的解决方案。但是极光推送团队认为,Openfire单机并发很有限,集群方案不成熟,代码古老而缺乏及时更新,因此不适合应用在生产环境中。因此,极光团队在初期使用Tigase解决方案。但是在使用中发现,Tigase其集群方案实现复杂,单节点容量有限,后期转为自己开发server.


从编程语言角度看,主流的XMPP Server主要是JAVA和Erlang。JAVA语言的优势是类库完备,容易招人。Erlang的优势是hot code swap, live console, 高并发. ejabberd与Openfire/Tigase比较而言,最大的优势是相对优雅的集群方案以及更高的并发性能。在没有语言偏向性的情况下,一般在开发初期都会选用ejabberd, 如WhatsApp, Facebook Chat, 米聊


从各种XMPP Server支持的特性看,ejabberd是对XMPP协议支持最好、实现最为全面的server.


从开源协议看,Tigase采用AGPL开源协议,因此只要有代码修改,就必须对代码进行开源。Openfire采用Apache开源协议,修改代码后可以闭源。ejabberd采用GPL v2开源协议,如果只在服务端提供服务,而不进行代码二次分发,修改代码以后也可以「闭源」,参考


综合以上各因素,Chat Service采用ejabberd作为初期的XMPP Server.

WhatsApp 公开源代码: http://www.whatsapp.com/opensource/

Chat Secure: https://chatsecure.org/blog/

Public XMPP Server列表:https://xmpp.net/directory.php

可以查看这些server的状态及基本信息(实现方式、认证方式等)。

「Thinking Clearly about Performance」阅读笔记

在国内,不知道有多少软件工程师在讨论问题的时候口口声声把性能挂在嘴边,但是到实际设计、编码和运营阶段,却完全将性能抛在了九霄云外。2011年京东促销,网站一度崩溃,东哥直接扔出一句“增加三陪服务器,活动重搞一次”。在引起广大程序员一片欢声笑语的同时,也揭示了天朝在“性能”上普遍存在的问题:并不持续的关注性能,直到出了问题的时候才进行补救。“安全”问题在国内的现状也类似。

缺乏系统性“性能”的关注与对这个概念的认知不清晰不无关系。Cary Millsap主题为Thinking Clearly about Performance的文稿对这一概念驾重就轻,信手拈来,真正做到了深入浅出。其中词汇部分的解释简洁准确,是这个文稿的一大亮点,值得细细品味。

关键点笔记

  1. Performance is an attribute of each individual experience with a system.
  2. 性能只需要关注两个点:吞吐量(throughput)和响应时间(response time)。
  3. 两幅图形象说明什么是性能
    Thouhgput responsetime 1
    Thouhgput responsetime 2
  4. 性能的衡量应该是具体而精确,否则你就是使用了错误的衡量指标。
  5. 序列图理流程,profile看数据,分析系统性能目标是否可行,以及哪些地方是系统的瓶颈。
  6. 把系统最繁忙的资源当做系统瓶颈往往是不可取的。不同的任务/应用,瓶颈也会各不相同。
  7. 明确你的knee在什么位置,据此设计系统容量和在随机访问情况下的knee负载。
  8. 性能优化就是与三座大山死磕:inefficiencies, queueing delays, coherency delays.
  9. 三座大山是永远无法夷为平地的,但是只要持续尝试,会发现越来越多可持续改进的点。
  10. 性能是一个特性,应该从一开始就有所考虑:

The software designer who integrates performance measurement into his product is much more likely to create a fast application and—more importantly —an application that will become faster over time.
—Cary Millsap