Tagged: 系统设计

1

多leader replication的实现及常见问题介绍

我们在前面的文章中介绍的都是单leader的实现。也就是说所有的写操作都会通过这个leader来实现。虽然说这是一种比较常见的实现方法,但是它也尤其局限性,比如说leader可能会有问题,比如网络问题等,这个时候就会有一段时间没法进行写操作。或者说当写操作很重的时候,所有的写的load都需要到leader这边,无形中就加重了leader的traffic。本文就来介绍一种多leader的实现方案。 顾名思义,多leader实现方案就是可以同时有多个节点成为leader,所有的写操作可以同时通过这些节点来进行。当其中一个leader在写的时候,另外的leader就和follower一样,也需要从它这边进行replication。 多leader的使用场景 多leader其实并不是一个比较常见的方案。那么一般在什么情况下,我们会考虑多leader的方案呢? 多数据中心的操作 假如我们的数据库是在多个数据中心的时候(实际上为了防止但数据中心出问题,一般的数据库都会分布在不同的数据中心),假如使用单leader的实现,那么leader就会在一个数据中心,从而使得所有的写都得通过那个数据中心。 而假如是多leader的实现,我们就可以在每一个数据中心放一个leader,这样在每一个数据中心中,还是单leader的情况,但是这个数据库则是多leader的情况。具体的架构如下图所示: 下面我们来看看这样的实现有什么好处: 性能 单leader的情况下,所有的写都需要到leader那边,显然跨数据中心的访问性能不会很好。而多leader的情况下,所有的读操作可以直接访问本地的数据中心,虽然需要在数据中心进行数据replication,但是数据中心之间的延迟其实对用户来说是黑盒,所以对用户来说性能是有提升的。 数据中心宕机的容忍性 单leader的情况下,如果有数据中心宕机,那么需要通过failover来找到新的leader,然后可以继续服务。多leader的情况下,单个数据中心的宕机不影响整体的写操作,无需做额外的failover也可以继续进行写操作。 网络问题的容忍性 同样的,但leader其实受leader所在数据中心的网络情况所影响,而相对来说多leader则可以更好的容忍单个数据中心网络的问题。 虽然看起来多leader的实现有很多好处,但其实它也有其问题,那就是冲突写,比如两个写同时发生在两个不同的leader上,并且彼此冲突,该如何进行处理,这个问题我们后面会详细介绍一些处理的方案。 Offline操作的应用 另外一个多leader replication常见的场景就是offline操作,比如你有一个应用哪怕没有网络也希望能够持续工作。 比如说你手机中的日历程序,你希望安排你的日程,比如添加事项,看看后面哪天有哪些安排。这些操作哪怕是在没有网络的时候也希望能够正常工作。只要当这个设备能够再次访问网络的时候我们能够成功同步这些就可以了。其实这就是一个多leader的场景,你可以把你的设备想象成一个数据中心,有网络的时候,就是正常的多leader同步。没有网络的时候,本地的leader也支持读、写操作。当再次有网络的时候能够做跨数据中心(设备)的replication。 协同写操作的应用 另外一个常见的使用场景就是会有多人同时写一个文档。比如说Google Doc,它支持同时有多个人来编辑。这种常见就和上面的比较类似,我们不希望一个人的写去影响另外一个人的写,所以这里通常就会写入本地leader,然后进行多节点的同步。 处理写冲突 我们上面提到多leader最大的问题就是写冲突,毕竟两个leader完全有可能同时修改同样的内容,如下图所示: 这里User1通过Leader1修改了title到B,但是User2又通过leader2修改了title到C,这个时候在他们进行replication的时候就会出现了冲突的问题,究竟是该改成B还是改成C呢? 避免冲突 假如我们现在能够想到一个简单的方法来避免冲突,那么这个问题就自然而然解决了。比如所有修改title的请求全部要到同一个leader来处理,这就可以规避掉上文提到的写冲突。这个方案还是蛮常见的,比如说用户的资料只能他自己能修改,而所有这个用户修改自己资料的请求我们全部指向同一个leader,这样就可以实现冲突的避免。 但是世事显然不会总是这么一帆风顺,比如说有时候某一个数据中心突然就出问题了,那么无可避免的,你就只能把所有的写操作都指向另外数据中心,这样就还是会出现写冲突。 收敛到一致状态 多leader其实很难说谁是最后写的,所以最终应该是什么样的内容有时很难讲,就像上面的例子一样,你说最终title应该是B还是C呢?这个时候就需要一些额外手段来辅助判断: 给每一个写一个独有的ID(比如使用timestamp,UUID等等),然后比较他们的大小。大得获胜。当这个ID使用的时间,那我们称这种方法为最后写的获胜(Last write wins LWW)。这个方法听起来不错,但也有其问题,我们在后面的文章中再具体讨论。...

1

SQL和NoSQL的分析

基本概念 SQL和NoSQL是一个很基本的概念,相信很多人都听说过,网上也有很多文章来介绍两者的对比。那么什么是SQL,什么又是NoSQL呢? 所谓的SQL(Structured Query Language),就是我们俗称的关系型数据库。它是基于关系模型来组织数据的数据库。一般来说,使用预定义的schema来决定数据的结构。所有数据都必须遵循同样的结构,这也就意味着你很难对数据的结构进行改变。 NoSQL(Not Only SQL),从它的名字我们可以很容易发现,它其实是基于SQL后来出现的,其实早期它这是社区讨论的一个tag,一步步演变到了今天用来泛指非关系型数据库。和SQL相对的,它是基于动态Schema的非结构化数据,它可以是基于文档的,键值对,wide column或者基于图的。 可以说NoSQL的产生就是因为在某些情况下SQL已经无法满足现如今的一些场景,比如超大数据等。但是,需要承认的是SQL目前还是主流企业使用的技术,其也是可以满足几乎绝大多数业务需求的。强调这一点的原因是,很多学生或者没有太多业界经验的人会下意识的觉得NoSQL更好,优先考虑NoSQL,其实不然,大多数情况我们还是应该倾向于SQL的设计,当然如何进行选择我们会在后文中详细讨论。 实例分析 在了解了相关的基本概念之后,我们来看一个具体的例子进行分析,这样才能对两者有一个感性的认识。就拿比尔盖茨的LinkedIn的页面来简单分析吧。就这样一个简单的页面,我们在数据库中该如何设计呢? 首先来看看关系型数据库中的表格设计,简单设计如下图所示。这里值得一提的就是我们如何保存城市相关的信息,我们这里使用的是id来进行保存而不是一个字符来保存,这样做有以下好处: 很方便进行修改,因为所有的城市名字都保存在一个地方,比如哪一天Seattle改名字叫Seattle2了,我们只要修改一个表格中的一行数据就可以了,而不需要把所有的记录都进行修改。 很容易进行本地化处理,比如说我们的页面需要在中国现实,那么Seattle就可以显示成“西雅图”,这样的设计就很容易做。 防止拼写错误,假如我们让用户来输入地址,那么就有可能这样地址被写成Saettle之类的,从而导致一系列问题。 更易于搜索,比如我们搜索华盛顿州的人,那么这样的层级关系就很容易被发现。而只保存字符就不利于这样的搜索。 其实像上面这种例子,使用面向文档的数据结构也蛮合适的,比如JSON格式的设计可以如下所示,相比于上面关系型数据库设计,这种设计在读取方面有很大的优势,我们不需要去做多个join来获取job和education之类的信息,只需要读取相关的user保存的信息就能得到我们所想要的信息。 SQL和NoSQL的比较 Schema的设计 如我们上面例子中所示,关系型数据库会把数据保存在多个表格中,这些表格相关是有关系的。表格是有行和列来组成的,每行就是一个数据记录,每列保存一个特定类型的数据,而且表格中的每行数据的列都是相同的(可以是null)。 而NoSQL则不同,总得来说NoSQL可以分为以下几个种类: 基于文档的数据库。这种数据库是基于类似JSON的文档来保存数据的。我们可以认为它虽然没有定义表结构,但是可以像定义了表结构一样使用它。它也支持一些复杂的查询条件,相比关系型数据库除了事务处理和JOIN不支持外,其他的各项功能都支持得很好。 基于键值的数据库。这个数据库存储的就是键值对,他们可以是各种各样的格式,可以是字符串也可以是复杂的值。它的特点就是处理的速度很快,它通过把键保存成特殊的index,从而达到快速查询的目的。它一般可以分为临时型,永久性和两者兼具这三种。所谓临时就是相关的键值都是保存在内存中,所以读取速度很快,相应的问题就是他数据很容易丢失,不是永久保存。而永久性的则相反,它的数据是永久保存的,也就是保存到磁盘中,相对来说就会收到磁盘IO的限制,从而读写的速度不是那么快。而两者兼具型则是兼具两者的优点,首先会把数据保存在内存中,从而达到快速访问的目的。同时又会根据一定的算法把数据保存到磁盘中,这样就可以保证最终的数据永久性了。 基于宽列的数据库。这种数据库和关系型数据库比较类似,只是它每行的列数目是动态的,可以逻辑上把这些列组成不同的列家族。 基于图的数据库。它使用的节点来存储数据实体,使用边来储存之间的关系。这种数据库在关系性比较强的数据或者推荐引擎中使用得比较多。 速度 在大多数情况下,这两种数据库的速度性能上来比较并没有特别的差别。但是在一些比较复杂的情景下还是稍有不同的。 我们上文提到关系型数据库会使用类似保存ID,然后JOIN的方式来存储数据,这当然有很多有点,就像我们上面提到的一样,方便修改啊之类的。但是相应的代价就是我们每次查询的时候都需要JOIN这些表格。而当JOIN很多表格的时候,必然会产生性能的损失,而NoSQL则可以很好的克服这个问题。 NoSQL并不太在意相应数据存储空间,它一切以查询结果为导向。因此其查询的速度显然也就会很快了。 扩展 一般来说,SQL的扩展都是垂直扩展,也就是加大CPU,加大内存,加大磁盘空间等来解决性能瓶颈。这种扩展的方式一方面很容易就达到性能的瓶颈,另一方面也可能最终没法满足日益增长的需求。现在SQL也开始在某种程度上支持横向的扩展,不过总得来说效果不是特别好。 NoSQL则是天然的支持横向扩展,也就是说当遇到性能问题的时候,你可以引入更多的机器来进行处理,这其实更符合现如今分布式系统的扩展趋势。显然在这方面,NoSQL是有先天的优势的。 指导原则...