1.2 分布式技术是大规模应用的最后一个考验
随着用户量的进一步增长,单个子系统数据库也会慢慢达到单机处理能力的上限。此时,已经不能再通过领域拆分来解决问题了,因为仅仅是单一的订单表中的数据就已经超出了单个数据库的处理能力。唯一的解决方式就是把订单数据拆分存储在多台数据库服务器中。至此,互联网应用已经成为一个彻底的分布式应用。但是做好这个分布式应用并不容易。
如何把订单数据保存到多台服务器上?有三类方法可以实现。
第一类方法是仍然使用关系型数据库。在多个数据库中创建相同的订单表,然后按照一定的规则把订单分别存储在不同的服务器上。比如按用户存储,将用户id按照一定的规则划分成组,常见的方式是按id取余数,如按10取余数,可以把订单平均分到10台服务器上,当订单量继续增长时,可以把规则改为按100取余数,就可以把订单分到100台服务器上。这种架构的难点在于当取余规则更改时,需要把原来存储在10台服务器上的已有数据迁移到100台机器上。
再比如按时间存储,将一年的订单存储在一台机器上,随着时间的推移不断地增加服务器。这种方法不需要迁移数据,但是只适用于订单量没有太大变化的场景,所以应用场景比较受限。
这类方法相对比较好理解,其核心就是针对每台数据库服务器分别执行SQL语句,然后将SQL语句的执行结果进行合并。但是这种架构的使用是非常复杂的,需要处理各种异常情况,比如某台服务器的SQL语句执行失败等。为了简化这种架构的使用,开源领域出现了很多数据库中间件项目,用来让开发者不需要面对多台数据库服务器分别执行SQL语句,感觉自己仅仅是面对一台服务器在执行SQL语句。但是其核心原理没有改变,只是这些数据库中间件自动帮助开发者把SQL语句合并的事情做了。另外,无论是否采用这样的数据库中间件,每次执行SQL语句时需要所有服务器都执行这条SQL语句,成本和性能都是不可接受的,可见采用这种架构的应用都有很多限制。应尽量避免这样的操作,需要把应用设计成每次执行SQL语句时最好只发给一台服务器来处理。因此,最终不管用不用数据库中间件,都需要背后的数据库拆分逻辑。
最重要的一个难题是这种架构保证一致性非常有挑战性,让所有服务器上的数据都保持正确,是应用开发者要考虑的事情,也是数据库中间件开发者要考虑的事情。
第二类方法是放弃SQL的便利性,采用分布式文件系统(见第2章和第3章)保存海量的数据。分布式文件系统是近年来迅速发展起来的大数据技术的基石,Google公司在这方面做了开创性的工作。GFS(见第2章)被称为Google公司大数据的“三架马车”之一,HDFS(见第3章)是开源大数据领域的核心组件,它们提供的可靠的数据存储能力和强一致性,为大数据技术提供了强有力的基础支撑。
另外,在在线服务方面,我们也可以采用NoSQL数据库(见第4章和第5章)来存储数据。NoSQL是近年来出现的新型的数据库和存储系统,从名字上可以看出它除去了对SQL的支持。但是缺失SQL的支持并不是NoSQL数据库的弱项。用NoSQL数据库替换SQL数据库往往适用于因数据量大而需要拆分的场景,在这种场景下,SQL的使用受到很多限制,比如互联网公司往往都有不能使用join、SQL中必须携带分片id等要求。在这些使用要求下,受限的SQL数据库的能力与NoSQL数据库的能力相比,已经没有明显的优势了。NoSQL数据库通常具有很好的扩展能力、数据可靠存储能力和可用性,保存到NoSQL数据库中的数据会被系统自动拆分存储在多台服务器上,并且随着数据的增长自动重新拆分、迁移,这些功能大大降低了系统的使用难度。有些NoSQL数据库还放弃了一致性,也有些NoSQL数据库并没有放弃一致性,比如Google的BigTable系统(见第4章)就提供了很好的一致性。MongoDB(见第5章)在早期版本中没有很好的一致性保证,会出现各种异常,导致数据丢失,但是随着版本的逐步迭代,不断地加强一致性,慢慢消除了各种异常和丢失数据的问题。
第三类方法就是使用NewSQL数据库(见第8章和第9章)。NewSQL数据库并没有去掉对SQL的支持,同时它还具有很好的水平扩展能力、可靠性和可用性。Spanner系统(见第8章)还不能被称作NewSQL数据库,它的后代产品才是NewSQL数据库。CockroachDB(见第9章)是NewSQL数据库,用户使用时无须考虑库表的拆分以及数据迁移的问题,就像使用单机数据库一样。相对于拆分数据库表的方法而言,NewSQL数据库给使用者带来的最大便利就是,使用者不用再关注数据的一致性,NewSQL数据库有非常好的一致性保证,这也是本书主要讲述的内容。
除前面讲到的三类方法中所涉及的分布式系统之外,做好一个分布式应用可能还会需要其他种类的分布式系统,比如消息系统。消息系统用来解耦各个系统,RabbitMQ(见第6章)就是这样的一个系统。此外,还需要使用分布式协调服务来管理分布式系统中的各个进程,比如ZooKeeper(见第7章)。
这些分布式系统的内部实现差别非常大,有些使用了非常复杂的分布式算法,第3部分会介绍其中的三种:Paxos算法(见第10章)、Raft算法(见第11章)、Zab算法(见第12章)。
最终,解决大规模应用问题就变成了对这些分布式系统和分布式技术的使用问题,用好分布式技术成为实现大规模应用的最后一个难题。