05.数据库拆分

关系型数据库调优

本章讨论关系型数据库调优相关内容,其向上承接了《DistributedSystem-Notes》等相关内容。

数据库分拆

在最抽象的层面上,数据库,Hadoop 和操作系统都发挥相同的功能:它们存储一些数据,并允许你处理和查询这些数据。数据库将数据存储为特定数据模型的记录(表中的行、文档、图中的顶点等),而操作系统的文件系统则将数据存储在文件中,但其核心都是“信息管理”系统。当然,有很多实际的差异。例如,许多文件系统都不能很好地处理包含 1000 万个小文件的目录,而包含 1000 万个小记录的数据库完全是寻常而不起眼的。无论如何,操作系统和数据库之间的相似之处和差异值得探讨。

Unix 和关系数据库以非常不同的哲学来处理信息管理问题。Unix 认为它的目的是为程序员提供一种相当低层次的硬件的逻辑抽象,而关系数据库则希望为应用程序员提供一种高层次的抽象,以隐藏磁盘上数据结构的复杂性,并发性,崩溃恢复以及等等。Unix 发展出的管道和文件只是字节序列,而数据库则发展出了 SQL 和事务。哪种方法更好?当然这取决于你想要的是什么。Unix 是“简单的”,因为它是硬件资源相当薄的包装;关系数据库是“更简单”的,因为一个简短的声明性查询可以利用很多强大的基础设施(查询优化,索引,连接方法,并发控制,复制等),而不需要查询的作者理解其实现细节。

这些哲学之间的矛盾已经持续了几十年(Unix 和关系模型都出现在 70 年代初),仍然没有解决。例如,我将 NoSQL 运动解释为,希望将类 Unix 的低级别抽象方法应用于分布式 OLTP 数据存储的领域。

数据库中间件

数据库中间件的主要作用是向应用程序开发人员屏蔽读写分离和分库分表面临的挑战,并隐藏底层实现细节,使得开发人员可以像操作单库单表那样去操作数据。典型的数据库中间件设计方案有 2 种:代理模式与富客户端模式,底层都操作了多个数据库实例。不论是分库分表,还是读写分离,都是在数据库中间件层面对业务开发同学进行屏蔽。

代理模式的代表,目前除了 mycat、sharing-sphere,其他几个开源项目基本已经没有维护,sharing-sphere 前一段时间已经进去了 Apache 软件基金会孵化器。 阿里巴巴开源的 tddl,已很久没维护。当当网开源的 sharding-jdbc,目前算是做的比较好的,文档资料比较全。和 sharding-sphere 一起进入了 Apache 孵化器。 蚂蚁金服的 zal

部署模式

代理模式

代理服务背后管理多个数据库实例。而在应用中,我们通过一个普通的数据源(c3p0、druid、dbcp 等)与代理服务器建立连接,所有的 sql 操作语句都是发送给这个代理,由这个代理去操作底层数据库,得到结果并返回给应用。在这种方案下,分库分表和读写分离的逻辑对开发人员是完全透明的。

代理模式的优势在于多语言支持,并且对业务透明。以 mysql 数据库为例,如果代理本身实现了 mysql 的通信协议,那么你可以就将其看成一个 mysql 服务器。mysql 官方团队为不同语言提供了不同的客户端驱动,如 java 语言的 mysql-connector-java,python 语言的 mysql-connector-python 等等。因此不同语言的开发者都可以使用 mysql 官方提供的对应的驱动来与这个代理服务器建通信。

不过代理模式也有其缺陷:

  • 实现复杂。因为 proxy 需要实现被代理的数据库 server 端的通信协议,实现难度较大。通常我们看到一些 proxy 模式的数据库中间件,实际上只能代理某一种数据库,如 mysql。几乎没有数据库中间件,可以同时代理多种数据库(sqlserver、PostgreSQL、Oracle)。

  • proxy 本身需要保证高可用。由于应用本来是直接访问数据库,现在改成了访问 proxy,意味着 proxy 必须保证高可用。否则,数据库没有宕机,proxy 挂了,导致数据库无法正常访问,就尴尬了。

  • 租户隔离。可能有多个应用访问 proxy 代理的底层数据库,必然会对 proxy 自身的内存、网络、cpu 等产生资源竞争,proxy 需要需要具备隔离的能力。

富客户端模式

业务代码需要进行一些改造,引入支持读写分离或者分库分表的功能的 sdk,通常 smart-client 是在连接池或者 driver 的基础上进行了一层封装,smart-client 内部与不同的库建立连接。应用程序产生的 sql 交给 smart-client 进行处理,其内部对 sql 进行必要的操作,例如在读写分离情况下,选择走从库还是主库;在分库分表的情况下,进行 sql 解析、sql 改写等操作,然后路由到不同的分库,将得到的结果进行合并,返回给应用。

富客户端模式的优点在于实现简单,不需要重复实现数据库通信协议,而只需要在现有的驱动之上封装即可。并且天然的去中心化,由于本身以 sdk 的方式,被应用直接引入,随着应用部署到不同的节点上,且直连数据库,中间不需要有代理层。因此相较于 proxy 而言,除了网络资源之外,基本上不存在任何其他资源的竞争,也不需要考虑高可用的问题。只要应用的节点没有全部宕机,就可以访问数据库。

富客户端模式的缺点在于:

  • 通常仅支持某一种语言。例如 tddl、zebra、sharding-jdbc 都是使用 java 语言开发,因此对于使用其他语言的用户,就无法使用这些中间件。如果其他语言要使用,那么就要开发多语言客户端。

  • 版本升级困难。因为应用使用数据源代理就是引入一个 jar 包的依赖,在有多个应用都对某个版本的 jar 包产生依赖时,一旦这个版本有 bug,所有的应用都需要升级。而数据库代理升级则相对容易,因为服务是单独部署的,只要升级这个代理服务器,所有连接到这个代理的应用自然也就相当于都升级了。

Links