当前位置: 首页 > 科技观察

京东云总监带你领略分布式计算的精髓(含视频)

时间:2023-03-14 23:54:44 科技观察

1953年,AbeGrosch提出Grosch定律,即计算机性能会随着成本的平方增长。1965年,戈登·摩尔提出摩尔定律:当价格保持不变时,集成电路上可容纳的元器件数量大约每18-24个月翻一番。现在随着电脑的普及,闲置的电脑越来越多,即使电脑开机,CPU的潜力也远没有得到充分发挥。互联网的出现使计算机系统连接和调用闲置计算资源成为现实。结果,分布式计算变得流行起来。分布式计算难吗?难的!所以,我们需要名师指点!下面要介绍的课程将由京东云资深总监授课,赶快阅读吧!本次直播课程由京东云高级总监郭丽静主持,从数据库基础知识入手,从实际应用出发,深入剖析从单机数据库到分布式数据库的技术发展与迭代。同时,他理论结合实践,为大家讲述了企业选择数据库服务的黄金法则以及京东云在这方面的应用实践等干货内容。课程概览本课程的分享内容更多的是关于数据库服务的演进史,重点关注从单机到分布式的转变从何而来,如何从单机数据库改进,实现分布式数据库服务。以下是郭立静先生分享的全部内容,希望能给开发者带来更多的帮助:从单机到分布式,数据库服务的演进史很简单。在许多情况下,一项技术甚至产品最初是从一个非常简单的想法产生的。比如2019年,我们在DB-Engines排行榜上看到了两个熟悉的身影,MongoDB和Redis。有趣的是,MongoDB属于DocumentDB。如果我们转过头来看DocumentDB-Engines排行榜,MongoDB排名第一,以绝对优势“击败”第二至第十名(第二名只有56分)。在DB-Engines中,Oracle和MySQL的分数非常接近;但是在DocumentDB中,MongoDB有400多分,而第二名可能只有100多分。同样,Redis在K/V领域的得分特别高,有146分,第三名是MemcacheD(第二名是AmazonDynamoDB,56分)只有28.7分。所以这两个数据库在各自专业领域是两个排名特别靠前的数据库,相互之间的时间也不是特别长,不到十年:Redis出现的时间比MongoDB早,Redis出现的时间是2009年,MongoDB也是2009年左右出现的.为什么Redis会出现并成为K/VDB中排名第一的数据库?其实在Redis出现之前,已经有一个叫Memcached的K/V数据库,早在2003年就发布了,一个版本最初是用Perl写的。***用C语言重写。在Redis出现之前,Memcached一直是K/V数据库的老大。为什么2009年Redis出现的时候Redis就取代了Memcached?直到今天,我们将Redis用于大多数缓存。即使是刚入行的同学,也没有听说过Memcached这样的数据库。Redis在这个过程中做了什么?事情比较简单。从设计理念出发,改变了Memcached原有的存储结构。之前,一个Key对应一个String,然后Redis把String变成了structured的结构化存储,也就是说Redis可以支持一些结构化数据,包括List,sortedset,hashes等,为什么这么小的改动就可以让它获得这么大的优势?关于这一点,我们还是要回到Memcached。假设我们要自己设计一个缓存系统,设计目标和Memcached一样,过程中需要设计一个KeyString缓存系统,那么这个缓存系统可以提供哪些服务呢?更进一步,当存储对象为String时,我们可以对其进行哪些操作呢?可以想象,在一种编程语言中,以C++或Java为例,一个字符串可以设置一个字符串,获取一个字符串,当然也可以删除一个字符串。除此之外,我们还可以对字符串做一些其他的操作,比如append、prepend等,即在字符串的尾部和头部添加一些内容,甚至替换整个字符串。当然你也可以做insert、erase、trim、find、substr等操作。在设计过程中,不妨思考一下为什么Memcached不支持insert、find、substr等操作?这其实是一个非常有趣的话题。理论上Memcached在修改Memcached的源码后可以支持这些操作,包括这些函数和调用,但是不支持的原因可能更多是出于效率的考虑。比如在Memcached支持substr或者find操作的过程中,浪费了Memcached服务器的性能。因为find可以把整个字符串传到本地再做find,substr也是一样,其实都是性能的问题。当然Memcached还可以提供更高级的操作,比如add或者一些gets操作,也可以做incr/decr,一个数的原子加减。如果研究一下Memcached的整个发布历史,它是2003年发布的一个版本,前期的支持工作非常有限,所以后续的高级功能是逐步加入的。再看Redis,可以支持的数据结构非常多,包括Strings、Lists、Sets、Sortedsets、Hashes、Bitarrays,还有HyperLogLogs、streams,streams是5.0的,最新的版本甚至可以支持一些顺序数据.纵观整个迭代过程,Redis最初的简单想法是能不能多支持Strings的结构和存储结构。从这个想法出发,会逐渐发展到支持的数据结构越来越多,操作类型越来越多的情况。以C++为例,一个List操作支持pop/push,也可以支持在List中间插入/擦除。对于Redis,除了常见的操作外,我看了一下Redis的整体发布历史。一开始也支持一些比较简单的操作,比如pop/push;随着时间的发展,越来越多的高级功能都建立在普通操作的基础上。比如BRPOPLPUSH的作用就是从一个List中弹出一条数据,插入到另一个List中。这是一个比较高级的功能,但是这也是用户发现自己需要这种场景后才添加的项目。.让我们再次探索MongoDB。MongoDB的“工作”其实和Redis有些相似。可以认为Redis是用K/V结构来代替类似JSON的类型的Strings,而JSON可以支持的数据结构有很多。MongoDB体现的功能相似度非常高。之前设计数据库的时候,如果是关系型数据库,需要一开始设计Schema,然后做一个DDL操作。当需要增加或减少某列时,上述操作不是很方便;特别是表格很大的情况下,操作时间会很长。随着业务的发展,是否可以使用JSON代替原型MySQLSchema?从这么简单的想法出发,虽然MySQL或者关系型数据库还是以Schema为核心,但是MongoDB使用的是Document,也就是JSON的格式。作为核心构建整个数据库的功能和生态。可以看出MySQL常见的SQL语句在MongoDB中的命令长度是不一样的,因为所有的命令都与JSON格式相关,底层的存储结构也会因为需要保存JSON格式而发生很大变化。这部分我想表达的观点是,很多数据库和技术产品的演进其实是有迹可循的。主要目的是设定解决问题的目标,进而完成底层数据结构的修改。在一定程度上影响了产品的功能。例如,MongoDB已经很长时间不支持事务了。不是不想尝试支持,而是要看底层存储结构的存储引擎,不能支持事务。同样的,如果你探究一下Memcached和Redis的内存管理设计,你也会发现Memcached的开发者或者社区也希望支持类似Redis的功能,但事实上他们注定无法提供这样的服务,因为底层存储结构。2分布式从何而来?为什么会有分布?主要原因是在信息爆炸的时代,业务量逐渐增大,单机数据库已经不能更好的满足需求,自然要寻找一些可行的解决方案。这里的方案可以分为两种,一种相当于表面方案,操作比较简单,涉及客户端方案和统一代理方案,比如代理方案。相比之下,底层方案可以分为三类。第一类是分布式块存储方案,第二类是计算存储分离方案,第三类是另起炉灶。首先,客户端方案可以用一个叫做TDDL的开源项目来代表,方案思路比较清晰。如果我们需要自己搭建一个分布式系统,把分布式方案放到客户端,最重要的就是“告诉”客户端SQL语句要链接到哪个数据库。毕竟不同的数据存放在不同的机器上。.对于客户端的解决方案,更重要的是与后端的一些连接以及如何解析SQL语句。第二种解决方案是Proxy解决方案。与客户端方案相比,代理方案的开发难度略高,但思路还是很一致的。例如,在用户表中,用户表的组成部分是ID。我们分发ID的分布式密钥。在查询具体用户ID的时候,其实是有一个Proxy的。如果用户ID为0,则知道后台存在哪个MySQL0。因此,对于Proxy来说,解析具体的SQL语句是非常重要的。在这个过程中,它必须有自己的路由来完成识别。客户端解决方案和代理解决方案有什么区别?不同之处在于客户端解决方案的开发相对简单。在JDBC或者需要客户端调用时,客户端不需要解析SQL语句,很容易完成引导。对于Proxy方案,需要兼容原来的MySQL协议。如何建立MySQL连接,如何维护与后台的连接,是比较难的。但是相对来说,Proxy方案有很多限制。无论是client的表面方案还是Proxy的表面方案,都对SQL的使用要求比较高。比如有些join很难支持,必须在业务方同意的情况下使用。另外无论是客户端方案还是代理方案,整体架构都比较相似。比如Proxy方案,涉及到前端如何连接客户端和后端的Backend连接,还要和实际提供MySQL服务的后端保持连接。这是两个连接的管理。了解之后,一般整个Proxy的设计都会是无状态的,因为路由信息是保存在Proxy本地的;但在路由方面,必须有一个相对的路由管理中心进行分发和变更控制。业内大部分的代理设计,大家会发现proxy代理方案的架构设计非常相似,区别在于工程质量。另外,Proxy方案的缺点是分布式事务怎么做,没办法保证顺序。通常在分布式的情况下,其实很难保证每个节点上的事务执行都按照我们想象的顺序进行。说完了表面的解决方案,我们还需要谈谈更深层次的底层解决方案。从表面上看,客户端方案和代理方案都没有改变MySQL底层的整体协议,也没有改变数据库的原生服务。可以认为MySQL的底层代码完全没有变化。目前已知三种主要的底层解决方案。第一个方案是块存储方案,包括SAN方案,到云上还有云硬盘方案,都是同一种类型。但是如果真的要做数据库的解决方案,目前主流的思路是计算和存储分离。为什么要将计算和存储分开?主要原因有:目前网络延迟一直在降低,带宽一直在增加,从我个人的工作经验来看,未来可能会有更大的网络带宽;但与此同时,磁盘IO的吞吐量并没有像网络那样快速增长。另外,存储虚拟化有利于降低成本,分布式存储有利于提高IOPS。如果在一台机器上做Raid,它的性能会比单硬盘好很多;如果用分布式系统写,它的IOPS其实会更高。目前业界有几个比较知名的计算存储分离方案,最著名的就是亚马逊的Aurora。为什么极光会选择计算和存储分离?关于这一点,我们需要探究一下亚马逊当时的RDS方案是怎样的。AmazonRDS是他们的RealtionalDatabaseService,整体数据存储在本地磁盘/EBS上。我们可以看到整个IO写入链比较长。需要写数据到磁盘,binlog到磁盘,redolog到磁盘,整个binlog两边都要同步。最后,EBS数据一定要妥善备份到云存储中。(这只是备份,与实时写入无关)。由于链路比较长,整个EBS的实现,EBS是一个分布式的快速存储,本质上是多副本的。在多副本的情况下,EBS还需要在远端同步整个数据,所以Aurora的设计目标就是思考是否可以相应的将存储和计算分开。出发点是数据库存储引擎能否与分布式块存储融合,形成一个新的存储引擎。另一种解决方案是F1/Spanner解决方案。什么想法?搭建分布式系统,如果兼容MySQL比较麻烦,可不可以另起炉灶,搭建一个新的分布式系统?它的思路很简单,就是重写一些SQL,所以当F1/Spanner不兼容MySQL的一些协议时,会引入新的分布式事务管理,将SQL拆解成一些K/V操作结构,对于这种对于解决方案,SQL兼容性是一个长期且耗时且最接近的过程。主要是难以兼容现有的生态。但是如果是新业务,这个分布式方案是没有问题的;如果是老业务,有自己成熟的SQL,用起来就比较困难。可以看出,对于一个MySQL服务来说,其实有两部分,一部分是Server,一部分是Storage。存储标准架构是redologplusdata,是InnoDB的一种结构。现在InnoDB已经成为了MySQL的标准,大家都在这样做。关于主从同步,采用binlog拷贝的方式,将binlog拷贝到slave端,slave重放binlog,slave才有完整的数据。这是一种传统的数据库组合模式。对于MySQL,它的数据流会是什么样的?第一,如果是针对事务或者SQL语句,会写入大量的redolog。第二步,会写入binlog。binlog以后会做半同步,同步到slave,返回一条消息。这时候就可以进行整体commit了。整个数据流的示意图,主从之间采用了整体的binlog复制方式。如果你想搭建一个分布式系统,出发点是不能把相同的数据放在同一个分布式系统中,你需要做什么?我们发现,如果计算和存储是分开的,所有的存储都放在一个分布式存储系统中,主从读取相同的数据。其实不需要binlog。这个比较容易理解。Binlog是用来传输具体数据的,因为数据是放在一起的。3计算和存储分离的好处是分布式存储的存储空间会比较大;还有一点,如果要增加一个新的slave,在MySQL的主从复制中,一般是怎么增加一个新的slave的?只需要创建一个空白的slave,慢慢的从combination开始同步数据。一句话,用binlog来同步数据;但是如果整个数据量比较大,需要很长时间去创建一个新的slave,或者在备份的基础上重建一个新的Slave,然后复制数据库备份。在此基础上追新日志,不管怎么加一个节点,时间还是要以分钟为单位,至少以10分钟为单位。但是计算和存储分离之后,新建slave的时间很快,备份数据也会快很多。因为对于传统的主从系统的备份,其实是需要文件系统备份的。文件系统快照也可用,mysqldump也可用。本地文件需要传输到云存储;在分布式存储系统中,这个任务可以转移到底层系统。当然,数据的强一致性有赖于底层存储来保证。如果计算和存储分离,整个高可用交换机会是什么样子?对于之前的MySQL来说,一次主从切换其实比较简单,因为主从是两个独立的存储和计算,他们之间没有任何关系,主切换到从,顶多binlog没打完后退;但是整个计算和存储分离之后,还是有一些变化的。比如第一个变化,我们可以看到对于一个传统的数据库,它的redolog是一个循环文件??系统,可以循环使用三个redolog;如果是在存储分离和计算分离的环境下,它的Redo日志基本上是设计成按编号排序的。主从切换后,logbuffer和bufferpool可能需要一点时间来重建它的两个bufferpool。因为在传统意义上,传统的MySQL主从切换需要根据日志稍微重建bufferpool。就备份而言,基本上变化比较大。整个备份会基于底层的块存储:可以备份整个页面的部分数据;另一部分需要对Redolog进行增量备份,这样一个可以快速完成。数据库的备份。事实上,在云端备份一个数据库比搭建两台物理机做备份要快得多。为什么?因为在云分布式系统中,做备份的时候,不是一台机器在备份,因为是存放在上级不同的机器上。对于一个新的slave,如果我们在云计算和存储分离的情况下创建一个新的slave,那么创建一个新的slave的速度会比传统的方法快很多,因为整个数据块已经存在了,而且可以读取直接就可以了,不用再复制一份。但这种情况也带来了很多问题。因为底层文件系统的备份数量是有限的,所以副本的数量也是有限的。深层次的原因是底层分布式文件系统的IOPS是有限的。对于主从关系,像传统模式下的MySQL,其实是没有这个限制的。4总结***总结一下这些方案的优缺点:比如客户端方案,它的优点是可以连接多个数据源,只要数据库兼容JDBC就可以连接,而性能更好。但是提高性能也带来了另一个问题。连接数可能会更多,因为客户端太多了,如果每个客户端都连接MySQL,那么MySQL连接数会很多。缺点也非常明显。如果公司只以Java为主,那是没有问题的。如果开发一个jar包,大家会很熟悉;如果一个公司使用Python、C++、Go,你必须要写一个客户端,其实是很痛苦的。另外,客户端发布了,SDK发布后升级很麻烦。所以绝大多数厂商都会采用Proxy方案,因为Proxy方案易于管理,易于升级,语法基本兼容,多语言SDK没有问题。兼容部分MySQL语法后,可以使用传统的MySQL客户端和各种语言的SDK,以及所有第三方开发的MySQLSDK。缺点是不支持事务,或者对事务的支持有限。对于计算和存储分离,其优势非常明显,性价比特别高。为什么?在购买云上的云数据库时,性能往往与购买有关。比如你买个1C2G10GB的小数据库,OPS可能只有几百上千;但是对于真正的计算存储分离的方案,一开始购买的种类可能比较少,购买的规格也可能比较小,但是可以达到高IOPS性能,数据库性能不会被规格限制你购买。关于缺点,整体存储空间有限,可能只支持64T或者128T,因为每个数据库分布式存储的副本数有限,只读节点可能也有限,只有15个或者14,但这并不重要。相信对于绝大多数用户来说,这已经足够了。另一个缺点是开发难度大,但这个缺点只是开发者的痛点,与用户无关。对于从头开始,Spanner/TiDB等数据库解决方案具有较高的可扩展性。因为对于Aurora这种计算存储分离的数据库来说,存储空间毕竟是有限的,但是对于这种数据库来说,它的存储空间可以认为是最具扩展性的,没必要去支持P题的数据库。还是说说缺点吧。很难兼容一些现有的SQL语法,这是一个比较大的挑战。比如TiDB是国产的优秀数据库,也号称最兼容MySQL的语法,但实际上还有很多语句不能兼容。数据结构决定了一些功能,也决定了兼容一些SQL语句的成本非常高。【本文为专栏作者“京东云”原创稿件,转载请通过作者微信公众号JD-jcloud获得授权】点此查看作者更多好文