目前其实有很多提供DRDS分布式数据库解决方案的服务商,比较流行的有阿里云。另外腾讯、百度、网易等几家大厂也都有提供这类服务,另外官方也提供了MySQL Cluster CGE企业级MySQL分布式集群服务。直接选择这些商业服务可以以最快的速度将现有系统迁移或者将新系统部署到分布式数据库环境中,但同时因为商业服务都有一个既成的整体框架,服务商能做到的只有根据需求进行微调,客户的自身系统或多或少要为分布式数据库的部署做一些相应调整。
以百度云服务为例,演示一下操作。
百度云分布式关系型数据库DRDS,官网上介绍的功能包括:平滑扩容、自动分表、主从热备、读写分离、自动备份、监控运维。
如上图所示一个DRDS实例,展示了几点信息。
域名、端口:服务器命令行环境可通过域名、端口以登陆连接mysql的方式连接drds实例,相当于单库地址。
中间件:中间代理节点,多代理节点可以提高系统可靠性,防止单点故障。
物理分片:集群,一组分片可以包含一个主库,多个从库(只读副本)。
DRDS集群由分片即单存储节点组成,单存储节点的规格和数量决定了DRDS集群的处理能力。即单存储节点的规格越高、节点数量越多,DRDS实例的处理能力越强。而单存储节点的性能主要由CPU/内存决定。因此用户应均衡配置中间件代理及存储节点的读性能、写性能,避免出现性能瓶颈。根据存储节点数*单节点内存推荐用户合理的代理节点数,确保中间件不会成为系统整体性能的瓶颈。
- 中间件吞吐能力QPS=单个代理节点QPS(5000)*代理节点数,
- (推荐)代理节点数=储存节点数 * 2;
- 总磁盘大小=单节点磁盘*存储节点数;
- 单节点内存默认一主一备;
- DRDS集群写能力=单节点写能力*存储节点数;
- DRDS集群读能力=单个副本读能力*副本数;
DRDS支持分表不分库,分库通过分表来实现。即分表后通过把不同的表放在不同的节点来实现分布式的分库,而不是直接通过分库键来分库。当前DRDS默认有64张表,如果用户购买了2个存储节点(即两个分片),则每个存储节点里面会存放32张表;如果用户购买了4个存储节点,则每个存储节点里会存放16张表。
举例有两个代理节点和两个存储节点的实例配置,那么这个实例的架构应该是这样
创建数据库
创建单表和分布式表
百度云的DRDS数据库创建的数据库是一个逻辑数据库,给应用看到的感觉就是一个单一节点的数据库,实际上这是一个逻辑数据库,因为你看我们虽然有多个存储节点,但是创建的时候不会让我们指定存储在哪个节点上。实际这个数据库内的表数据可能分别存储在不同的存储节点当中,数据库命名也不同。但是代理节点会把应用的连接路由到真实的存储节点。创建表的时候可以选择是单表还是分布式表。创建单表,创建的表不分片,会被随机存储在某一个存储节点上。创建分布式表,表数据会根据分片规则分散存储在每个存储节点上。如下图
这边可以看到。 如果是单表的话,是随机存储在某一个存储节点上。如果是分布式表的话,是不指定的,相当于做了分表,每个节点会有个分表。根据分片规则做数据保存。
SQL限制,百度云做了很多针对分布式数据库的操作限制。入下面表格:
这里面很多其实就是上一篇提到的跨分片Join,分布式事务等问题,百度的解决方案就是直接禁止不支持这些操作,也是很棒棒哦。。。如果应用中有用到的,那不可避免地要做相应的调整了。
开源中间件
第二种解决方案就是使用开源中间件,确实有很多企业和组织自研了基于MySQL分布式关系型数据库的中间件,并且将他们开源出来,比较有名的比如有MySQL-Proxy,MySQL官方提供的中间件,能实现负载均衡,读写分离,不支持分片;MyCat, 强大的数据库中间件,包含读写分离,容灾备份,多种方式的分片;Atlas,支持读写分离、故障切换,不支持跨库分表;等等其他中间件。
以MyCat为例,演示一下使用。
MyCat的架构如下图
官网上介绍的一些特性有:
- 支持JDBC连接多数据库
- 支持NoSQL数据库
- 自动故障切换,高可用性
- 支持读写分离,支持MySQL双主多从,以及一主多从的模式
- 支持全局表,数据自动分片到多个节点,实现高效的表关联查询
- 支持一致性Hash分片,有效解决分片扩容难题
- 多平台支持,部署和实施简单
- 支持MySQL存储过程调用
- 支持自增长主键,支持Oracle的Sequence机制
以上未列出所有,可以看到,基本上解决了几个我们比较关心的分体,事务问题,扩容问题,跨分片问题,主键和Sequence问题,先不管他到底怎么实现的,实现的怎么样。至少提供了一种解决方案。
以下安装方式取自官方文档:=====>
MyCAT 有提供编译好的安装包,支持 windows、Linux、Mac、Solaris 等系统上安装与运行。linux 下可以下载 Mycat-server-xxxxx.linux.tar.gz 解压在某个目录下,注意目录不能有空格,在
Linux(Unix)下,建议放在 usr/local/Mycat 目录下,如下: 下面是修改 MyCAT 用户密码的方式(仅供参考):
目录解释如下:
bin 程序目录,存放了 window 版本和 linux 版本,除了提供封装成服务的版本之外,也提供了 nowrap 的 shell 脚本命令,方便大家选择和修改,进入到 bin 目录:
Linux 下运行:./mycat console,首先要 chmod +x *
注:mycat 支持的命令{ console | start | stop | restart | status | dump }
conf 目录下存放配置文件,server.xml 是 Mycat 服务器参数调整和用户授权的配置文件,schema.xml 是逻辑库定义和表以及分片定义的配置文件,rule.xml 是分片规则的配置文件,分片规则的具体一些参数信息单独存 放为文件,也在这个目录下,配置文件修改,需要重启 Mycat 或者通过 9066 端口 reload.
lib 目录下主要存放 mycat 依赖的一些 jar 文件.
日志存放在 logs/mycat.log 中,每天一个文件,日志的配置是在 conf/log4j.xml 中,根据自己的需要,可 以调整输出级别为 debug,debug 级别下,会输出更多的信息,方便排查问题。注意:Linux 下部署安装 MySQL,默认不忽略表名大小写,需要手动到/etc/my.cnf 下配置 lower_case_table_names=1 使 Linux 环境下 MySQL 忽略表名大小写,否则使用 MyCAT 的时候会提示找不到表的错误!
安装好以后只需要配置三个文件,就是schema.xml, rule.xml以及server.xml。
schema.xml配置举例:
这里创建了一个逻辑库,十一个逻辑表,其中七张分片表。创建了两个分片(数据节点),两个存储节点(数据库实例),其中一个节点是一个主从集群。
rule.xml配置举例
创建了MyCat用户(对于用户来说就是数据库用户)。
配置好了以后,我们的分布式数据库存储网络大概是下面这个样子的:
对于应用来说,访问的仍然是一个单库,而被分片的表分成两个小表保存在两个存储节点中,两个存储节点又分散在两个物理集群。
我们现在使用客户端工具连接到MyCat逻辑库,然后往逻辑库插入几条数据,看他们在各自的物理数据库中的情况。
创建一个测试表ts,有id和name两个字段,根据id分片。
mysql> CREATE TABLE `ts` (
-> `id` int(11) NOT NULL AUTO_INCREMENT,
-> `name` varchar(30) DEFAULT NULL,
-> PRIMARY KEY (`id`)
-> ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
连接MyCat,插入几条测试数据:
[root@jim bin]# mysql -u root -P8066 -p -h127.0.0.1
Enter password:
mysql> INSERT INTO ts (id, name) VALUES(11111, 'first');
Query OK, 1 row affected (0.02 sec)
mysql> INSERT INTO ts (id, name) VALUES(22222, 'second');
Query OK, 1 row affected (0.02 sec)
mysql> INSERT INTO ts (id, name) VALUES(33333, 'third');
Query OK, 1 row affected (0.01 sec)
mysql> INSERT INTO ts (id, name) VALUES(44444, 'forth');
Query OK, 1 row affected (0.01 sec)
mysql> select * from ts;
+-------+--------+
| id | name |
+-------+--------+
| 44444 | forth |
| 11111 | first |
| 22222 | second |
| 33333 | third |
+-------+--------+
4 rows in set (0.00 sec)
如果我们的分片规则生效了,那这几条数据应该分散在两个单库集群中。
先看3306
[root@jim bin]# mysql -u szmbke -P3306 -p
Enter password:
mysql> use szmbke;
mysql> select * from ts;
+-------+-------+
| id | name |
+-------+-------+
| 44444 | forth |
+-------+-------+
1 row in set (0.00 sec)
看到第四条记录插入了3306主机,再看他的从库3307
[root@jim bin]# mysql -u szmbke -p -P3307 --socket=/var/lib/mysql-3307/mysql.sock
Enter password:
mysql> select * from ts;
+-------+-------+
| id | name |
+-------+-------+
| 44444 | forth |
+-------+-------+
1 row in set (0.00 sec)
数据被自动复制了过去。
接下来看另一个主机3308
[root@jim bin]# mysql -u szmbke -p -P3308 --socket=/var/lib/mysql-3308/mysql.lock
Enter password:
mysql> select * from ts;
+-------+--------+
| id | name |
+-------+--------+
| 11111 | first |
| 22222 | second |
| 33333 | third |
+-------+--------+
3 rows in set (0.00 sec)
第1,2,3条记录被插入了3308。分片规则生效了。
针对MyCat说两句,实践MyCat最大的收获是了解基于MySQL数据库并且通过代理中间件的方式来实现DRDS分布式关系型数据库的这种实现方案。开源的MyCat给我们展示了各方面的实现细节。
但是MyCat一点也不完美,甚至有很多缺陷的地方。在使用的过程中我发现,要实现分库分表,必须通过自己在三个配置文件中做配置,例子中只做了最简单的一分为二的实验,实际生产中,分库情况可能复杂得多,这时候这样的配置方式过于复杂和不好维护。
而且MyCat对于数据扩容,数据支持这方面没有提供什么有效的帮助,如果更改了配置文件,那么之前已经配置好的分布式网络架构,要怎么人工调整?这也是一个大难题。
同时框架本身也存在一些问题,比如我在配置的时候多个DataNode如果对应到同一个物理数据库,这时候通过MyCat查询到的数据居然也有多份!