大家上午好!
很多公司都在开发自己的分布式数据库架构,且不少公司都可能使用上了,也有很多人在讲分布式数据库架构,这些是真正意义上的分布式数据库吗?
若要我加一个词的话, 我一般说伪分布式或者说所谓的分布式数据库架构,是跟陈国庆分享的NoSQL一样,只是起一个简单且好听点的名字,之所以谈这个话题,就是想与大家分享一下个人对伪分布式数据库架构的理解及所实践的。
PPT主要的内容主要有几点:什么是分布式数据库;什么是伪分布式数据库;分布式和伪分布式数据库架构的优缺点;伪分布式数据库架构适用的场景;二种伪分布式数据库架构的设计思路,一类适用于电子商务等领域,另外一类适合于SNS游戏等领域。
首先申明二个要点:第一点不支持分布式事务的,肯定不是分布式数据库;第二点分布式强调的是可用性、可靠性和数据一致性,其中数据一致性又分松散一致性和严密一致性,因为分布式数据库有不同的实现算法,为此数据一致性都有各种差异。
接下来,我们看一下分布式数据库的定义:由一组存储在网络中不同服务器上的数据组成,网络中每个节点具有独立执行局部应用的能力,也可以通过网络通信系统执行全局应用的能力。
为什么需要伪分布式数据库产品?是因为集中式数据库,当数据量越来越大,数据的读写量也越来越大,且无法通过垂直增加或升级硬件设备而满足的,以及越来越成为业务增长的瓶颈,那么我们就不得不考虑革新,采用一种更加有效、可行的方案解决。
伪分布式数据库的应用场景,稍微罗列了下:电子商务平台(C2C、B2B、B2C)
、SNS平台、IM即时通信软件、电子邮件系统、日志分析系统、SNS游戏、其他平台型网站。
大致总结了下,使用伪分布式数据库架构场景的三要素:
- 大数据容量,且垂直升级扩展受限的;
- 高并发事务型的;
- 数据更新量远大于数据读取,且数据更新量非常大;
接下来我们看一下分布式数据库一个最独特的架构图,但是看之前,先了解下分布式数据库的四个是核心模块。我们把四个名词解释一下:
什么是局部数据库管理系统?
什么是全局数据库管理系统?
什么是全局数据字典?
什么是通信管理?
- LDBMS
建立和管理局部数据库,提供场地自治能力,执行局部应用及全局查询的子查询;
- GDBMS
提供分布透明性,协调全局事务执行,协调各局部DBMS完成全局应用,保证数据库全局一致性、执行并发控制、实现更新同步和提供全局恢复等功能;
- 全局数据字典
存放全局概念模式、分片模式、分布模式的定义以及各模式之间映像的定义,存放有关用户存取权限的定义,保证全局用
户的权限和数据库的安全,存放数据完整性约束条件定义;
- 通信管理
实现分布式数据库各场地之间消息和数据传递;
这是分布式数据库最复杂的一种结构,每个节点都有一个全局数据字典和全局数据库管理系统,但市场上的产品中都不会使用这种架构。因为此架构的分布式数据库产品的实现技术难度高,各个节点之间通信和管理成本高,好处就是全局数据库管理系统和全局数据字典不会成为单点,为此市场上的产品多是采用多个全局数据库管理系统和全局数据字典解决单点的问题,但不是每个节点都用。
接下来回到我们的重点:什么是伪分布数数据库架构,大家千万不要像迷恋NoSQL一样迷恋伪分布式这个名字,同一个道理。伪分布式我简单的理解就是多个集中式数据库,再加上数据库自身复制,最外层再加上开发的软件和一些其他的组件;
分布式数据库的优点蛮多的,大致罗列了四点:
1>.数据独立性:数据逻辑独立性、物理独立性、分布独立恶性;
2>.适当数据的冗余,实现高可用性;
3>.集中和自治相结合的控制结构;
4>.全局的一致性、可串行性、可恢复性;
一个产品有优点,其自然也会存在一些负面的,大致如下:
1>.部署复杂,对硬件、网络等环境要求更高;
2>.事务、数据查询性能相比较下降;
3>.商业产品费用较贵,开源产品暂时存在瑕疵;
4>.技术实现复杂,开发成本高;
那接下来我们继续谈下伪分布数据库架构的优缺点。伪分布式的优点就是提供了类似分布式数据库的数据库透明性;解决集中式数据库的扩展局限性;能够提高数据的访问性能、可用性和可靠性,因为把很多数据拆到很多不同的服务器上,数据被打散了,而且现在PC服务器的处理能力非常不错,可以通过伪分布式数据库架构提供的自动切换功能,使得可用性和可靠性有保障。
伪分布式数据库架构的实现技术也不难,有很多现成的方案,开发成本也不高。而且我拆分了数据库之后,可以用一些自动化的工具模块,使对数据库的维护成本可控的。
伪分布式数据库架构也有其缺陷,
1>.不支持分布式事务 ;
2>.数据拆分之后出现数据合并难度与部分功能限制 ;
3>.数据库设计技巧难度加大 ;
二种通用伪分布式数据库架构都大致有组建,信息如下:
- 前端通信协议:MySQL通信协议、JSON协议;
- 后端通信协议:MySQL通信协议;
- 存取路由算法控制器:HASH值法、数据库路由表法;
- 连接池:数据库连接池、应用程序连接池(可选);
- 负载均衡:客户端调用API接口;
- 解析器:SQL解析器、JSON字符串解析器;
- 查询结果集合并缓冲区;
- 序列生成器;
- JSON字符串操作合并队列服务;
- MemCache管理模块;
- 第三方平台ID转换器;
- 数据库可用性探测模块;
- 命令行管理接口;
稍微解释几个模块,及重点解释数据存取的路由法则和序列生成器,我们先说下应用程序与伪分布式数据库架构的通信模块,前段应用程序都是连接到这个数据中间件上,然后通过数据中间件访问数据库,完成数据的读写操作。
数据库可用性探测器就是通过做一个UPDATE操作的方式检测数据库服务是否正常,使用修改命令的原因是MySQL
HANG会有很多种情况,但是一定无法完成写操作。
命令行管理接口,可以根据数据库可用性探测器或人为发送的命令,完成一些操作,比如数据库服务从A服务器转移到B服务器,那么就可以发送一个强制切换命令。
查询结果集合并缓冲区主要为弥补因数据打散而存在数据合并的需求,比如一个查询操作需要操作多个库,那么SQL解析器会拆分成多条SQL执行,然后结果集在此缓冲区合并,甚至还可以再做一些如排序、分组统计等操作。
负载均衡模块,我们需要提供前端应用程序访问数据中间件的驱动模块,那么我们可以把负载均衡的模块集成进去,前端只需要配置数据中间件服务器的IP及连接信息即可,尤其自动完成命令发送到哪台中间件服务器。
……
我们再深入到之前说的二个模块,第一个是数据路由的存取算法,第一类我们是:HASH值法;第二类是:路由表法。
HASH值法,一般是根据用户UID算出一个0~1023的值,根据用户ID好处就是可以把一个用户的数据尽量存储在一块,方便读写操作。我们要根据现有数据容量、数据库服务器负载、业务数据增长等信息,预先确定要划分为多少段,比如我们把0~1023划分为128段,也就是把用户数据划分到128个数据库中存储起来,然后每次数据的存取,就根据SQL语句中的拥护ID计算及存储的位置,把SQL语句或事务发送到对应的服务器上执行;
路由表法,一般是有一张表存储用户ID,及存储其的数据库ID,还有一张存储数据库访问信息的表,大致如下图:
CREATE TABLE db_config(ID SMALLINT UNSIGNED
NOT NULL AUTO_INCREMENT,
is_full TINYINT UNSIGNED NOT NULL DEFAULT
0,
user_TOTAL MEDIUMINT UNSIGNED NOT NULL
DEFAULT 1000000,
master_server_id MEDIUMINT UNSIGNED
NOT NULL DEFAULT 3306,
master_ip VARCHAR(40) NOT NULL DEFAULT
”,
master_port MEDIUMINT UNSIGNED NOT NULL
DEFAULT 3306,
db_user VARCHAR(16) NOT NULL DEFAULT
”,
db_pwd VARCHAR(45) NOT NULL DEFAULT
”,
db_name VARCHAR(40) NOT NULL DEFAULT
”,
slave_server_id MEDIUMINT UNSIGNED NOT
NULL DEFAULT 33060,
slave_ip VARCHAR(40) NOT NULL DEFAULT
”,
slave_port MEDIUMINT UNSIGNED NOT NULL
DEFAULT 3306,
host_status_id TINYINT UNSIGNED NOT
NULL DEFAULT 0,
host_status VARCHAR(80) NOT NULL DEFAULT
”,
PRIMARY KEY(ID)
)ENGINE=InnoDB AUTO_INCREMENT=1 CHARACTER
SET ‘utf8′ COLLATE ‘utf8_general_ci’;
CREATE TABLE uid_dbid_map(user_id BIGINT
UNSIGNED NOT NULL,
db_id SMALLINT UNSIGNED NOT NULL DEFAULT
1,
third_uid CHAR(32) NULL DEFAULT NULL,
PRIMARY KEY(user_id),
UNIQUE KEY idx_Third_UID(third_uid)
)ENGINE=InnoDB CHARACTER SET ‘utf8′
COLLATE ‘utf8_general_ci’;
稍微解释下,为啥uid_dbid_map表中还有一个字段:third_uid,主要是因为像SNS游戏,多是接入到第三平台,而各个平台为不使外界通过此猜测出其有多少注册用户及`安全,给我们的ID都是非常奇怪的,为了程序通用、性能等,我们对第三的ID一律作MD5运算,然后存储起来,在玩家操作过程中,使用内部ID进行数据的操作。
接下来我们继续深入谈下自增序列器模块的作用,想实现:
- 实现MySQL自带的字段值自动增长等效的功能;
- 同一应用集群中数据库表的自增类型字段值具有全局唯一性;
- 支持数据库级别的水平拆分表,同时还需要支持数据库内部的表再次水平拆分,其ID值都来源于同一条配置记录;
其表的结构如下:
CREATE TABLE increment_config(ID MEDIUMINT
UNSIGNED NOT NULL AUTO_INCREMENT,
DB_NAME VARCHAR(40) NOT NULL DEFAULT
”,
TABLE_NAME VARCHAR(40) NOT NULL DEFAULT
”,
TABLE_TOTAL TINYINT UNSIGNED NOT NULL
DEFAULT 0,
COLUMN_NAME VARCHAR(40) NOT NULL DEFAULT
”,
START_VALUE BIGINT UNSIGNED NOT NULL
DEFAULT 1,
OFFSET_VALUE SMALLINT UNSIGNED NOT NULL
DEFAULT 10000,
FLAG TINYINT NOT NULL DEFAULT 0,
GMT_MODIFIED TIMESTAMP NOT NULL DEFAULT
CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,PRIMARY
KEY(ID),
UNIQUE KEY idx_TableName_DBName(TABLE_NAME,DB_NAME)
)ENGINE=InnoDB AUTO_INCREMENT=1 CHARACTER
SET ‘utf8′ COLLATE ‘utf8_general_ci’;
对于涉及自增类型的表,在此配置一条记录,主要有表明成、表在一个数据库内部拆分的数量,自增起始值,增长的步长。有些情况下,需要内部再分表主要是考虑到一些表的数据容量可能会变成很大,而MySQL做表的变更会阻塞数据的写操作,若是较小的表,就可以更快完成变更操作。前端应用程序可以选择启动或用完之后一次性向中间件服务器申请10000个ID值域,这样可以避免每用一次都取而提高效率。 |