00:11
哈喽各位啊,大家晚上好呃,欢迎非常呃感谢大家在周末还能有空来抽出时间参加咱们今天晚上举办的DB洞见直播活动,那么我呢,是今天的开场嘉宾啊,我是来自呃腾讯云数据团队的呃唐燕,那么首先我们呃先稍微测试一下咱们这个呃直播间的这个状态是否OK啊呃大家如果能嗯正常的看到我的画面和声音的话呢,麻烦在这个直播间可以扣个666。OK,好的,那看来应该呃没有什么问题,行,那我们呢,呃呃还要给大家介绍一下,我们在本期直播呢,还设置了这个呃抽奖环节,那么到我们今天晚上,我们也是为大家准备了丰厚的礼品,那我们会为中奖的同学呢,送上一套技术啊数据库相关的技术丛书,以及呢,或者说呃有可能抽中咱们腾讯啊专门出品的这个怪系和记忆优原整一个,那我们会在第一位嘉宾和第二位嘉宾啊分别分享之后呢,分别进行两轮抽奖,所以呢,在今晚的整个过程当中呢,就欢迎大家啊认真听课,并且积极提问,而且呢还要积极参与我们的抽奖,获取我们的周边礼品。
01:35
那么在呃正式开始分享之前吧,我先啊跟大家聊一聊咱们这个活动的一些大体背景吧,那呃我们其实咱们这个D建的数据库论文解读直播系列呢,已经是啊搞了好几期了,那在每一期呢,我们都会邀请一些学,或者说在腾讯的这个在工业界的一些啊技术人员来解读为大家跟一跟大家一起分享吧,就是啊嗯目前就是像呃最近的一些数据库技术,技术的创新的趋势啊,也让更多的数据库从业者了解到现在目前行业的一些前沿的技术的热点,从而呢,在大家这个数据库圈子里面形成一个呃非常的一个创新成果这么一个分享的氛围,那呃在这一期呢,我们呃将会聚焦在存储领域吧,那为什么呃会在存储领域呢?那其实嗯,数据库的基础研究吧,呃,是腾讯一直在坚持做的事情。那在我们看来,在。
02:35
数据库这个呃,非常传统的一个领域,它在经历了几十年的发展之后,其实在这个新呃,新一代的数据库,它所包含的一些主题内容,它不仅仅在啊,我们一直常说的这种Q优化呀,啊,索引结构啊等等啊这些比较局限的空间,其实发展到现在,比方说我们经常会说的云生技术啊,H啊,还有我们啊跟数据库相关的一系列的产品生态智能化,智能化管控等等,那在这个整个云时代的这个发展之下,数据库它本身这个系统技术呢,是有了一个非常大的一个跃进,它所包含的这个呃,知识的范围也越来的越广,所以呢,今天晚上呢,我们是呃。
03:25
嗯,截取了呃当中一个也是数据库这个领域内呃非常受大家关注的一个话题吧,这是跟啊存储相关的一个话题,那么今天晚上呢,我们呢是会呃我将由我和我的另外一位同事去重点去围绕就是这个呃基于msm的一个存储技术啊当前有一些怎么样的一些啊前沿的研究热点,那么我的同事呢,将会接待我之后呢,会为大家带来那腾讯TT数据库团队在目前的这个存储领域是是做了一些怎么样的工作,那OK,那在呃那我在我正式的分享开始之前吧,我还是在先,呃刚向各位刚刚进直播间的各位朋友就是在简单介绍一下自己,呃我呢是来自这个呃腾讯腾讯云啊TC数据库团队的呃唐燕,那我呢,呃呃,博士毕业于浙江大学,在博。
04:25
这期间呢,我的呃研究领域呢,主要是包括这个分布式存储以及大规模数据啊密集型相关的一些统技术,那么当前呢,我是在这个腾讯云的T数据团队,负责数据啊大规模管控相关的一些工作,那今天晚上呢,我会为大家啊就是呃带来的一个技术分享吧,是这个是2021年发表在呃数据库呃其中一个顶会之1SMO,应该也是大家非常熟悉的一个会议了,呃是发表在2021SKIMO上的一篇论文,那呃今天跟大家分享的这篇论文呢,主要是觉得它里面的一些嗯设计的理念还挺有意思的,对,而且还还是挺多挺多的一些思想,值得我们去呃一起去探究一下,那这篇论文呢,它是呃这个名字呢,是叫这个nova LM,那它是一个呃,从一个非常呃广泛的意义上来概概括呢,它是一个将传统。
05:25
的基于LM tree的结构的KB存系统呢,做成了一个分布式的,并且是做成一个组件化可动态扩展的这么一个嗯存储系统,那么今天晚上呢,我的介绍可能应该是会主要包含五个部分吧,那首先呢,我会呃跟呃大家一起去回顾一下lsm它呃是一个怎么样的一个一个就是大体的一些背景,它的一些基本概念。然后呢,在第二部分我会呃就啊这一篇论文作者所提出的整套系统,它是大体上提供了一些呃怎么样的主要的功能特性,它主要的一些设计的亮点在哪里,我会跟大家呃去逐一去介绍一下,那在第三部分呢,我我会挑一些,因为这篇论文其实也非常的长,非常的详细,那我会呃挑两到三个,我觉得就是挺有意思的,比较啊,也属于论文里面比较重要的一个啊,设计点去跟大家啊去分享展开一下。
06:25
那么在第四方面呢,在呃展示一下当前那作者做出了这个nova l SM这个分布式的一个组件化的这个系统之后啊,它所展现出来的性能效果是怎么样的?那第五部分呢,其实我觉得更重要,因为嗯,咱们是一个呃DB见嘛,就是说要洞察去看见更多的东西,那其实呃论文每一年大家都能看到非常多非常多,那别人的工作总是啊铺天盖地,数量非常多的,更重要的是我觉得我想跟大家一起探讨和分享,我们在看到别人的一些有意思的工作成果的时候,呃,联系到我们工作实际,联系到我们的工程落地,会产生一些呃怎么样的思考,对。
07:08
OK,那接下来那话不多说,我就先跟大家啊,先聊一聊l l SM tree它的一些基本的一些背景是怎么样子的吧,对,那l SM tree呢,应该呃,很多数据库的同行应该也知道它的一个全称呢,就叫做这个lock structure tree,它是一种呢,基于啊面向磁盘存储呃,设计等呃数据结构,那其实它这种结构也已经呃非常不不是一个新鲜的事儿了,他第一次提出呢,是在九六年的时候,是是这个呃,Patrick他在这个一篇期刊上发表的一篇提名,它就叫做这个呃VLSM的这一个论文,那这个lsm这个数据结构呢,它的一个由来吧,设计的一个由来就是它。因为以前数据库的这个索引基本上是采用这个B加数的方式来作为一个索引结构,那那B加数的情况下,它其实这个写性呢,就是随机写性能是会一个比呃被人扣冰稍微多一点的这么一个点,所以LM tree的一个提出呢,它主打的就是用一个将这个离散的随机写景流,呃非常巧妙的转换成这个批量的顺序写操作,那么因为在无论是在呃机械硬盘还是说在这个固态硬盘上吧,顺序的读写性永远是要明显好于这种啊随机读写的,那呃随着这种它作为LSMG作为一种非常高效的一种KV存储的结构吧,它已经是被非常多的呃业界的的系统所应用了,那其实呃我们在这个呃PPT里面所列出来的一些嗯系统,大家应该啊,里面的名字有很多的是大家非常耳熟能详的,比方说非常著名的这种啊,开源单机数据库,想来我。
08:54
BDB,那还有这种啊,比较还有呃国外的很呃也是非常热门的,像Co DB,那还有国内的像这个呃,就是一些厂商的,比如说base,还有咱们就是呃国内的也是非常优秀的这个开源数据库,呃,公司呃,创业公司泰迪B,包括咱们自己腾讯云内部P也是有基于这个lsm做底层的存储引擎去开发的这个啊分布式数据库,对。
09:24
那呃就接着讲到,因为lson tree呢,它确实是有呃比较多的一些优点,所以才会被广泛的应用到呃这么多的一些呃成熟的这些这些系统当中,那么它的一些优点呢,就包括呃其中最大点肯定是非趁的写性能,那还有呢,就是它因为呃底层会对这些呃重复的数据会进行一些呃历史版本的一些回收,所以呢,它的这个空间的这个呃利用率是非常的高的,然后呢,它会那个。呃,因为它整套体系当中呢,它会有非常多的一些,呃,非常多细节的一些参数吧,所以呢,呃,很多诶高阶的这些诶开发者也非常喜欢它,因为它的这种可可可调性非常的强,它有非常多的参数,也非常的复杂,都可以做一个专门的话题,然后呢,呃,它有很好的就是再基于这种LM,它本身就是一个对数据有多版本的一个写入,所以的话在基于lsm,然后再去做跟数据库呃密切相关的这种并发控制,还有多版本控制呢,它其实就是本身已经有一个天然的优势了。
10:36
那我们来看一下,就是在lsm的这个呃对数据的更新,其实跟这种跟呃基于B加数是有什么样的一个区别呢?那这里一个区别呢,就是呃一个非常可以,嗯比较简单的就可以理解为一个个是in place update1是out place update,那B加数的这个呃这这个更新呢,我们是称之为这个呃这个这个in place是因为呃我我比如说这里图里面展示的呃一个呃K1这个一,如果我本来一个是一个V一个,那这时候我我我像这个一是写下来了一个啊V4的,那在这个时候呢,我们是会去找到这个T1,然后呢马上将这个V4写进去的,所以呢,嗯我们可以看到在B加数的这跟种啊索引结构里面,对数据的这种啊,更新的或者插入它是一个完全只是一个会引起一个实时的一个随机IO的,所以说在毕加数的这种场景下呢。
11:36
解性能是会受到一定的影响的,但是因为毕加树它是一个啊,可以支持一个非趁的一个检索性能的,所以它的读性能是比较好的,OK,这里啊,有观众提问说啊,咱们的直播内容会不会有回放,可能我先回答一下观众吧,可能这个问题因为毕竟周六晚上大家也比较关心,那咱们的这个直播内容全程是有回放的哈,呃,不用担心,那后续的回顾呢,以及内容呢,我们会在我们的云家社区以及咱们的腾讯云数据库公众号进行发布,所以呢,也非常欢迎大家呃,关注我们的官方公众号,就是云家社区和腾讯云数据库公众号,对。
12:18
OK,那回到我们刚刚呃讲的这里,呃这个对比,那相比之下,那在LM的这个结构里面呢,如果这个时候对T呃T1进行一个V4的这么一个更新的话,我们并不会马上的把这个T1改成一个V1,而是说将它转化成一个顺序写,把它写到这个,把它写到这个啊内存里面去去啊在就是追加在这个K3V3的后面,所以的话,因为顺序写它的性能永远是比随机写要高很多的,但是呢,它我讲到后面会发现,但是呢,它这种方式的话,也是以一定的读性能去牺牲读性能以及啊空间放大来达到的。
13:01
那在九六年它刚提出的时候吧,L3去年它是呃一个非常呃原始的结构吧,这里的话就是呃在这里是展示的是一个就是它刚提出来的时候是怎么样的,它其实呃每一个更新它它到了这个就C0,我们代表是一个在内存里面的一个一个状态,然后呢,每当这个数据写入就是它会逐渐的往下emerge去,那当C1它满了的时候的II层满的时候,它就会把就是啊底下的叶子节点就是从CI到这个C的这个I加一去往往下去,那么所以呃。这里可以看到就是层数越大就表明了数据写入的是越早,那每一层呢,它其实当时呃最初的这个版本呢,它投是一个B加数,那C0层呢是内存的,呃在内存的一个节点,它是接受这个最新的一个数据的更新,然后呢,C1层到这个CK层呢,都是存在于磁盘的,那后来呃,随着大家的不断的改良和完善吧,那呃目前的一些一个主流的一个R的一个实现基本架构呢,就是像这个图里面所啊说就是像像。
14:13
所显示的这样子的,那我们可以看到就是在内存里面,我们会保留一个叫ma table这个结构,那它这个ma table就是拿来接受最新的数据的更新的一些操作的,然后t table呢,它的一些里面的数据查找呢,查找呢是用这个索引结构,是用这个跳表skip list来实现的,那当当这个呃这个map table达到了一定的大小的时候呢,我们会进行一个叫flash操作,Flash操作呢,就是把这个map table我就呃停止将它写入了,然后我会我们会将这个MAT table把它刷到这个磁盘上,那刷到磁盘上面呢,它就会变成一个啊静态的文件就是一个s table,那这个s table我们就就是L层的是完完全全是它是table是样是怎样的,那到了L0L1层呢,就会嗯,进行一个规定的排序,那排序呢,就意味着L1层到这个LK层呢,它都是一个有顺序的一个呃状态的,所以说。
15:13
在每一层往下沉的时候呢,就是其实上呃相当于对内部的数据就是进行让他们在物理上都保持有序,然后呢,呃就是每一个数据它再往下再沉一呃再再下沉一层的话,它会再进一步的根据这个不同t range来画成一个个不呃互相不重叠的这么一个啊access table。那这里面展示呢,是基,呃是可以说是啊LM基于LSMG这个数据结构可以说是大家最知名,就是听的最多,也用的最多,很多人会基于它进行二次开发的这个rock DB,那rock cb呢,整体的一个结构呢,是怎么样子呢?啊,大家这里可以看到,当一个写请求来的时候,那RO它啊写一个lock,我们叫这个lock日志,那这个日志呢,是用于这个啊以。
16:07
以便防止,就是在这个table还没有刷到磁盘上的时候,如果这台啊机器故障了,那故障了的时候呢,我们就必须要有一定的方法去进行这个故障恢复,因为数据,尤其是在像咱们这种啊t circle是面向这种呃金融领域的这种呃金融应用场景这种数据库就是数据的呃可靠性是永远排在第一位的,所以的话就是相当于我必须要写这个日志成功,我们才能把最新的一条数据啊插入到这个内存里面,Ma table里面,那ma table呢,它有一定的这个这个阈值的大小的阈值的控制,那当它呃到了一定的阈值,比方说我们呃用在生产环境当中,一般设置,比方说是一个句,那到一个句之后,它会转变成一个被冻结成一个,叫我们叫一个呃,Imutable ma table就是一个不可再更改的,那这个时候呢,当呃,当它一个ma table就是活跃的ma table变成一个被冻结的ma table之后,他就。
17:07
就可以这个原原来的那个ma table就可以啊,重新把这个内存清空啊,接受新的数据的写入,那通因为这个imus的呢,它要被SH到这个磁盘上,那去做了这个改良呢,就相当于把flash这一步跟呃就是把呃就前台接受写入的这个map table呢,完全是啊隔离开来,就是就是这里是做了一个改良,然后呢啊接下来的话就是啊呃imitable就是imusable mapable被发SH到了这个L0层之后,那L0层的这个文件呢,它也是呃可以呃达到了一定的阈值之后,比方说L0层的文件达到多少多少个,那这个时候呢,就会触发一个系统的ion,那ion做的什么事情呢?就是因为L0层的这些key,它L层的这些ST之是的们相包的,这个也是有可叠的,那这个时候要做一件事情,就是把L层的这些。
18:07
啊文件啊,重新从磁盘上读取起来,做一个规定排序,那这个时候呢,就会往下啊,生成这个L1层的文件,那从L1层到这个L层,那么这个L呢,在当中我们一般会配置成层。在这里面所有的这个啊,所有的这个文件,他们的这个T的范围就已经互相不重叠了,并且是按照这个T的这个顺序去排放的,那当要如果我们要读取一个比较老的数据,已经不到这个内存也不在L层的时候呢,我们会从这个L到这个LN层去读取这个ST,那这个ST因为它有非常的,所以的话,嗯,在呃实际当中,我们去会会用这个去去用这个bloom filter去去把它作为一个啊一个一个加快,加快就是读取的这么一个方式吧。
19:03
OK,我这里呢,诶也收到了,诶这个实时跟进的一位观众的一个一个提问吧,就是说啊,这位观众问啊,W日志不会成为写实的瓶颈吗?诶这个问题非常好,就是我也分享一下,就是我们在呃实际的实际的场景当中吧,就是呃首先W日志呢,它也是一个追加的一个这么一个呃顺序的日日日志写入,但是呢,你说它会不会成为瓶颈它。不一定会成为瓶颈,但是在写W日志的这么一个啊,一个一个这个环节里面吧,其实是确实还有很多呃优化的技巧去做的,呃,比方说我们我们呃自己的t circle的这个这个呃这个场景里面吧,我们在WL的时候,我们也是呃本来在呃以前的版本里面也是会将它作为一个这个D的其中一个就是W这这一份数据也会啊成为一个lsm,但是呢LM呢,它的一个特点是说我我会不断的就是呃从table,然后呢又又不断的往下去做,然后我们后来发现呢,就是说像这个W日志的话,我们是完全可以用另外一个引擎去作为一个啊这个单独的一个数据追加写的,所以一般来说像这个WL日志呢,是,嗯,一般来说是不会成为这个写数据时的瓶颈,对。
20:30
然后呃再说一下就是呃,基于这个LM tree的一个查询的话,就是比方说就是我们经常有两种两种方式,就是有有一个是叫这个点查,点查呢就是呃一个顺序呢,就是我们会从这个呃从上而下就是我们会会会会先去查这个ma table,然后呢,再到这个零,然后再L1,那一旦这个第一次发生匹配,我们就会停止,因为从上层的这个数据永远是就是会比下层是版本更新的,那在范围查询的话呢,就是这个的就是这个。
21:03
这个这个啊,代价就会更大,因为我们在每一层都要找到匹配的范围,然后再进行一个多路的规定。那再再聊一下,这个应该也是在L3P这个范围,就是这个领域内被聊的很多的一个话题吧,就是说空间放大,读放大和写放大,那空间放大是什么呢?因为所有就是LM tree里面所有的这个写操作,它都是这个顺序追加写的,而且对于新数据的这个更新呢,它并不会马上反映到这个数据的旧的这个值里面,就像我们之前的那个例子里面,对T,呃,T1的一个操作,它那可能在一段时间之内,在这个L的这个存储里面,它可能都会保持多个版本,它所以的话,LM trade,呃,基于L的这个,呃,这个系统它是通过。分配新的空间来存储这个新的这个值的就是我们啊前面去提到的这个outle update,所以呢,冗余的数据,或者说数据的多版本在一定时间内是一定会存在于这个F3区的这个系统里面的,所以呢,我们将这种将实际的占用空间,诶不好意思,呃,实际的占用空间大于数据本身的这么一个,呃现象呢,我们就称之为这一个啊空间的放大,那为了。
22:21
去减少这个,因为我们空间不可能空间是有限的,不可能让它一直的膨胀,那为了我减少这种啊空间的放大呢,那基于LM呢,它就会有一个,就像刚才一直介绍的L1往L2 L3L4去不断的往下去做这个,从而呢清理这些过期的数据,以及呃,就是一些嗯不同数据的它一些比较旧的版本,所以呢,就不断的会把这些呃空间放大的一些空间所释放出来,那第二个部分就是一个独放大,呃为什么去要要要跟大家介绍这些呢,因为这些背景呢,他会对我们待会儿分享的这篇论文,它的一个呃解决问题的一个出发点是非常有帮助的,对那毒放到呢,就是。
23:04
代表着如果我要读一个数据,它这个数据本身的大小,呃,会呃,比如说是1K,但是如果我的整个存储的结构,呃。呃,存储的结构它是比较,呃就是基于一定的设计,它会所读到的值会触发,会触发多次IO操作,那一次IO意味着从客户端的一条啊读请求,它所读取就是在我们后端所需要做到的这个磁盘的这个读的实际量已经远大于这个目标数据本身的大小,已经影响了读性能的时候呢,我们就已经会,我们就称之为这种是啊读放大,那读放大怎么样去减轻它呢?那我我我我就像我刚才说的就是LM呢,它它在下面的这个,对于下面的这种SST table,它会做一个布隆过滤器,那波隆过滤器呢,它是可以做到,如果某一个它不在呃某一个S件里面的时候,那它是能呃一定的,就是这个判断一定是对的,所以呢,就从而去降低这种就是相当于给SS文件索引,那就大。
24:11
那接下来呢,就是第三个方面写放大,那写放大这个呃这这这个这个事情就是说因为compassion的时候,其实我们会对呃在每一层,比如说第四层到第五层去,去的时候,其实我们会把多个SS文件去反复读取,读之后呢,去做一个排序,然后排序好就是呃删掉一些数据的旧版本之后,我们会再次把这个写入文件,所以呢,就从效果上来讲,就是我们可以看到每一条key,它可能在整个呃存储系统里面啊,已经是被啊被写的这个这个已经很多次了,所以的话就是相当于一条key可能每一层他都被写一次,那在客户客在在客户端而言,他只是感觉我只写了一条key,我只写了一次,但是在后台而言,呃我们是把一条可重复的写入,那所以呢,这时候呢,会带来尤其在compasion的时候,就是LM去为呃,基础的这个。
25:11
和这个存储系统的这个解放大,呃瞬间造成这种码L的飙升是非常多的的,就是这方面的从业人员吧,就是会会去啊解决和的一些问吧,那那呢,尤其以代的这种系统,其实理念呢,就是最初就是想用这个呃空间放大和读放大来换取这个写大的降低,来达到比较好的一些啊写性能,呃那那但是虽然是这么说,但是呢,就是这三个放大之间呢,其实做好权衡它其实不是一个容易的事情啊,因为呃比方说,比方说我们去假设两种极端情况啊,如果我们完全不去做,完全不是做,那就意味着什么呢?就是我们的这个L3呢,就是它就呃已经基本上可以认为它就是个log文件W是一样的,因为它的不断的刷下来到L0层,那我们不去做,那我们就只有零层的文件。
26:11
那这个时候如果我要去读一个key的时候,那这个时候毒性呢是非常的可怕的,因为这个时候我去找一个key,那这个时候如果我在那个内存里面的这个里面找不到,那我我我就要去扫描所有的这种SST啊文件,但是呢,这个时候呢,就不存在写放大,那这是一个极端的情况,那另外一个的情况就是说,如果我们通过的操作,我们把就一次性的就是把所有的这种S就呃一直维持在只有一个单个的就是呃就是我我我这个文件就代表了我当前写下来过的所有的历史的key,并且都是有序的。那这个时候呢,读性能会非常好,因为我只需要读一个文件,并且呢,这个文件又是有序的,我读起来之后,我马上就可以找到这个呃对应的这个这个这个呃地,但是。
27:05
这个时候如果要达到这种效果的话,就相当于我要随时去做非常多的这种connection的操作,那这个时候呢,其实会导致非常严重的解放大,而且这个时候呃,因为要不断的把这个三的SST文件,然后读起来,然后去合并,然后再写,那其实这个时候对前台的这个呃,新的写入也会肯定会产产生一个非常大的影响的,对,那前面介绍了这么多,这些就是关于啊lsm的一些基本的概念嘛,那其实那那接下来就是第二部分,我们正式去引出今天的啊一个主角吧,就是20221年,我在smo上面就是看到一篇还挺有意思的一个就是一篇文章,那它的一个整体的一个系统呢,它是取名,呃取名为一个啊nova l l SM啊,这里的话我再看一下,呃,有有。有这个诶同事问,呃有有时候观众问到是不是LCM结构的数据库都最好使用SS硬盘,呃这个问题的话,那呃那是肯定的,就是呃其实应该说基于哪种结构呢?肯定是对于数据库这种啊,呃延迟敏感型应用来说吧,就是肯定是SSC硬盘的,这个肯定会比这个机械硬盘啊,就是会好很多,对然后还有另外一个问题是问到如果查询的数据是很早的,且未发生修改的数据已经被emerge到比较早的文件了,呃性能如何优化,呃这也是一个非常的问题,呃这个呢,就是呃首先首先在原生的这个像RODB里面,就是如果是一条这条数据已经是要沉,就是沉到比较底的话,因为它呃沉下去的话,它有一定的这种啊,算法有有一定的这种啊,规则去去去优化的,那如果是一个非常早的,它要沉下去的,那首先如果这条key。
28:58
是真实存在的话,那呃。
29:01
它会就是一层一层的去根据这个刚刚说的这个bmfi去找,那如果呃运气比较好,这条key是它是只存在于呃,因为它只发生一次嘛,他它未发生过修改,所以他话这条T它只会存在于诶其中呃一层的这个啊这个这个ST里面,那这个时候呢,其实你呃根据这个如果这个b filter的这些参数配置,它这种假阳发生的比较少的话,其实是能够通过读一次SST就能够啊去把这个把这个这个这个呃这个T给找出来,那当然了,如果把所有的内存的配置比较大,SST呢,也是可以部分的缓存的缓存在内存里面的,那这个时候就可以呃更再一步再一步的提高吧,对。好的,我们呃在接下来我们再再去聊一聊这个novaba,那这里可以看到呢,首先呃,它的一个非常显著一个特点吧,就是我们刚刚说了,就是整个呃,整个整个基于lsm的这种呃架构体系的话,它其实在里面它负责一些呃主要的一些一些组件吧,其实可以包为三,包括三部分,就是参照那个CB的实践,那第一部分呢,它是一个写日志的这个组件,就是不断的写这个W写成功了,然后他再往这个啊这个LSMG的这个table去查一条新的数据,那这是一个部分,另外一个部分呢,就是说本身去处理这个啊L的这个啊,这个这个写入的这么一个线程,那在这里呢,就是在这里这个图里面,大家可以看到,就是它用这个缩写就是LTTC呢,就是代表着就是l s component就代表着我就是把这个作为另外一个组件也去抽出。
30:51
出来,那下面呢,下面呢,就是通过一个他因为他这篇文章呢,主要是讲述的是不同负责不同功能的一个,呃。
31:01
不同功能的一个一个这些组件呢,他们都是通过一个rdma的网络去连接的,那这篇文章呢,虽然它去呃去去强调了这个RDMA的这么一个一个一个一个网络交互方式吧,但是呃,我整体留下来吧,那肯定这篇文章它的一些呃主要贡献和主要的一些呃创新点吧,其实跟他DMA的一个关联不算特别的紧,紧密,所以的话,今天呢,接下来这些部分呢,就是关于rdma的这些一些东西的话,我也不会去啊去啊去深入去讲,因为。他这里提到用RDMA其实只是为了想就是啊呃也算是一个一个一个技巧吧,就是说呃当网络不成问题的时候,像这种把原本集中在一个进程的不同的模,他去通过啊网络去交互,也能达到一个很好的一个性能的一个效果,所以的话,呃他们去借用了就是rdma的一个一个概念,去进行一个呃去润色这篇文章吧,所以呢,RDMA这个这个东西其在天分享,它并不是一个主哈,那第三个部分就是就是底层的这个啊存储,就是负责把这些接收到,接收到一些一些,嗯上层这个LTC这个这个组件,它下发下来的就是它会提供这个标准的文件接口,那这个时候呢,我们我们嗯接收到一个就是呃,它叫这个storage component,就是叫做SC,那为了这个表述方便啊,其实他们这套架构呢,在咱们这个数据库里面,就是现在。
32:36
这种分布式数据里面也也已经建了很多了,其实呢,它总体来说就是一个哎,存算分离的这么一个一个架构。就是上面的就处理这个LS就叫这个计算节点,然后他们要写磁盘的时候,就是要flash进行那个加m table flash的磁盘,然后呢,还有这种各种comp就读上来,然后再写上次序,就是规定排序之后再写下去的时候,那就都有诶底下的这个呃分布式的这个这个这个这个存储存储这存储节点来来进行,对然后呢,他们还就是说在也是借用了一定向这个现在呃一些一些比较好的一些数据库产品一个念吧,那在计算节点和存储里面,存储节点里面呢,他们都会按照这个彼此的这个功能去划分独立这些线程池,那每个线程池呢,这些啊线程数吧,都是可以配的,那其实相当于比方说在计算节点里面,它把这个嗯,现成的功能分为了四种,那一个呢,是专门跟这个client端,就是跟呃,客户这个请求打交道的,就是负责收发客户的请求。
33:45
那呃,专门有一个线呢,是负责这个RD,就是网络IO相关的这么一个操作,那还有一个线呢,他是负责这个跟相关的相关的意思就是啊,去不断的去啊扫描当前的这个,这个当前的ST是否符合,然后怎么做,然后呢,最后一个线程,这里叫一个的一个概念,就是他会去负责整理,就是他这个概念,待会我会提到,他会去负责,就是不断的去整理他当前的这个range的一些啊重排重组织的,待会我会提到这个东西,对,所以呢,呃,就是我我再回顾一下就是说。
34:26
这套架构其实看起来它,嗯,如果它是放在一个,比如说像现在已经我们经翅看到的呃分湿数据库的一个体系,其实呃看起来蛮平平无奇的,但是它我觉得我个人认为呃这篇工作的它的一个主要的一个一个一个亮点吧,就是说在于将这种l tree,呃基于就是一个单机,本来是单机的一个东西,然后呢。他提出一种想法,把。把这种原本单机的一个呃一一个系统明确的划,划分出就是计算层,然后存储层,然后通过一定的方式去解决了,在计算层本来他会发生一些呃,停写啊,环写这些啊东西,对,然后呢,下一个下就是介介介绍完这个架构之后,就是跟大家就是分享一下,那他的这篇文章里面所提出来,就是说他所解决有三个核心问题吧,那有一个呢,我觉得不算个,就是没有这两个核心,就是第一个核心的一个挑战,就是说呃,基于这种LNP结构的存储体系,像level DB DB他们都会不可避免的,就是要解决一个问题,就要这个缓血,或者说贫血,那会发生在什么时候呢?刚刚其实也有啊提及到比方说啊我的这个。
35:42
内存里面的table,嗯,我配置他们最多是可以写八个,那这时候因为写入非常猛,那这时候已经全部要flash到这个磁盘上了,并且当前的这个S,呃L0的SS文件也有非常的多,那这时候LL0层我我要开始做ion了,但是这个时候compion呢,因为它毕竟涉及到这个磁盘IO它还没做完,那还没做完呢,就会阻塞这个呃的table,对这个L0层的这个s flash的这么一个过程,这个时候发不了怎么办呢?那就会发生发生滑,然后如果呃就随着这个阈值的一个推进,那如果是实在是不进的话,那甚至会停写,就是停写呢,在客户端呢,所感知到的一个一个现象就是啊,请求会掉零。
36:28
对,然后那为了解决这个就是在这个啊,缓解停在LN区结构的这个存储系统里面比较严重的一个问题呢,那他在这片,呃,这片工作呢,针对这个问题呢,是呃,提出了两个解决办法,那第一个呢,是设计了整体的刚才这么一个架构,那这个架构的一个一个设计呢,就是有一个很大的帮助,就是说我把。处理写入和处理这个so的两部分,两大,两大主力模块拆开计算,存储,分离。然后如果哪一部分慢。
37:02
如果哪部分慢,我我就加哪一个部分的那个节点去加这一部分的能力,那这是一个呃比较亮眼的一个突破,那第二点呢,它是他们是引入了一个叫这个动态分区,就是D位的这么一个机制,那这个机制呢,是目的就是为了把让这个业务的写入压力就是在LVC上,就是在计算层的已经进行了一个啊区间的一个划分,就是呃,然后呢,每一个range呢,它会负责就是每个range有自己自己的一个map table,那在这个ma table就是它通过这个区间的划分就是呃,从而实现了每ma table它们之间的这个key的范围是不相交的,那不相交的时候就从而就可以呃,就像刚刚介绍到的,从而就是说我们这个L0层,它就实现,其实就相当于把这个L0层也也可以变得是一个,呃,没有互相重叠的这么一个一个状态,那这个时候呢,我们就可以对L0层的这个comp呢,去进行一个并行的一个comp,就这个时候就能加。
38:03
加快这个呃L0层的这些文件的消化,从来就不会说呃也也不是说不会,应该是说减小这种将来会影响到这个t table flash到磁盘上的这么一这么一个过程,那第二个主要的挑战呢,其实说那我在他这种呃方式下,它其实是呃划分了很多嗯不同的这个drange。比如说啊零到1000,待会有有个图会可以看到,那其实它每一个它都会增加一定的table的数量,那其实呢,增加了那么多ma table之后,如果一个图请求过来的时候呢,它是会呃,相比起原本的我,我所有的数据都写在一个ma table里面,那我在读的时候呢,其实我的这个呃。啊,那所以呢,就是面向这一个map去去去去,根据那个到表去进行个get的,如果能get到的话呢,其实这个呃请支持马上能能够返回的,现在呢,划分成不同的这个D,然后它的这个呃,Ma table的数量增加了,然后呢,所以要查询的这个ma table以及L0的SS呢,肯定是已经变多了,那它的一个解决办法呢,就是说呃,因为要配合这种嗯增加了不同的D划分,然后呢,也也也也也有很多一些呃查询开销,所以呢,它就实现了两个索引,应该是说一个是叫一个啊一范给范围查询用的一个索引,然后呢,一个是一个点茶的一个索引,那也在后面也会啊介绍到,因为他的文章这一篇文章呢,我后面也会放个链接,以及他们的开源,他他其实工还是做的挺多的,就是我今天晚上讲的肯定是我觉得我挑挑是挑出来了一部分,就是觉得最亮眼,并且最有启发讨论的一些部分,对,就是这里展现的。
39:50
并不是这篇文章的啊所有啊,这个主要成果刚刚也已经啊介绍了,这可以跳一套,那呃在这篇论文吧,蔡老师他们就是应该是在这个introduction这部分还没写完的时候呢,就是先把他们的一个个主要的一个结论吧,一个呃成果所展现出来,因为大家可以看到就是它在展示的是一个存算分离这一个原本是一个独立的这么一个,呃一个一个单节点的一个存储系统,做成了一个存算分离的这么一个可以任意扩展的这么一个啊分布式架构吧,那他这里所所想要展示的就是一个我的计算能力和存储能力,对于总的,当我扩展的时候,我对这个总的吞吐。
40:36
总的这个响应的请求的这个能力呢,是有可以提升的,那它这里呢,就可以就是他就放了一个图,这个图是怎么看呢?就是从左下角开始,他用的一个最最原始的配置,就是我存储节点只有一个啊,然后呢,这个计算节点也有一个,但是呢,计算节点我只配了32兆的内存,那32兆的内存呢,也就意味着我的这个ma table呢,是啊比较啊比较少的比较少,那这个时候呢,大家可以看到它的呃总分土呢,就只有呃9K是比较比较低的,对呃然后呢呃然后它它这个呃纵轴的可以看到啊纵也看到,就是它是在就是纵轴是表示把这个计算能力就是往上扩展了,它这个想像像就是相当于一种啊垂直扩容吧,垂直扩容,把这个呃,Memory memory从这个32兆变成这个4G,那这个时候呢,它是很明显的,可以把这个呃,把这个这个总的。
41:36
吞吐量提供到就是提高到这个从9K提高到这个50K,但是呢,这个时候大家可以就是从这个图吧,从这个图的这个上方可以发现,呃,从直观感受来看,大家可以看到就是中间这些有空隙的地方越来越多,那这是为什么呢?这些地方就是我们刚刚说的就是请求调零,因为这个时候计算能力加强了,那这个时候就是意味着我我我可以进就是进行,就是说写入的就是更多,因为我内存大了嘛,然后ma table我的数量去变多了,那变多了之后,我就是这个L层的SST文件的生成速度就会加快,那当L0层的那个生成文件就是速度加快了之后,那就对存储层的这个的能力,就是这个时候就瓶颈就成为就是就是落到了这个存储层了,因为它只有一个节点,只有一个节点,那这个时候虽然它的这个峰值,这个峰值的这个是提高到了五,那。
42:36
他这个时候就是啊。就是我我们是可以看到就是啊就是的更多了,因为就像刚刚说的,这个时候就发生了停写,因为我的这个呃,203S已经不及下去了,那这时候我只能等,就相当于计算节点在这个节点,那这个时候OK怎么办呢?就比方说有用户他正在用着一套这个nova的这个这个存储系统,那这个时候呢。
43:03
当我发现这个存储系统它是一个啊瓶颈的时候,我就把它扩,那怎么扩呢?就是把把比如说我一个节点,我扩到十个就是底下的,因为你就是呃。因为跟不上计算节点的速度嘛,就是把存储节点进行一个扩容,一个节点扩到十个节点,那这个时候就可以啊,非常显著的看到那这个这个时候啊,这个总的吞吐量就由这个5万就达到了差不多是这个250万,然后这个虽然有一些地方这个请求也还是会骤降一下,就是稳定性还有待提高,但是呢,呃,从整体上来看,就几乎是没有一个掉零的一个一个一个现象出现了,所以说如果就是对比起单机,因为这里刚好刚好也也有诶观众提到一个一个一个问题啊,就是说这种基于就是传统的单机的这种单节点的这个LM的一个数据库,呃,存储系统跟现在nova这种有什么显著的区别,那这里我觉得这张图就能非常的去解释一个一个事情,就是单节点,如果发现啊,我的这个内存很好,然后这个网络很好的时候,就是相当于计算能力非常的时候。
44:15
但是我的磁盘能力不够,那这个时候我是很难在单节点上去做一个扩展的,那比如说我我发现我磁麦非常的好,但是呢,其实CPU不够好。那这个时候我也很难很难去去单单的去把CPU跟内存去扩大,但是呢,它基于nova的这种设计的话,就就有一个什么好处呢,就是像这张图所示,我发现哪一个能力不够的时候,我就去扩哪哪哪一层的节点计算能力不够,我就去扩,然后存储发现成为瓶颈了,我就去扩存储,其实其实也是非常就沿着当前就是我们分布式数据库里面这种啊,比较常见的像这种就是存存乱分离,然后独立又可以扩容的这么一个一个一个思想吧,对,然后接下来呢,就是跟大家分享一下,它里面就是我觉得一些比较重要的一些啊设计吧,那首先呢,是一个这个流程,那整个流程呢,它这个,呃,这这个流程呢,就是啊展示了,就是我在客户端发起一个写请求的时候,那这个时候的一个在计算节点跟存储节点,它是以一个怎么样的方式去把这个数据给给写下去的,那首先呢,它呃,在这个后端发起一个新的文件的那个啊新的写景就。
45:27
操作,然后呢,这个存储节点呢,在这个在接收到了这个请求之后,因为这都是基于r d ma的一个交互的,它会在呃在这个这个这个buffer的区域分配一个内存,内存区域,然后呢,分配好了之后,会把当前的一个一个一个偏移量,就是我当前内存一块可以写的,然后通过这个啊告诉这个呃C,然后呃然后呢,这在这个客户端接到这个这个这个这个啊返回之后,这个响应之后呢,它就会开始写数据,那写完成之后,他会去告诉这个存储节点,诶我写完成了,那然后嗯,这个存储节点接收到了这个,这个就是完成了信号之后呢,就会把这个数据持久化,并且我再告知客户端,然后呢,写完这个刚刚这个流程呢,是写一个呃数据文件,也就是说ss table,那写完之后呢,我们要去更新这个原数据文件,因为底下是分布式的,那他我我要知道哪一些文件是写在哪里,并且就是说哪一层文件。
46:27
他当前的一些啊,呃,就是比如说每一个的一些范围啊,还有就是说啊一些一些之类的东西,要写在这个原数据文件里面,那要以同样的流程把这个原数据文件啊给更新了,这是一个。呃,大体上的一个一个一个流程,那呃第二个比较重要的一个设计,就是说刚刚已经,呃就是提到的它这个D是什么意思呢?那我们可以看一下,首先嗯,在它整个架构里面呢,它会把这个业务的一个请求范围,就有点类似于就是啊这个。
47:01
传统的基于中间件的这种分布式数据库分分分表一样,首先我我我假设我假设我业务的范围是一就零到1万,那我当前我有十个,我有十个这个啊。呃,计算节点,那这个时候我就会把这个十个计算节点呢,它的区间划为十等份,那这里所展示呢,比如说我这里是第一个第一个这个计算节点,他所负责的这个T的空间范围就是零到1000,那零到1000呢,就是他啊,那这个范围他他负责了,然后对于这个零到1000啊,在这个计算节点里面,它会去做一层,就再再做一层划分,那这一层划分是业务是感知不到的,就是它就叫这个动态区划分,就是简称,它就会写就是这个叫dge,那这个D呢,它是拿来干什么用呢?就是首先我我我这个零到1000呢,它是一个一个大的一个l SM tree,然后呢,但是在ma table这一层不同的这个呢,是可以有自己的ma table的。
48:03
而不是说零到呃,零到1000,这这这这整个区间,比如说我又划分成了十个十个D,它并不是共用,它们map top是独立的,那这个时候就有一个好处就是。再比方说,再比方说我这十个地位我都是啊,就是零到100,然后100到100到二百二百到300这样子的话,那相当于这。这些地位之间,他们的这个T是不重叠的。是不接的,然后。它的这个啊,D呢,它下面还有一层,就是再多了一层,这个就呃这个就更细了,但是它的文章里面也没有展开过多的细节,它叫一个tiny range,就是这个这个t range,它T是拿来做什么用呢?就是如果他发现这个d range里面啊,它有一些range,比如说很小的范围,很小的范围,比如说890到895这个范围,它是有一个非常。热点的一个一个现象出现,而隔壁的那个range呢,它又没有那么那么热,它就可以用这种tiny range去做一个啊,细粒度的一个负载的重均衡,当当然了,这部分呢,在文章里面也确实没有展开,就是我们可以先假设,就是说它有这么一个一定的机制,可以保证在一个计算节点里面划分出来的位值之间,呃,能够动态的大致上能够保持在每一个d range呢,它的接收到的请求都是这个啊,大体上均衡的,然后呢,在这个基础上,因为他们的这个这个啊,Key的范围是不相交的,所以的话,大家可以看到就是在这里。
49:38
Table啊,它它就是当它变成了这个,呃,Imusable就是不可再写之后,他们就是会需要这个独立的就是flash到这个磁盘上,而这个时候呢,Flash的时候,那flash到S就是在层,呃在这个L层的这个S,那来自于不同的这个的话,它其实它这个T是全相交的,那这个时候就有一个好处就是呃这个放到后面应要讲就是可以进行一个并行的,一个就L层的并行的。
50:11
呃,那。我先讲下一个,下一个对那大可以看到其是呃,文章呢这里呢也列了一个对比吧,就是帮没有这个D这种划分跟有D这种划分的时候,会发生一个怎么样的一个一个就是好的一个变化呢,大家可以看到这上面的这种情况,那二零层的这个,因为它是没有办法去并行的。在。这种情况下,假设一个最坏的情况吧,就有可能L03的某一个ST,它在最坏情况下,它是有可能是覆盖了整个空间的整个T空间,就比方说这个大家可以看到这里有一个非常长的一个叫零的零到600吧,那我们先假设很快很快的情况下,这时候这个这个啊这个L0层的S,它是一个零到一这个范围吧,然后当它要发生就L0到L的时候,它必须要跟其他四个S去做一个归并,那这个时其实那在这个时候他会呃要把不但不但要把L0层的其他ST全部去读来比较一遍,并且L1层的,因为我这个区间就是到那这个时候L层我知道自己些S属哪个范围,属于哪个范围,是因为发生一个很的情况,就是在很的时间之内生个LS件,然后。
51:36
好,这个S文件又恰好覆盖了这个的范围,是覆盖了L1层的所有的SSD的,那这个时候就相当于我要把SL1层所有的SD重都读,就是都读一遍,然后再做一个规定排序,那这个时候放是非常严重的,那也就意味着L0层的L1层的这个变慢,那变慢会发生什么,就是刚刚一直反复提到的那样,可能flash的就会变慢了,那flash不聊了,那前段的前景就就会出现慢慢的缓,然后到这个停写,对那有了有了这个之后呢,就相当于我们的这个就是这个com,它就可以就是分开区间,就大概呢,可以看到下面的这个示意图,就是我零到100,我L0到L1,我是可以独立的去看独立ion的,我100到200也是可以独立的,就是可以啊,非常的实现一个啊并行的一个compion,因为在原生的里面,只有从every层开始ion,它才它才可以啊进行一个一个一个并行。
52:36
的一个,对,然后这里还有一个好,第三点好处呢,也是文章里面提到的就是啊到这个,因为是这样子,就是如果协调者他发现呃,就在刚刚其实有一个有一个有一个组件,它叫一个协调者,如果当前就是存储层的这个节点,就是资源非常充足的话,其实这个。
53:00
呃,这个这个compassion的这个操作是可以由这个存储层去主动发起的,当然这个呢,在文章里面他并没有去展开,因为他说他只是他们的一个一个一个想法,就是说我不需要计算层序发现啊,去不断的去把这个。把这个就是不断去扫描啊,我当前有哪些可以做compassion,而是有存储层去去去发现,那呃这里也有观众提到,为什么要考虑下,那我我的猜测吧,因为它没有讲展开讲这部分,首先我猜测是呃首先在它的这种体系里面,呃,存储层是比较好扩展的,然后计算层其实没有那么容易,没有那么好扩展,因为它其实相当于一个分库分表的,然后如果它扩展了,会涉及到一定的这种呃路由重分布,然后呢,要告诉就是前端请求路由啊变的这种,然后呢,它是存储层,它是非趁去扩展的,所以的话,如果能将这些非常啊非常时的一些操作放到一个一个存储层,那如果下沉去做的话,也能极大的减少在这个啊,在计算节点跟存储节点之间的一个啊数据的一个开销,对存储层做完之后,我就直接把这个一个一个更新之后的云数据告诉这个计算层,诶我现在的就是做了什么肯然后呃云数据更新。
54:19
怎么样,对,这是一个,呃,另外的一个点,那第三个就是这是一啊刚刚这个还没讲,对,就是这个,呃,就是刚刚所提到的,因为他们划分了非常多的一不同的一个动态区间,那动态区间就意味着ma table的数量增加了,增加了呢,其实对这个啊,查询操作的它的一个一个啊耗时呢,它是会会增加的,那这个时候怎么办呢?那其实就是呃呃这个点我我也觉得应该怎么说呢,这是因为他做了这个主要的创新点之后,这也是不得不做的一个点,对,因为他。你毕竟你画的区间,然后ma table增加了,那我怎么怎么能在原本的基础上呢,再把这个呃读写请求的读性能给维护好,无非它就是首先它维护了一个呃lookup index,就是为了就是如果当前当前如果这些这些啊数据是存在于咱们的这个m table和SS,呃就是L0SST的话,我们就可以就是呃非常快的去通过这个lookup index去去这个啊查找到那当某一个L0层ST呢,它被comp到了这个L层的时候呢,索引上对应的这个这个entry呢,就会被remove掉,然后呢,这个呃计算节点呢,它同时呢,它还维护了这个这个就是范围的这么一个索引,因为他知道每一个的一个范围嘛,所以当一个请求呢,一个SC请求就是涉及到了key,它也是有可能是在这个table呃,L03SST去找到的话,那这个范围所引呢,就能非常呃快的去去响应这个。
55:55
个scan的一个一个操作,那最后一部分呢,就是涉及到这个这个这个存储层,那存储层其实大家刚刚是可能没提到一点,是我某一个某一个SSD文件,我要写到这个存储节点上的时候呢,首先我我就是做这种啊分布式的系统呢,要保证个事情,那第一呢,要保证一个负载的均,第二呢,我要保证一个,因为毕竟它是存储层嘛,它要保证这个数据的一个啊去避免一个单点的故障的不可恢复的这么一个场景,所以的话呢,它就是呃根据一定策略吧,就是一定的一个一个power d就是用一个呃就这个是用一个现成的方法了,就是没有太太高深的一个原理啊,就是说他把我我我会把一个呃数据文件,然后呢,就是呃,打散一个S个里,然后呢,呃,因为考虑到这个一个。
56:55
它它就是这篇文章面所提到的就是啊,数据文件,也就是每一个table是用这个就是这种方式来来存的,那他们的一个的就是们三加的一个方式,就比方说我有一个S,就是三个数据块,三个数据块,三个数据块然后呢就是啊然后。
57:22
根据一定的算法,在这三个数据块里面去校验出一个校一个校验快,然后就变成一个三加一的这么一个形式,那这种方式呢,就比就是说传统的就是多副本呢,它会节省很多的空间,因为这三加一的方式呢,比方说一个一个s table呢,它是三兆,那这种三加一的方式呢,最终它所占的空间也就是四兆,但是呢,它能容忍就说一个节点的丢失,那原数据文件,因为它比较小,然后呢,他他用的是就是直接用的这种这种多部多副的方式,比方说啊数据文件他们就直接写一个啊三副本,对。呃,这里有观众,呃提提到一个问题,我觉得就是这个细节也抓的很好,就是D如果发生变化的时候,数据会在ma table之间,呃,移动吗?这个问题问的很好,其实我在后面跟大家的那个讨论的那一页,我也列了,就是跟这个类似相关的一个一个话题吧,就是呃,它的数据应该是会移动的,但是文章里面确实没有比较去强调这个,就是说它第,因为它下面不是还还划分那个什么tiny range。
58:29
其实它设置那么多机制,就是想为了做到一个,就是我d range一开始的划分,随着这个workload变化,我肯定不能够保证,呃,自始至终它的一个workload是均衡的,那这个时候他肯定会有一就是要不断的调整,但调整的时候他怎么样根据这个就是说保证这个数据的这个啊不要。双写或者说存在两份,或者说数据一致性,那这方面呃,比较遗憾没有提到对。OK,其实那刚刚就跟大家讲了,就是它比较重要的设计吧,然后呃这一部分的话,我觉得可以稍微快点过,因为就是一篇论文里面,它肯定性能展示的话,它呃表现出来的性能数据还还是挺亮眼吧,因为它做了一些嗯不同的一些比较吧,首先它会呃自身他调参,就是说呃我去表明诶我我我自身我通过调不同的参数,我是能够就是达到呃挺好的一个扩展的,呃比方说我调整这些呃。
59:32
这个这个计算节点啊,还有存储节点啊,都能够达到一个在不同的这种分布下,比方说他用了这个呃,就是数据在这个uniform就是这种,这种叫什么,就均匀分布,均匀分布下还有这个齐雾分布,就是这种有热点数据,比方说呃,二十百分之八十的访问概率都是集中在20%的这种啊,就是其雾符符合这种奇雾分布的这么一个啊,一个一个一个一个访问分布的这种形式下去做了很多很多组的这种对比实验,然后呢,当然就是结果就是都都能说明就是在啊这种读写比例不一样,然后呢,数据的这种啊,访问的概率分布不一样的这种各种场景之下都能够取得,就是挺好的一些一些那个,因为它的测试呢,还是非常的充分,然后呢,就是这里就不多展开,然后呢,刚刚是测自己,然后呢,后面还放了一组,就是说他会跟当前的一些像这个level DB跟DB他们去进行对比么。
60:32
数据吧,然后呢,呃就是这里就稍微提一下,就是大部分场景下,呃,尤其是大家可以看这个左上角,就是它所比较出来的,就是在这种小规模的场景下,它它是这个就是黄色的,这根就是黄色,这根是他们,呃是这个novam,就是在这种黄色黄呃小数据场景下,它比这些rock CV呢是领先非常多,尤其在这种比如说像部分布就是有热点数据存在的情况下。
61:02
呃,读写各占一半,它的数据测出来是比这个rock d高,呃是它的差不多四倍,对快接近四倍,但是呢,呃随着这个吧,就是随着这个嗯数据上的扩大,其实它到后面的这个优势也在有一些,其中一些worklo上面的优势没有那么明显,比方说右下角吧,右下角是一个啊,就是一个十个十个节点,然后呢是一个2T的数据库,那这个时候因为Rose它本身它也可以,就是因为也也分了十份嘛,然后呢,就是这种写多的这种场景的话,它其实它其实呢,就是跟这个原生的C呢,就是差距也没有那么的明显了,对,而且呢,它这里也也发生了一个比较有趣的现象,就是蓝色这个啊这个这个实验,蓝色这个,呃这这一组实验呢,它标明的是叫这个RO c tu,就roci tu呢是他们去。
62:00
去去根据有很多调优参数嘛,就是。呃,红色的这组是他们没经过调的,然后蓝色这组呢,是经过了他们的调的,但是呢,在很多场景里面,其实也再次印证了,像基于LM这种结构存储系统呢,呃,很难调出一个,应该是说应该是不存在某一组参数能够让这个系统在。所有不同性质的worklo worklo下面都取得比较好性能的一个一个这么一个事情吧,就可以看出就是这个像这一组啊,右下角低这一组中间啊,这个100%是写的这一组,Uniform分布的这一组,你看就是经过调还比没调优用原始参数的这个这个吞吐量还要低,对,所以的话也也也是另外一个启示吧,就是说因为nova SM它本身也是一个啊,基于这种有非常非常多的一些调优参数,要要做的一个事情,就是他们也这篇文章也非常实诚的展示,就是说嗯,很难说做到一套参数,我在所有的场景里面我都是最优,对。
63:13
然后呃,最后一部分吧,最后一部分就是这两页我觉得是蛮蛮重要的,就跟大家就是就是把把这篇论文就是最重要的一些点,我给大家分享的时候,也谈一谈我的一些一些想法,就是也就是啊聊一聊,就是我们就是读完别人的一些工作之后,那肯定会受到一些呃启发想法嘛,对,就是我我我我想到的一些点嘛,对,那呃再回顾一下前面就是回顾前面就是那但凡去基于这种lsm去做优化的所有的一些工作吧,他嗯,无非他面临着两个两两个问题,就是如果另外一个解,就是刚刚说到的读放大,写放大,空间放大,然后呢,上面方框这里是我刚刚提到的,就是说如果你走一个极端和另外一个底端,那其实会发生什么事情,然后所以的话,大家就是我。
64:03
要提出一些方法,我们不能走极端,然后在中间这些地带,我们能去做一些什么事情去啊,把所有的事情都把把这几方面读啊,写啊,空间啊都去优化,对,那呃,那nova LM呢,它就是说我在这三个因素之间,我去做一些取舍设计的它一个基本的一个亮点,比较一个原理吧,就是我把原本的这种啊,单机单节点的系统,我用一个分布式组件化的一个方式,其实也有点我们现在聊的很热门的一个一个一个一个一个一个场景嘛,就是说呃,像微服务一样,就是。将原本一份代码里面不同的模块,我将它就是拆出来,然后呢,这种方式就是说我每一个服务的的的能力不够了,我就去加这个服务的资源,那从而就令原本这些每一个拈就具有可扩展性,也把原本单机的一些资源的一些限制去打破了,那呃。
65:06
但另外一个方面就是,就是说我我我觉得这篇文章能够能够带来的最大一个一个去比较创新性的去做了这个事情吧,这个是非趁的一个启发,尤其是将这种将不定期的compa对磁盘这种这种冲击,就造成短期冲击呢,相当于可以剥离出去,这是非趁的一个一个,呃创新吧,对,那在实验当中呢,就是有一个地方吧,就是当然这个可能也要经过验证,就是他实验用的这个每个KV的默认大小是1K,就是嗯,不算小的一个数据。所以的话,如果在。EK这种场景下,我个人现在就是根据原理来判断的话,其实在对于这种D这种设计呢,它。它是比较优势的,因为它是通过可以它在那个那个实现里面,它有一个细节就是说啊,如果当一个一个一个table,它的这个包含的这个这个unique key就是它包含了,就是说啊这种不重复的key小于一定阈值的时候,它是会在不同的之间把那个给合并的。
66:13
因为它做d range以及这些合并呢,它其实就是有一个非常呃统一的一个出发点,就是说我要想方设法去减少这个磁盘的写入,所以的话,它的他用这种啊,1K的这种啊,大比较不算小的测试数据的话,对于他自己的这个结果来说是比较优势的,我个人觉得就是它默认1K,那我那其他原生的这种CB,我不断不断的写磁盘,那这个时候呃,因为每一条T它这个量都不小,对吧,就是1000条,1000条T就一兆了,然后。对,100万条就是一个句了,那这个时候就相当于第一位句,它本身就可以减少这个磁盘写入,就相当于它把自己的优势给给给给取,有一点点取巧的放大了一些,对,那然后呃,第二点呢,就是还第二点呢,就是刚刚也提到,就是像它里面呢,是讲述了,就是说我这个dge还有t range的这些啊机制设立吧,是可以去动态的保证我的一个计算节点在不同的这个table的写入之间呢,它是一个比较。
67:19
比较均衡的,它是可以有一个动动态均衡,但是因为咱们毕竟是工业要做落地的嘛,那从工业落地的角度上来说,其实这一块从我们根据一般的工程实践上来的话,它会涉及到比较多的这种数据一致性的保证,就是说你这份数据在那份数据里面就是挪来挪去,那会不会造成啊没血了或者是双写了之类之类的,比较遗憾的是这一块呢,没有呃太多的展开去讲。那还有呢,另外一个方面,也是从这个工程实践上去去进行一个推敲吧,呃,比方说呃比方说呃在这个呃刚好我这里看到也有一位观众提一个很好的问题,就是说呃如果我们要将这种像这种思想将工程落地的话,呃需要考虑什么方面的因素,那其实这里的话,呃我我也列了一些,这这这个也刚好可以跟这位观众去分享和讨论这个问题吧,嗯,我我觉得吧,比方说在在我完整的看下来之后呢,就是比方说在刚刚的那个呃计算节点网测试节点写入的这个流程的交互当中,哈,文中呢,先提及到了这个,我先写这个数据文件,更新了这个block,然后之后呢,我再会去这个啊,更新这个原数据文件,但是呢,因为。
68:37
任何场景,呃,就是在分布式场景就更加了,就是任何环节我们都要考虑这个异常的存在,那如果这两次中间发生了故障,我们是怎么样处理啊,是由这个呃上层节点去完成一个事物的操作吗?是,是写了一些就类似于事物的两阶段日志吗?等等,就是如果他写了中间就是说写数据成功了,但原数据文件没更新成功,那这个时候是怎么处理?对,那这个时候是没提及到的,那对于这种工程实践上来说,其实是蛮致命的,因为正常的流程很容易写,但异常的流程往往占据的代码量更多,对,那比如说还有另外一方面啊,它这个。
69:19
数据文件它是用这个扣的方式去保证这个数据和可靠性,但是我计算节点怎么样去校验和保证我N加一个数据块写入同时成功,那如果有部分失败呢?比方说刚刚说的是三加一三加一个,呃,三个数据块,一个校验块,那如果是两个数据块成功了,一个加验块没成功,那这个时候是谁去把这个多余的啊,我我如果要回滚这个操作。那我是怎么回滚,或者怎么重试,然后我怎么样去保证这个就是在存储层不会有脏数据的存在,那还有就是说呃。如果有单个数据,它已经发现它坏了,磁盘坏了,发现丢失了,我是怎么样去重新生成,对然后重新生成的时候,因为在这个Co的这个领域,就是重新生成的这个啊,这个代价也是一个专门的一个话题,就是我这些数据怎么样分布才能让我在这个恢复的时候,就是这个从速度还有战略的带宽上去去去做一个最优化的一个策略,它本身也是一个啊另外一块比较值得去得去推敲的一个领域,对,然后呢,呃呃,接下来呢,就是另另外一个方面,因为就是他也没有,他没有,他没有就是特别提到他只是说文章里面用一句话带过就是N个LC,他会责N个啊区域的这些数据的写入,其实呢,在这里呢,就相当于比较像是咱们这个分布式数据库,基于比较传统的基于中间键的这种分布式数据库,就是有一个中间键,我知道你的底下的存储节点,或者说底下负。
70:55
写节点分别是呃去负责哪一份哪一部分数据的,那这时候就是相当于分部分分库分表的操操作,那这个时候呢,啊,其实路由变更这一步的灵活性呢,是会有一定的限制的,所以他在文章里面去。
71:10
呃,是是特意没有去去提,就是说加这个计算节点的时候就怎么样去做,对,因为加计算节点就意味着我新加的计算节点这些负责的range就会啊改变,对,那呃还有还有另外一个比较,其实是很重要的一个部分,就是它的所有的这个,呃性能测试里面吧,基本上是嗯去描述这个。性能的最大值,那最大值最大吞吐量这个指标重要吗?它固然重要,它肯定很重要,因为代表着你一个系统的能力上限嘛,但是往往在我们的这个真实的这个业务场景当中,业务除了这个嗯,能力的最大值,它还有一个非常重要的考察指标,就是你的性能的稳定性,就是你不能你不能跟我说,呃,这一个小时我能提供非常非趁的性能,但是下一个小时我有可能会因为一些不稳定的因素,然后会掉零,然后呢,而且它这种像nova LM,它是基于这种分布式的这么一个呃,一个架构。
72:12
它所有的写数据,它一直在这种网络交互,网络交互网络交互,所以的话,本身它因为磁盘的IO就会已经会带来这种啊总体性能的不稳定性了,那现在又加入了这种啊网络网络之间的一些开销,那网络抖动就更就更更平常,就是就就就就常见吧,就是所以说嗯,我觉得就是这种思想挺好,挺挺新颖,但是呢,呃,加入了这么多网络的一些因素之后啊,性能的抖动就是是不可不可忽视的一个一个因素吧,那在文章里面的就是也确实也还没有啊去谈及这方面,就是我的一点思考,当然了就是呃,这这这个文章我觉得就是还是比较好的一点,就是说他的一些理论啊什么的,他都没有说是停停留在。
73:05
就是纸面层面嘛,他也把这个代码,它是基于这个level DB。然后呢,呃,自己应该是加了两万多行代码去实现了这一套啊,他所描述的这些核心的这些设计,也把就是这个get的地址,大家也可以搜得到,所以的话呢,就是大家有兴趣的话,可以去针对我刚刚呃聊到的一些话题,看一下他们在工程实践当中是不是有考虑,如果没考虑的话,有有有兴趣的同行也是可以继续的去,去深入的这么去去。继续去二次开发吧,对都都是可以的,对,那么我呃今天呢呃这个技术分享呢,就呃我的这一趴就啊到这里吧,然后呢,呃但是呢呃那接下来接下来终于诶感谢大家就是这么这么久来听我啊说了这个话题吧,也希望大家呃有一定的收获那呃。
74:01
我分完之后呢,也进入到这个第一轮的,呃,第一轮的这个这个抽奖环节吧,那抽奖环节的话,我们第一轮的奖品呢,是由呃,咱们腾讯这边送出的五套啊数据库技术相关的丛书,然后呃,大家呢,现在可以扫描我们的二维码呢,进行一个抽奖,然后呢,手机端的用户呢,也可以把这个截图呢,呃呃,这个这个保存下来,呃,我们11点之前的这个扫码都是参与,都是有效的,OK,那我现在呢,就是啊给大家再多一点时间啊,十秒钟吧,就是大家可以扫描这个二维码进行抽奖。OK,好的,那我我相信就是在看直播的小伙伴应该也是已经把这个码给扫了,那非常感谢大家参与这一轮的抽奖哈,我们再会在今晚的大概11点开奖,然后中奖的同学呢,到时候记得填写这个联系方式和邮寄地址啊,然后呢,也欢迎大家继续来关注我们下一轮的分享,然后继续啊进行提问,那就像我在一开始介绍那样,就是DB见这个系列呢,我们不断会去啊,分享我们在节日前沿的一些啊见解吧,然后呢,因为在腾讯内部,咱们做这个腾讯数据库,我们也可以,我我们也是不断在这个基础研究创新去持续关注,而且我们一直觉得这两者就是技术研究前沿探探索跟这个技术的工程化落地,两者呢是一定是相辅相成,相互促进的,所以在啊,咱们TB数据库团队在存储方面的这个工程落地方面呢,我们也做了非常多的一些工作。
75:49
那接下来的时间呢,我就把时间交给我的同事,同样是来自这个腾讯云的数据库专家工程师啊,朱朱冲,呃,大家我也可以叫他TDY,那他为我们带来咱们推S团队在这个分布式数据库啊,分布式存储层相关的一些啊,落地的一些新的体会和技术分享,对。
76:11
你把时间交给他。呃,大家好,感谢我们的唐嫣老师给我们分享的那个lava LM素的,呃,我我先做一下我自我介绍吧,我叫朱聪,呃,研究的领域主要是关注分布式事务以及大规模数据密集型系统,目前呢,主要是负责分布式数据库t t circle存储引擎相关的工作。嗯,我今天要分享的主题呢,就是跟我工作的内容有关的。呃。呃,就是我们的TTC口新敏态存储引擎。呃,我们为什么需要去做我们的那个敏泰存储引擎呢?呃,TTCQ呢?我们首先介绍一下我们t t circleq t tcq呢是腾讯面向金融场景,高性能,高可用。
77:12
的企业级分布式数据库解决方案,在国内呢,拓了20的银行里面呢,已经有一半多在使用TT了。嗯,但是我们在推广的过程中呢,其实是遇到了一些,嗯,银行提出来的一些那种需求,但是我们呃在我们TTC口的目前的这套架构中呢,就是说不能特别好的去解决,呃主要表现在哪一个是兼容性,呃因为我们t t circleq呢,大家可以看到我们在那个分布式存储这一层呢,是一个个的那个MYSQLDB,呃然后呢,我们在中计算层呢,是通过那个哈希呢去把这个数据呢分片在呃下面的那些存储节点上面去,所以说在这个过程中呢,我们需要去指定一个shut key,这然后呢,这就要求呢,那个用户呢,在建表的时候呢,去指定这个下key,然后呢,我们才可以把这个就是说数据呢,通过哈希呢分在不同的那个DV节点上。
78:05
呃呃,第二个呢,就是说我们在运维的过程中呢,就是说我们因为我们是分布式数据库嘛,那么我们可能需需要承接扩容这种操作,那么当我们做存储成扩容的时候呢,呃,这个时候呢,我们通常就需要呃DBA它去手动发起,而不是说去做自动的一个扩容,那么DBA呢,它虽然虽然说这个手动发起的过程呢,已经很简单了,只要DBA呢去登录,登录运维,我们的运运维页界面,点一个操作扩容,我们就可以把那个数据搬迁,然后扩容到一个,就是说加入到一个新的节点上去,但是呢,在这个过程中呢,我们的事事物呢,还是会受到的,就是说一个中断,就是说当前的那个会话,它需要断开一下,然后才会就下一个连接呢,他才可以正常的处理请求,那么这种这个这个这个事情呢,在业务那边呢,他看到的就是说是一个中断,呃,还有呢,就是说,嗯,我们的一个就是模式变更,就是我们经常可能会遇到就是说我的业务啊,在运行过程中需要加一个字段啊,或者加一个索引,那么这种这种这种情况呢,在我们的那个就是就。
79:06
就现在的这个架构里面呢,我们就需要借助一些呃PT工具来做online DD为什么需要online呢?因为我们不可能停机嘛,就说因为如果数据量很大的话,我们这种加加电呀,或者是加索引这种操作啊,可能就是需要比较长的时间,业务是无法去忍受的,呃,所以说我们就需要依赖这种PT,但是PT呢,毕竟是外部工具,如果当我们在在用这种这种PT工具呢,进行online online加索引啊,或者加电的时候呢,如果这个时候呢,系统出现了一些故障,那么这个就是说我们怎么样去让这个故障,就是说比如说原子的回退啊,或者是可以继续经常推行推动啊,这个过程呢,就是说处理起来会非常的,就是说比较比较麻烦,不是说不可以做,但是就是说会很麻烦,而且是比较难去保证,就是说绝对的,就是说这种这种这种一致性,呃,那么。嗯,就是说基于这些这些问题呢,所以说呢,我们就提出了我们的就是说,嗯,现在这种架构的一个升级版本,我们就说内部呢,就称之为就是说t t circle敏态存储引擎的一个架构。
80:09
呃,那我们这个这个架构呢,它的一个目标是什么呢?就是说我们是希望呢,就是说业务能够像一个使用一个单机数据库一样,去使用我们的一个系统。呃,然后呢,我们就是说,嗯,就那那怎么样才能去做到让用户就是说一像使用一个单机一样的去使用我们的分布数据库呢,那这里就会有几个特性,就是说我们首先呢,就是说跟MYSQL是完全兼容的,就是说呃,你的用户以前在MYSQL上怎么用,就就到到我们的新系统上也是怎么用,包括存储过程和和触发器,就是说这些就都可以。嗯,完全是一致的,还有呢,就是一个全局一致性,就是说不能说就是说因为我是个分布式了,那我就嗯,比如说某些情况下,我可能就读到了一个事物的一半,或者是或者是就是说呃嗯,就类类似的一些,就是说事物并发上的一些可见性的问题,还有呢,就是说我们刚刚提到的,就是说我们在D边或者是或者是,那就是说我们的数据容量不够的情况下,我的扩收容的话,我们的业务呢,应该就是说是完全就是说没有感知。
81:09
然后呢,就是说呃,完全原生的一个在线表结构变更,就是说我们不再就需要依赖于就是说其他的一些外部的一些PD工具啊或者什么之类的,就是说我就就跟就跟我用买Q一样,我就想加个列,我就用一个就是说加列的语句就执行,但而且这个语句呢,就完全是就是说它是一个online的,就是说它它不会去把你的表锁住,然后影响到你的业务。呃,然后呢,呃,我们今天要介绍的呢,就是我们这的这这一部分,就是说最下面的这一部分,就是说是我们的一个,就是说我们的一个存储这一块,我们的存储这一块呢,就是说它它呢是一个分布式的一个KV系统,它呢就是说并并且呢,就是说它还要对外提供一个事物和一个自动。扩缩容的能力,那我们这个这个系统呢,我们可以看到就是说我们其实是数据是多副本存储的,我们把那个数据呢,就是说拆分成。很多很多很多很很多个,就是说一块一个一个数据块,然后我们每我们的数据块呢,其实就是说它是一个按有序的,就是每个数数据块内部它其实是有序的,然后呢,我们每个数据块呢,其实会有做一个raft的一个就是说呃,就是三副本,对然后。
82:18
呃,然后呢,就是说我们这里,这里就是说底层呢,就是说数据是怎么放呢,其实是基于,也就是基于刚刚就是说我们的唐嫣老师呢,就给我们介绍的这个LCM数的这个。呃就呃首先呢,就看一下我们的,就是说我们的一条circle呢,就是说发到我们的系统中呢,我们是怎么样去把它就是说转换成一个KV操作,然后怎么样去把它就是说分布在我们的一个,就是说那个KV系统里面的呢,首先呢,我们看到了一个就是说建表语句,就是collect table,呃T1它有这个这个这个表T1呢,它有一个组件ID,也有一个二级索引fe,呃当我们收到这个这条建表语句的时候呢,我们会其实我们首先呢,就是说我因为我们要把它转转码成就是说呃在KV系统的一个分布上,就是说我们现在收到的这个界面就不再像原来MYSQL一样的,就是说,呃把那个就是在本地呢,就建一个表空间的文件,然后把这个数据插到这个表空间里面,我们现在呢,就是说,因为我们后端呢,不再是一一个本地的磁盘了,而是一个就是说分布式的一个KV系统,所以说我们的这个计算层节点呢,就说到一个这样的语句之后呢,它肯定就是说要把这个表就映射成一段KV的一个map,那那我们是怎么去映射的呢?就就就刚刚的这条语句,就是说组件,组件ID呢,我们会获取一个就说。
83:31
就说一个一个索引ID,这个索引ID呢,就会作为这个组件的这个表的一个前缀,那我们的我们就可以意识到,就是说假设我们ID呢,这个获取到的这个前缀呢是零一,那我们就可以说前缀是零一的这个这个这个key,那就属于呃这个这个T1这张表的组件,然后呢,二级索引呢,它同样会去获获取一个索索索引ID,那我们假设这个二级索引F1呢,它获取到的索引ID呢是零二,那我们就可以做这个推断,就是说呃,我们。零二开头的这个T,那就一定是属于T1表的F1的二级索引的数据啊,那我们当我们我们看一下,当我们收到了一条 inside intot1value,呃,这个就value的值是133的这个这个数据的时候呢,其实我们是就是说我们会产生两两个key,一个key呢,就是组件组件一它的对应的value是什么?那么我们结合上面的就是说获取的那个索引ID呢,我们就对他进行一个就是说编码,就编码成什么呢?就是说索引ID是组件的索引ID是零一,然后我拿到了这个Y,呃,Key呢是11,所以说我们编码成0101,然后这个呢,就是就是这条组件的一个一个编码,然后我们把这个这个编码队插到那个我们的数据数,就是说我们的数,呃,存储的那个KV系统里面去那那。
84:45
那我们的那个就是说二级索引呢,是同样的,就是说呃我们呃我们二级索引呢,就是说这个这个这个F1呢,它是等于三的,那么我们要通过二级索引找到组件,这这样的话,我们这个索引才是有意义的,所以说呢,这个这个时候呢,其实我们拿到的是三一的这个这个对那么么,我们就会编编码成呃F1的索引ID是零二,那么就是020301,那么这这条这个。
85:10
这条呢,就是说,呃,就是说这两条呢,K呢,就是我们我们就会对应上了这个这个in inside等语句,那么其同样的呢,当我们来到另外一条的时候呢,就是说232的时候呢,其实是同样的一个,这个道理这里我就不再赘述了,那么那么我们怎么样去把这个数据读取出来呢?当我们比如是说我们收到了一个,就是说一个查询,它有个很明确的就是说无染条件,就是说ID等于二,那么其实呢,我们会。嗯,因为我们知道就是说T1这张表的索引ID是零一,那么当它的ID是二的时候呢,其实就是0102,那我们在这里呢,就是说比如说我们在读的时候呢,我们会知道0102,它是属于REGION2的吧,REGION1的这个范围,那么我们就会到这个这个t store1的这个REGION1上去读取,然后把这个值给读取出来,嗯,那么当我们如果假设我们收到的是一条二级索引的值呢,那这个时候呢,其实。
86:03
啊,就比如说F1等于三的时候呢,那么我们其实知道就T1的F1这个二级索引,我们我们的索引ID是零二,那么我们可以拼出0203,但是我们的二级索引就是它它它不只是有这这两个这两个段,它其实还有一段就是组键的段,那我们怎么样把这个找出来呢?其实就是说我会我们是前缀扫描,就是通过一种前缀扫描的方式,在这个RADIO2这里前缀扫描我们就会发现了,我们其实是有两个组件的,就是对应的这个组件是一跟二,那我们再回表就回到这个t store1的RADIO1上去,把这个值给读出来,最最终呢,我们其实就会读到了这个这这两行数据啊,那么这里呢,其实我们就会以看到,当我们的一条exce语句过来的时候呢,其实我们会产生两个KV,那如果恰好呢,这两个KV呢,就是说它的那个所所属的那个存储节点是不一样的时候呢,那么它就会出现一个问题,就是说我们要么要保证这条银色的,就是说如果它成功了,那就这两条key都要插成功,如果它失败了,那就这两条key都要失败。所以说呢,这就。
87:03
这是我们的第一个问题,就是说是一个原子性的问题。嗯,然后呢,第二个问题呢,就是说就是一个就是比如说假设我们如果同时就说两个客户端,他收到了呃,都都是都都是插入这个组件等于三的这个值的时候呢,我们其实我们知道就是说呃组件它是唯一的,就是说它不可能不可能就是说数据库中存在了这个组件,就是两条不同的数据,那那么我们的我们的就是说计算层呢,它就会说我假设我收到了这个in inside value等于inside的这这行语句的话,我会先去呃就是说存储这里看一下这个值在不在,如果不在的话呢,我就把这个三这个组件等于三的这个值插进去,但是假设我现在有两个客户端同时执行的时候呢,那我们可能就会出出出出出现一个顺序,就是说我这两个这两个这两个计算成的都去存储节点看了一下,这个组件等于三的这个值在不在,结果发现呢,诶不在,那他们同时就把这个组键等于三的值插进去了,那这样的话呢,其实就遇到了一个问题,就是说呃,那我就把一个组键等于三的就是两条不同的值给插进去了,所以说呢,这里。
88:08
也是我们遇遇到的第二个问题,就是说我们要怎么样去就避免这种情况,就是说这种呃,并发事物的一个处理。嗯。呃,这里面呢,其实还是会有一个问题,就是说假设嗯,我有一个我现在正在导数据,呃,就导非常多的非常多的数据,然后呢,我这两个在这个节点呢,它存不下了,那么我们就,嗯,就是说在我们的新系统里面,我们要去做一个自动的一个就是说扩容,那么在这个扩容过程中呢,这个事物其实还是在执行过程中呢,那么我们可能就要就是说把这个数据呢,就是说搬搬到其他的节点上去,那么在这个过程中呢,我们这个事物呢,就是说怎么去保证我们这个事物它是不受影响的,这就是我们的第三个挑战,呃,这里呢,就是我我我。呃,总结一下。嗯,就是。我们现在有三个挑战,一个就是说事物的一个原子性,就是一个事物呢,它涉及到的数据呢,就是说很很有可能就是分布在就是说多个存储节点上,那么我们就是说必须要保证这个事物涉及到所有的修改,就是要么成功,要么全部失败,就是说不可能有部分成功和部分失败的,要这种我们是不能接受的。第二个呢,就是说我们事一个事物的一个并发控制,就是说并发的事物呢,就是说他们之间呢,不能出现张读和张显,呃,张读呢,就是有个最简单的理解,就是说我们事物A呢,读读到了一个事物B,他没有提交的数据,这个是不被允许的,为什么这不被允许呢?因为事物如果,如果事物A提到读到了事物B,他没有提交的数据的话,那假设事物B,他后面他主动放弃了,他回滚掉了那4A。
89:41
他这个时候呢,如又然后就提交了,那那这种就就就相当于是产生了一个非常诡异的,就是说一个很难以理解的111种行为,所以说呢,其实如果如果如果一旦出现这种情况,就不管事物A怎么去处理,都是非常困难的,所以我们不允许这种事情出现。呃,还有一个呢,就是彰显,就是说我们呃事呃彰写它其实有很多种,有一个最简单的理解就是说事,就是说事物A和事物B,它我们都同时基于某一个数据版本,然后写入了不同的值,就是说其中一个把另外一个覆盖了,就比如说我们是数据库收到了呃两条,对对这个账户加100块钱的这个操作,结果呢,就说我们我们两个师傅都都发现,诶你本你的账户里面本来只有500块钱,然后都变成600块钱,但是其实这两个,这两个加100的操作,最后你只只加了加了一个就变成600块钱,其实你应该是700块钱的,所以说这种情况呢,是就是说我们也是不能够接受的,然后还有呢,就是一个呃调度不杀事误,就这个呢,主要是我们系统,系统给自己的一个约束,就是说我们的那个,就是说我们我们现在的这个,就是说TTC的一个新新形态呢,我们是我们的一个很重要的设计目标,就是说让业务呢,就是说在变化的过程中,就是数据的,不管怎么变,就我的业务呢,就是完,就是正常执行的,就是说完全不需要去管我现在要扩容,扩容我我可能会受到影响,或者是我的。
90:58
我的会话会中断啊这种事情,所以说呢,我们我们也要去解决这个挑战。
91:10
呃,我们这里看一下,就是说,呃,观众的一个一。111个就是说问题啊,就是呃,有一个观众提到,就是说我们这个是不是是不是类似于买locks,呃,其实呢,就是不不太一样,因为买logs呢,它其实就是说把那个英诺DB呢,换成了一个就是说logx DB,就是说这个存储引擎进行了一个替换,我们现在呢,就相当于是。把这个存储引擎呢,就是说呃,就是一个单机的存储引擎,就把它去掉了,然后换成了一个,就是说远程的一个KV系统,就是说它不再是一个,就是说是一个单机的一个,就是说操作文件的一个存储引擎,而是一个就是说对外提供KV接口的一个,呃呃,就是这这种这种。呃呃,有有有观众反应我的语速有点快,后面我就慢一点哈,嗯。
92:02
我我控制一下语速。呃,我们现在就看一下,就说我们在我们的这种就新的那种,就是说KV的那个,就是说存储里面,我们是怎么去解决这上面的前面的这些挑战的。呃,首先我们来看一下我们的这个原子性。呃,就是本就是原子性的,其实是有一个经典的2PC的一个解决,解决的就是说呃,我们其实只要就是说我们在那个就是说计算层这里呢,就是说把那个就说per commit的这个日志记下来,那那那如果当当比如说我的一个存储节点发生故障的时候呢,比如说我的,比如说我呃逻一它prepare成功了,2PREPARE失败了,那那我后面就走向about阶段就可以了,就是说我们可以在就是说计算成这一层去做一个协调者,然后把日志就是说寄到本地这种方式,但是呢,就是说呃这个呢,就会有一个问题,就是说嗯。
93:02
呃,如果这个计算层呢,就是说发生了一个就是说永久性故障,就是说它的恢复不了了,它的本地日志,那么我们可能就会出现就是说悬挂的一个失误,就是因因因为为什么呢?就可能假设我现在执行到第三步了,就是就呃就两个两两个region呢,都prepare成功了,然后这个计算成挂掉了。那而且他的他的日志是记在本地的,他再也没法恢复恢复了,那这个失这个失误就没人来推他的commit了,那他就永远永远挂在这里了,嗯,所以说呢,这种呢,就是说是在我们的设计里面呢,是不可以接受的。呃,就那那既然记在本地是不可以接受的,那我们是不是就就还有一个很简单的方法,就是说那我把我的就是说计算成的这个日志呢,就放到那个存储层去,那呃就是比如说我的那个properwork,我本本身就是说呃存储存它就是一个KV系统嘛,那我映射成KV,就是说放到呃就是说这个这个。
94:01
这个你的那个KV存储里面去,那这个其实是可以的,就是说那这样的话,就比如说这个呃,计算层挂掉的话,那我因为我的日志放在远端的这个存储里面,那么。呃,这样的话呢,就比如说我的其他的计算层呢,就就可以去不停的就去扫描这个这个这个这个这个就是说我们的这个日志的这个这个这个KV的这段范围,如果发现就是说有事物长长,就是说迟迟不提交的话,那我们就可以接管,就把这个事物接管过来,继续把它往下推进,那么但但是呢,这里其实就会有一个就是说就是会有两个问题啊,就是说这一个问题,第一个问题呢,就是说这个恢复会比较慢。嗯。因因为呢,就是说我们需要就是说其他的这个计算层节点来接管这个计算层层节点的一个一个就是说,就是说他的一个点阶段的一个推动。那么这里面就会有一个超时,就是说我们什么就是说判断它多久,就是说这个没有去推进是是正常的呢,就是说这个第一这个超时的时间不保设定,就是说你设置设定的太短了,有可能是说这个这个我的计算层节点呢,只是说只是简单的就是说夯了一会儿,然后可然后我又继续继续推,然后结果呢,我发现这个事物呢,被其他的这个这个计算成节点已经已经接管了,就是说这种事情呢,假设就是说如果一旦有这种可能性的话,就很有可能会出现一个把它往报的推,一个把它往抗密的推,那这种情况呢,就是说就是就会很有可能会出现一个就是说半提交的问题,就破坏了我们的一个原子性,嗯。
95:27
那其次呢,就是说这个这个这个方案呢,它还有一个问题,就是说,因为我们的每每一层存储节点,它都是。就是说都是一个raft,就是说你写到这里面去,他的日志要给你返回成功的话,他都至少要在一个raft的多副本里面打,就是说他要一个就是说多数派,就是说提交,那么这里的网络呢,就是说层次呢就会非常高,所以说呢,我们就。最终呢,就是说采用了一个方案,就是说我们把这个协调者呢下沉,就是说,而且这个协调者呢,他是不不记录日志的,那么这这这样做呢,就是说我们可以就是说降低这个就是说这个延迟,就是说我们可以看到就刚刚那个那个那个那个情况呢,它有八成的网络啊,这个呢,只有五成的网络,那么那么但但这个会带来一个问题啊,就是说我的这个协调者。
96:17
他在就是说他如果故障了怎么办,因为你不记日志,那么我们采用的方法呢,就是说让所有的参与者呢,就是说去把这个协调者给恢复出来,然后协调者恢复出来的时候呢,比如说我现在有一个参与者,他是处在commit不prepare状态,那么。他发现就是说呃,协调者迟迟不给他推下一步的请求操作的话,那他就会去给协调者发一个请求,然后尝试把协调者给给唤醒起来,那么协调者唤醒出来起来之后呢,他就会把所有的那个就是说呃,就这里面还有一个细节,就是说那个参与者呢,他其实要也要知道,就是说这个事物所有的其他的参与者是谁,这样的话呢,他才才能把这个协调者给唤醒出来,那么当他唤醒的时候呢,他就会把这个参与者列表告诉这个呃协调者,那么协调者如果一旦知道了这个参与者列表的时候呢,他就会广播一轮,就是说给所有的其他的协调者去广播一轮,然后知道所有的协调者所处在的状态,就能明白,就是说这个这个事物他现在的所处在的状态是是prepare还是commit,然后继续往下推进即可。
97:18
所以说呢,我们最终就采用了这种方案,就是说它既可以就是说延迟不太高,其次呢,又可以保证,就是说这个计算层呢,它可以就是说允许它永久故障。啊。呃,这个就是说我们的这个就是说分布式事物的这个原则性呢,就是这样去解决的,然后我们接着看一下,就是说我们的这个分布式事物的一个并发控制。呃,这里我们。可以看一下,就是说呃,我们因为我们是据就说底座就是说是一个就是说LMLSMLSM呢,其实我们都知道,就是说他的那个,就是说它的那个key呢,其实它分为user key和一个就是说呃时间戳,还有一个就是说呃操作类型,操作类型主要是有两种,一种是put,一种是delete,然后。
98:08
然后还有就是它的一个value字段。嗯。呃,那那我们就说要要在这个就是说。Lsm的一个基础上去做到一,就是说分布式事物的一个并发控制,那我们还需要就是说除了除了这个,就是说SSM赋予我们的一个基于时间戳的一个数据多版本,那我们还要就是说,呃,就是额外的加很多的东西,就第一个呢,就是说我们的一个全局时间戳服务,就是说他呢就是保证,就是说时间戳呢,是在全局单调递增的,呃通常呢,就是说asm的一个引擎,包括log DB和Vox DB它都是就是说是它有一个单,呃单机的一个时间戳,会可以保证单机的时间戳去递增,但是它不能去做到一个,就是说全局的一个时间戳,就不他不能保证所有的节点的那个time都是原严格递增的,所以说呢,我们首先呢,就要补齐这个,就是说我们要有一个全局时间车服务,然后呢。
99:06
我们的失误呢,就是说就是说我这里可以看到,就是说呃,就是在呃右边这边就是说我们有个失误,会有一个失误空间,就是说当他在,就是他的一个执行操作呢,就是说当他开始的时候呢,他会去拿一个时间戳。然后呢,这这个时间抽呢,就是他的start ts,就看就看看我们这个例子里面,就是说我们如果执行了一个就是说啊,A等于A加五的这个。呃,这个操作的话,那么。我们我们首先拿到一个时间抽,假设就是我们拿到了一个四,那么那么。这个事呢,就是这个这个事物的一个start PS,那么这个事物呢,它会去读,比如说在我们的数数据存储里面去读的时候呢,它读的一个规则是什么呢?就假设我们现在是要读的是A的话,那么我们会发现就在我们的存储这一块呢,就是说我们有现在有三个T,有两个呢是A,那么我们会读到哪一条呢?我们读的这个规则呢,就是说我们读到的是一个,就是说第一个小于等于这个这个这个四的,就说我们发现第一个小于等于四的是三,那么我们就应该读到的是三这个版本,就A的这个三这个版本,那么这个值呢,就是就是十,那么呃,因为我们的这个操作的是update,那么我们读到了这个十,这个十之后呢,那我们会把它加五加五之后呢,那我们就就会执行一个,就是说一个po的操作,这个po的操作呢,就会把这个A等于15呢,它不是立即写到这个磁盘上面了,就是不是立即写到这个LM数的结构里面,而是写在这个事物的这个这个它的这个私有的这个空间里面。
100:36
那么。然后然后呢,就是说我们这个这个试用呢,就是说他他他在提交之前呢,他还会去获取一个时间戳,我们这个时间戳呢,就就是一个就是说假设就它是假设是五,那么这个时间戳呢,我们定义成它的它为commit ts,那么我们拿到这个computer密TS之后呢,那么我们才会就是说就是就是进行commit commit的时候呢,我们才会把这个就是这行A等于15这个操作,把它写到这个存,就是说这个这个LM数的这个结构里面,那么。
101:11
我们可以看到就是说,呃,这个这个时候呢,这这条记录呢,就是A,它它等于15,然后他的时间戳是五,然后它就有一条它的type呢,是不。那么我们是不是有上面这些规则就可就足够了呢?其实并不是,我们可以看一个例子,就是我现在假设我现在有两个事物,事物T1和事物T2。呃,事物T1呢,它在开始,它开始的时候呢。假设事物T2他先开始,然后他他执行了我们刚刚的就是刚刚我们的例子里面的那些操作,那么他他在get的get的操作的时候呢,失误T1他开始了。
102:02
然后15天呢,他把这个A等于15呢,他写到他的自己的一个那个,就是说私有空间里面,然后。45T1呢,它它它就执行get,这个时候呢,因为45T2他还没有提交它,那所以说呢,我拿到的是一个十,那么然后然后45T2才commit,那么事物T1呢,他会它基于十呢,因为它是加五操作,他就会把这个15这个操作就是说对吧,就把这个他会他会拿到这个十,然后加五之后他就是15,然后他就会把这个15写到写进去,然后当他考虑的时候呢。这个时候呢,就会我们就会发现,那他就把这个如,如果我们允许他这样去操作的话,那么。这里就相当于是两个加五的操作,最终呢,只加了一个五,相当于就是说这个更新丢失了,那么这个这种情况呢,就产生了我们前面所说的这个脏血,那么这种情况我们要怎么去解决呢?其实可以可以看到,就是说我们在这里呢,就引入了一个叫冲突检测的一个操作。
103:01
就是当我们事物呢,就是说在提交之前呢,我们就是说在这个提交的时候,我们收到了这个事物考虑的请求的时候呢,我们先要进行冲突检测,冲突检测成功了之后呢,我们才会允许,就是说他去获取时间戳,然后最后再把这个这个这个数据写到磁盘上,就是写到我们的LM结构里面去,那么我们引入了这个之后呢,我们再来看这个45T1的这个操作,那么当他呢。就说来。执行commit的时候呢,还会再去获取一次这个这个就是说这个commit ts,那么当他就获取这个commit ts的时候,呃,不当当他去提交的时候呢,他会去做一次冲突检测,不好意思,刚刚说错了,就是说他会去做进行一次冲突检测,那么他去冲突检测的时候,他会发现,诶,那么这里。就我我我一开始的时候,我的study ts是五,就是说我拿到的时间说是五,那么我去提交的时候呢,我发现这个A呢,已经有一个就说更新的版本六,就比我的这个WTS还要大,那么它就得就是说回滚掉,就是说这所以说我们呢,就是说这种这种冲突检测的模型呢,我们称之为乐观事物模型,就是说在提交前呢,我们要去做冲突检测,就是说呃读取所有就是说我们在这个就失误提交的时候呢,这个这个put key在就是说LM结构里面的一个最新的时间。
104:19
然后跟我们的这个事物的这个WTS去比较,如果呢。呃,这个这个我们这个这个就是说我们这个呃有发现有key的这个,呃时间抽呢大于我们的starts,我们就不允许提交,反之呢,就是说我们所有写的这个数据的这个时时时间抽呢小于我们的start ts我们才允许提交。嘿。嗯,对,就就是说刚刚呢,我们通过引入那个就是说呃,冲突检测这种方式呢,就是说我们成成功的,就是说把T1的这种,就是说彰显呢,就这种情况下的彰显呢,给解决掉了,就T1这个时候呢,他不会提交成功,他会回滚掉,那么其实呢,我们还有另外一种就是说嗯,可能的调度,那这种调度呢,就是说假设我们的T1T2呢,它不再是就是说T2先提交,然后再提一再提交,而是他们同时。
105:21
提交,那么。会出现一种什么样的可能性呢?那我们可以看到就是说我我我们同时提交的话,那么可能就是说在两个线程里面对它进行进行处理,那么他们可能呃,同时去做冲度检测发现,诶那我这个A的这个版本呢,都比我的这个失误的一个开始的时间戳要小。那我就都可以去去把它给写进去,然后那我都都都去把这个comut ts获取掉,然后再把它们写到这个LM结构里面,那么这个时候呢,我们其实就发现张显他又出现了,那么我们要怎么办呢?其实我们可以结合到上面这个,呃,这个这个这个这个我们成功检测出T1要回滚的这种这种调度逻辑里面就可以发现,就是说我们的这个这三个操作,就是说冲突检测获取卡TS到提交,它必须呢,就是说是要就是说要串行化,要串行化的话,那他那那就是说他才可以就是说做到这种,就是说我T2提交的,那我T1的提交的时候呢,才可以在冲突检测发现这个就是说版本冲突的问题,然后再回滚掉,那么。
106:26
这这这种呢,就是说啊呃,在单机的情况下呢,其实它是没问题的,因为它可能是一个很小的一个原子性的一个操作,但是如我们在分布式事物里面呢,就是说我们这个时间抽呢,再不不再是一个单机的一个原子的一个自针就能获取到的,而是就是说可能是需要去一个全局时间,时间从服务器里面去获取,那么这这个这里面就会有网络的开销,就是说这种这种情况呢,就是说我们把这个变成一个原子操作呢,那对性能的影响就会变得不可以接受,那么我们。要怎么怎么去处理这种这种情况呢?呃,这这个时候呢,我们先按一下不表,我们再看另外一个问题,就是说当我们的输入呢,他设计。
107:09
多个节点,就是说呃,我我们还要考虑一种,就是说怎么样去统一这个就是说就是所有节点的一个时序保证一致性读那我我们再看看一个例子,就是说假设我现在不是这两个失误呢,就是一个是转账,一个是查询总账的一个一个一个操作,那么我我可能会出现就是说呃,我这个T呢,他会先对A这行呢加五,然后。哦不对,A进行减五,然后再对B进行加五,就是说相当于是我把五块钱从A呢这里呢,转到B上面去,那我一个执行的步骤可能就是我首先在第一个节点上对A呢,就是说进行的减五的操作,然后呢,再去在B上,就是说去执行一个加五的这个这个操作,那我我另外一个事物呢,他可能就会出现这种情况,就是说我先读了。
108:04
第二个节点发现B是十块钱,然后再去读A节点是五块钱,那我读到的就是15块钱,但是其实我们转账的这个过程中,钱并没有减少,一开始是20块钱,那我转完账还是20块钱,那么这里面其实我们就产生了一个就是说分布式事物的,就是说非一致性读这个问题,那么。啊,这那么结合这个问题呢,我们还要考虑就是说什么问题呢?就是说我们为了分布出事物的一个原则性,那么我们在这个里过程中呢,还还引入了一个两阶段提交,就是说我这个commit,这个过程中呢,其实他也不是就是说直接把数据写进去,他会要先prepare prepare成功了之后呢,他才会去commit,所以说呢,我们还要考虑一个问题,就是说我们前面的这个分布式事务的这个两阶段,然后去怎么去跟冲突检测去结合,最后呢,我们还要考虑就是说我们前面的那种,就是说呃,提提到过程中就是说,就是说我们的一个就是说如果假设我们在这里要原子创新化的话,那我的性能要去怎么去结合呢?就是说基于这些操作呢,我们。
109:04
就提出了一个就是说我们的一个事,呃,事物并发的控制的一个就是说算法,就说我们是怎么去把这些所有的这些点都结合到一起,然后去解决这个,就说我们分布式事务并发控制的这个问题,首先呢,我们把两阶段的这个过程呢,跟乐观事物冲突模型去结合起来,就是说我们在prepare的时候呢,去进行写写冲突,大家可以看到就是说我这里是一个协调者,那当我收到就是说比如说我前面这些get操库的操作执行完之后,那我的计算层节点呢,就会发commit请求过来,那么我们的携调者节点呢,它它会把这个就是说circleq里面的commit呢,变成一个proper操作,那我会在。呃,Prepare阶段去做这个冲突检测,那我们是怎么做的?首先我们在prepare这里呢,去获需要去获取一个prepare ts,那那么然后然后呢,我会对这个数据呢,就是说加上一个proper rock,那如比就比如说这个A,那我我我put a的话,那我就要对A进行一个proper lock,那假设我现在有个并发的事物呢,他也在执行这个操作,那么他就会发现这个A呢,就是说他已经被加上了这个proper lock,那其实这说明什么呢?就说明这两个事物呢,这两个并发的事物呢,操作了同一行,那所以说呢,他就需要去去回滚掉。
110:25
所以说呢,我们就在prepare阶段呢,就是通过这种方式呢,我们在prepare阶段呢,就。就只就已经把就是说这个活跃事物的活跃并发事物的冲突检测给做完了。那但是呢,这里其实还会有一个问题啊,就是说我并发的,就是说同都是活跃的这种并发事物,就是说啊,我成功检测出来,但是还有一种可能就是说假设,就是说我另外一个思路,他其实他其实在你加这个pro rock之前呢,他已经把这个pro rock加上了,但是呢,他还继续往前推,他推的非常快,他他不仅不仅不仅就是说加完了,然后他还把数据写写写到这个磁板里面了,然后最后把事物就成功的执行完了之后呢,他还是最终要把这个proper work给释放掉,那你这个时候呢,就是说这个时候呢,这个时候呢才去把这个proper work给。
111:14
加上那其实这个这个这个这个情况叫什么呢?我们我们称之为就是说活跃失误和已提交事误的一个冲突检测,那这个过程中呢,我们我我们是在哪里做呢?其实其实就是就比如说我我们我们这个流程里面,就是说我们的这个properwork加成功了之后呢,我们就还要进行一次冲突检测,这个时候冲突检测呢,就是说就是去解决这种情况呢,就是说我们去看一下,就是说呃,我们就LCM数结构里面的这个这个事物有没有跟我就是说这种已提交的事物有没有跟我是并发的,如果有的话,那那其实我也是不能提交的,因为一旦我提交就产生了一个就是说彰显,那所以说呢,也会普失败,一旦普失败的话,那协调者就会把这个事物推向报的操作,但是如果所有的节点都pro成功的话,那么他就会把这个就说协调者就会把这个这个操作的就是说推到就是说commit commit的时候呢,我们会拿一个commit ts,那然后呢,就然后就会就是说把这个数据就写。
112:15
然后这个LM lock里面,一旦一旦我们把这个就是说这个这个数据写到LM结构里面的话,我们就可以把前面的那个prepare lock给给给解除掉,因为我的思维已经提交成功了。嗯。嗯,就是说我们就通过这种方式,就是说就就就这就是我们的一个,就是说我们思路并发控制的一个算法,那我们再看一下,就说我们这这个算法是怎么去解决,就是说我们刚刚说到的,就是说在两个节点上去做一次性读的这个问题呢,其实可以可以回到这个过,就是说我们我们套到我们的这个算法里面的话,我们发现就是说当我们。在提交的这个时候呢,我们我们我们正在准备写数据的时候呢,其实我们在这个这个这个这个节点中已经把这个paperwork给加上了,那么当我们这个就是说TR去读的时候呢,其实去去在B节点上去读的时候呢,他就会他就会遇到这个主,这个就是说我们去读的时候,他会遇到这个主色主塞的那么。
113:13
当这个主社会到什么时候,就是说结束呢,就是说他会。他会等到这个就是说这个15完全提交成功了之后,那才会允许你去读,那那这个时候呢,就是说当这个T完全提交成功了之后呢,那我这个T2读到的B呢,就是15,然后接着再去读A呢,他会发现它是五,那加起来就是20,所以说呢,我们就是通过这种方式,就是说把这个就是说分布式情况下的一致性读给解决掉了。嗯。啊。这里我们看一下就是说。观众的一个问题啊。呃,有一个观众提到,就是说我们这个就是说我们这个分布式并发控制算法跟谷歌的协议有什么异同呢?啊,这个问题就就比较好一看,就是对这块有过研究的一个同学才可以问出来的啊,就是说跑这个协议呢,其实就是谷歌在big table上去让客户端做到。
114:19
呃,就是说呃,我们这个分布式事物并发控制的这这种这种这种算法,它不光是做到分布式并发控制,它还可以做到就是说呃一个就是说原子的提交,但是呢,就因为它是在客户端去做这个过程,就是说呃底层呢,它是一个big table,他没办法去给他提供一个就是说一个其他的保证,所以说呢,他就必须把那个就是说我们中间的一些lock操作,就是比如说我们的proper lock这种这种内存中的操作呢,就变成一个就是说。呃,数据项写到DV里面,那么这个过程中呢,其实就可以看到,就是说它的一个就是说开销,就是说你要去持久化的一些,就是说work这种这种信息,那么它带来的代价就必定会更高,所以说呢,从理论上呢,就是说我们这套算法呢,其实可以在性能上超越poul,就是说呃,这也是我们就是说不去用po的一个重大的原因,因为我们的性能其实是非常关键的。
115:13
嗯。呃呃,接下来呢,我们呃看一下就是说。呃,就是说我们的一个就是,呃,就是数据调度,他就不杀,怎么去做到,就说我们不去影响这个这个事物。呃呃,大家呢,其实可以关注一下,就是说我们腾讯云的这个数据库视频号,就是我们后续呢,还会有非常多的,就是说这种技术干货呀,包括论文解读,就是说持续在这里进行分享啊。呃,那我们先看一下,就是说我们这个就是说我们在TC口这个这个就是说这种新的这种架构下去,怎么去做到这个,就是说这个数据调度的呢,其实我们的数据调度呢,就是说因为我们的数据是分段管理在region中的,那我们的数据调度呢,其实就是通过region的一个调度。
116:04
来完成。那我们region调度呢,其实主要就分成就是就是就是三个操作,一个就是region的分裂,就是说当我们的这块数据就越来越大,越来越大,越来越大的时候,那我们其实就要分成两个两个region,那么其呃然后呢,就是region的迁移,就是我们就通过region的迁移来做到,就是说这个数据的一个搬迁,最后呢,就是就是一个数据的一个切主,我们通过这种主动切组,就是说我们有一个管控节点,它会主动去发现某些节点上它的就是说立的非常多,它的负载比较重,那我们就会去发一些主动切主的这种操作,然后达到一个就是说呃负载上的一个动态均衡,就是说我们的region的调度呢,就主要是这三类,那么首先来看一下,就说我们region的分裂。嗯,这里这里呢,可以看到这个示意图,就是说呃乐一呢,它就就比较大,就是说数据可能有热点,就是说都集中在写这一段范围,那么当我们大到一定境界的时候呢,我们就会就是说会找到一个就是说嗯分裂点,然后就把它就是说分成就是说。
117:00
这最短范围分成两个部分,然后就会产生一个新的规置,那么这个分类点是怎么选取呢?其实就是利用一些,就是那种就是估算函数,就是去看一下,就是说呃,这个最段范围内LM数它的那个就是说它的那个s table有多少个,就每一个就是说它的一个估,就是说一个它会有一个,就是说原数据,它原数据就记载着这个table的一个大小,就是说然后我们通过这种就是比较粗糙的方法呢,就估算出来这个region它。这这段范围它大概有多大,然后然后我们就是说一旦我们可以估算出这一段范围有多大的话,那我们其实就可以随意,就是说我们可以随机找一个这个这个点,然后去看一下,就是说这个路径中这个以这个点为分裂,它两边的这个数数据量大小会不会是比较接近,如果不不行的话呢,那我们就采用二分的方法,就是说就就是就出二分,直到我们找到一个分裂点,就是说让这个region两边的这个大小呢,是是比较接近的情况下,那我们就会把这个这个就是这个key就当成一个分裂点进行进行分裂,然后呃,当我们就是说分裂成功了之后呢,那我们。
118:03
那我们可能就会就会就是说对这个region进行迁移,就是说我们把这个region就是说比如呃,搬搬到其他的节点上去,那我们是怎么去搬的呢?其实我们就通过一个loft的一个增减副本方式可以看到,就是说呃,我们六群二呢,就是说在在这里有三个副本,然后我们新加入的一个节点,那我们新加入这个节点呢,首先呢,我们就会。在就把这个微二变成一个四副本的节点。然后再。嗯,再把它就是说把一一个副本,就是说从原来的那个就是说节点里面删掉,然后就变成一个就删副本,但是这样的话,其实我们就通过了这种方式呢,就把这个RADIO2的一个数据呢,就搬迁到了这个新的这个存储节点上面去,然后我们持续执行这个操作,那么我们就会就发现就很多的数据呢,就包括搬到了这个呃,新的节点上面去了。呃,当当时当我们搬完的时候,我们可以发现就是说有这种情况下呢,就是说新的这个节点呢,它都是一些呃flow节点,它都不存在独流量的,那么其实这种这种这种并不能就是缓解,就是说之前节点的就是说他的一个就是说比如说他有读写热点的这种问题,所以说呢,我们最后通过一个就是说主动切走的这种操作,就是说呃解决了这个,就是说这个读写热点的这种问题,那么在这个就过程中呢,我们其实有一个就是很大的约束,就是说我们的这种业务层,他不能感知到服务的中断,那不能感知到这个服务中断的,那有一点就是非常重要,就是说我们不能去把这个,呃就是说这个事物给杀掉,那么我们事物的就跟这个,就是说,比如说我们前面谈到的这个论的分裂啊,切煮呀,还有。
119:38
还有那个搬迁呢,他就是说他是并发执行的,那么。哦,我我们可以看到就是说魔的调度呢,就他他的迁移呢,是通过rap的增减副本的方式进行的,那么他这个时候呢,他跟那个提供服务的leader呢,它是没有直接关系的,那么这个时候呢,其实它这个并发是是完全没有问题的。
120:01
但是呢,我们可以看到,就是说分裂和切阻呢,它都是在leader上面,就是说会会执行的,那么那么这个过程呢,它跟事物呢,其实就是说它有不可避免的一个并发,那么我们其实其实就很有重要的一个问题,就是说要让我们的事物的这个生命周期就跨越这个分裂和切除,就是说如果如果我们不能做到这点的话,那么我们分裂和切除他就很有可能就是说要把这个事物杀掉,或者是要等这个事物结束的,那这种呢,就就就不可避免的,就是说会会会有两个问题,一个就前一个呢,就是说会引起业务他的一个感知,他的事物失败了,会话被中断了,后一个问题呢,就可能就是说我要进行,就是说因为我要等这个事物,就是说旧的事物结束,那新的事物源源不断的来怎么办,那我就只能就是说禁止新的事物开启这种方式,那这样的话其实也是进行,那么业务还是会有感知,那所以说呢,我们这里其实有一个很基础的问题,就是说要让我们的事物的生命周期跨过分裂或者是切除,那么如如果能做到这一步的话,那我们。
121:00
才可以就是说去谈,就是说呃,业务层它就可以不受到我们这个这个数据搬迁的这个影响,那我们是怎么去做到的呢?其实我们可以看到,就是说我们这里举了个例子,就是说我假设这个45T它。他写了两个两个数据,一个是A一个是H。然后,然后它在执行这个put等于H的过程中呢,就是说发生了分裂,那么分裂分裂的点是是哪呢?是G,那么我们可以就会知道,就是说我们会要把H呢,就是说搬到一个新的路径上面去,那么。那么我如果我们执行的这个这个。这个这个班的操作呢,这个时候呢,那么我么我们再接着去执行get h的话,那么。我们其实就。哦。嗯。对,就就在这里的话,我们比如说我们get h的话,我们就会去这里读,就是说那么这个时候呢,因为这个时候呢,这个事物呢,就之前的事物呢,只是依附在这个六一上面的,那么这个log al尔法呢,就是说他没有这个事,这个这个事事物的数据,那么这个时候呢,变成H过来呢,他会他会去磁盘上读,那么他读到的呢,是这个,呃,就是说磁盘上它的H呢是二的值,那么其实呢,我们刚刚就把那个这个这个H等于五这个值写进来了,但是我这个时候读到的呢,是H等于二,那这个显然就出现了,出现了问题,所以说呢,我们第一步呢,就是说我们分配的时候呢,不光要搬迁,就是说我们的那个,就是说呃,磁盘量的这个。
122:31
这个LM的这个这种数,就是说我们事物的内部的,就是说这种这种事有的这种数据,就是说我还没有提交的时候的这种这种数据呢,也要就是说搬迁,所以说呢,这是我们第一步就是说呃,微云上活跃子私物的私有数据在分别的时候也需要搬迁,那么呃,我们刚刚刚刚呢,就是说这个例子中呢,就是说我们,嗯,是是就是说在这个过程中呢,就是说它它在执行的这个put等于AH等于五的这个操作的时候呢,它后面还有一个就是说get h的这个操作,假设我们没有呢,就是说假设我们刚刚执行完这个put。
123:07
H等于五,然后我的事物立马提交的这种情况呢,就是然后我们再来看一下这个例子,就是说我们现在put h等于五这个执行了,然后发生了分裂,这个过程中,这个事物跟这个分裂并发了,然后我立马就说去提交,那那么这个时候呢,其实我们可以看到就是就是这个事物本身呢,他其实一直知道的,就是说,比如说我们这个计算层在执行这个事务的时候,他一直对接的都是这个陆俊一,那么最后呢,他提交的这个操作呢,也是交交给陆俊一,但是在这个过这个这个过程中呢,其实我们知道就是说这个事物呢,它其实已经变成了两个有两个参与者,参与者进来了,那。那那但是计算层呢,交给这个这个这个这个这个这个协调者的时候呢,他其实告诉他我的参与者只有只有一个,就是说六一,那么如果我只把这一部分,就是说这个数数据就说提交了,那么相当于是我的这个H等于五的这个操作。
124:00
可能就丢失了。那么。那么这这种情况我们要怎么去。具体呢,就其实就我们在这里的操作呢,就是我们在这个六据一上呢,其实就会他他在分裂的时候呢,我们就会对这个事物就是说记录一些信息,记录什么呢?就是说我这个事物呢,它分裂了,它有一个应问语是例卷二,那么当我们这个这个这个计算成的直接去提交这个事物的时候呢,他哪怕他的这个呃,参与者里面呢,只有这个瑞俊一,那么其实我也知道,就是说我的有一部分数据已经传到六卷二上面去了,那么那么就是说呃,我我这个事物呢,就是说他。他就会告诉这个携,呃,携带者就是说你还少了一个,就是就是参与者六二,然后你去把这个六二补齐,就补到你的参与者列表里面,然后再去执行这个两阶段提交啊,就这个就是说我们这个这个就是说解决这个问题的一个啊,就是一个方法,呃在这个过程中呢,我们可以用持续图可以看的更加清楚,就是当我们去假设我们一开始我们的这个参与者列表里面只知道了这个逻一跟链二,那么我们这个协调者去提交的时候呢,就这个参与者列表里面呢,只有一跟二,那么他就比如说我们是,但是很不巧的是,就是说我这个这个事物在提交的过程中呢,六军二分裂了,它分配就是说分配出了六件二跟六件三,那么我们在这个呃,提交的过程中呢,就会遇。
125:26
就就是说在六一上他的purpose就是OK的,然后当这个prepare请求发给692的时候呢,他就会告诉就是说发现诶我分裂了,然后我的另外一个就说我的那个新的,那那那一半呢,是是六径三,那么然后然然后他再去比较一下这个路径三在不在这个这个这个这个列表里面,诶发现这个六径三不在这个参与者列表里面,那他就会告诉这个协调者,就是说呃呃,我的这个play请求呢,就是说没有这个参与者那么。那么这个时候呢,这个携带者呢,就会把这个参与者三呢,加到他的这个列表里面,然后再再发起一轮普票广播,那么这个时候呢,因为因为三已经在这个这个这个这个这个里面了,那么当六二上这个思路去讲校验的时候,他就会发现,诶,我这个分裂的这个新的这个region呢,已经在你这个上面了,那其实这个教练是OK的,那么这一轮之后呢,那么我们会发现三个节点的这个普派操作呢,都。
126:21
嗯,都已经成功了,那么我们继继续去往下执行这个commit请求就可以了。呃呃,刚刚呢,我们的那种情况呢,是一种比较理想的情况,就是说当我提交的时候呢,分店已经完成了,但是还有一种可能性,就是说,呃,我这个就是说提交的过程中呢,这个分裂还正在执行中,他还没有完全就是说执行完,我并不知道这个分裂的结果是成功还是失败,所以说呢,在这个过程中呢,其实我们也会把这个就是说我正在分裂的这个这个这个这个这个过程记录下来,就是说当我这个时候收到了普请求的时候呢,我就会告诉协调者,你从你一会重试吧,因为我正在分裂中,然后协调者就会去重试这个过程,嗯,直然后直到呢,就说我这个分裂完成了,然后那么。
127:05
那么我会就会走到前面的这个流程里面,就是说我的这个参与者,就假设我们分裂成功了,那么那么我们就会让携带者去补齐这个参与者这个操作,然后最终呢,通过这种方式呢,我们就解决了,就是说这个有调度的过程,跟事物并发的这个这个这个操作,嗯。呃,好,那个今天呢,就是我的这个分享呢,就是呃就呃就结束了,那个我们再看一下,就是有没有观众的一些问题啊。呃,有一个同观众问到呢,就是说rap通常是单数副本,如果增减副本过程中容易出现双数副本的情况的话,是否?能一一定保证不出现双数副本leader的迟迟无法选举出来的问题,其实呢,啊,这个这个观众呢,其实也是非常敏锐的,他发现了就是说这个这个就是说我们双数入本中的一个,就是说呃,Timing的问题,就是假设我们现在是双数入本,而且通常就是说,比如说我们去替换这种,比如说我们有一个呃机器已经故障了,那我们现在加入另外一个新的机器的话,那么很有可能其中有一些呃三副本其实已经变成两副本了,那么我们把这个新的副本给它加进来的时候呢,把新的机器给加进来的时候呢,那么是呃,我们就会有一个四副本,但是其中有一个副本已经挂掉了,那万一这个加加进来的这个新新的这个机器呢,又故障了的话,那就变成了两个节点故障,那其实就这个时候呢,它就会。
128:38
很有可能就会出现,就是说呃刚刚谈到这个问题,就是说呃双数副本一半挂掉了,那其实即使你有两个副本活着,你也不能去提供服务,那其实这个问题呢,我们已经内部就是说最新的版本已经正就说已经解决掉了,我们用的就是一个就是说呃呃joinnior joinni,呃那个叫鞋一致性的这种这种方案,就是love的那个论文里面已经提到的,就是呃成员列表里面,他有一种就是嗯,就是我我我会就是说把那个就是删掉的那个副本跟呃提交的那个就是新增的副本,就变成一个logo,就把它给加进去,然后这个时候呢,就是他其实会有一个旧的杀副本跟一个新的三副本,它其实都会都会同时生效,那么这个时候呢,其实如果它挂掉了两个节点,那么它在旧的配置里面挂掉的也是一个节点,新的那个配置里面挂掉的是一一个节点,那这种情况呢,其实它的可用性还是还是继续保证的,就是通过这种方式呢,我们可以就是说做到一个就是说呃,可用性的一个最大化,嗯,好,那回答完这个问题呢,就是我们。
129:38
最后的一个抽奖环节,嗯,我们第二轮的奖品呢,就是说是五个那个怪企鹅的记U型。呃,寄一年优行者,呃请中奖的同学呢,就是说呃记得填好那个联系方式和邮寄地址,方便我们的工作人员呢,在后后续的那个就是说邮寄的这个过程中呢,就是说寄送奖品,中奖的结果呢,我们在会在今天的晚上的11点呢,就是公布,然后呢,我现在再给大家一点时间,就是说我们倒计时十秒,就是说十九八七六五四三二一好。
130:17
那嗯,在节在直播的最后呢,我非常感谢就是说各位参与到我们的活动中来,欢迎大家呢,就扫描我们的二二维码,就是关注我们后续更多的这个活动,我们下期再见。
我来说两句