MySQL简单易用,并且开源,自用可以免费,用得好的话可以发挥自主可控成本低的理想功效,非常受互联网企业喜爱,现在也逐渐开始进入非互联网企业(不喜欢用传统企业这个词)了。但也的确缺失一些针对企业的高级功能,比如新增列、添加索引还会对整个表的数据进行重组,需要独占整个表,因此在单机使用时,需要控制单个表的大小,以减少做运维维护工作时独占表的时间。在多核(超过24个核)情况下的线性扩展能力(包括事务能力和查询能力)也不够理想,需要有较好的方法来快速解决这一类的技术需求。
当一个表太大不利于维护时,我们会将大表拆分成小表,这些表还属于同一个数据库,这种技术称为分表;当一个数据库的处理能力不够支撑业务,增加CPU的作用也十分有限时,就可能需要将部份表移到别的数据库,以增加系统处理能力,这种技术称为分库;通过精心的数据模型设计,将大的业务表拆分成小表,再将一系列小表分到不同的服务器,使得每台服务器都能独立承担部分业务处理,这种技术称为水平拆分,俗称为分库分表。分表的数量可以和物理的机器数不一致,分表数量称为逻辑份数,分库的数量称为物理份数,当逻辑份数大于物理份数时,就可以迅速获得水平扩展能力。
在使用传统商业数据库时,必须要通过应用层修改应用代码来实现,现在流行的做法是将应用开发语言统一,比如用统一的Java框架,然后编写一个统一的数据访问层,比如TDDL、ZDAL等。这种做法在大并发量下的性能上有一定的优势,可以减少一次网络交互,但在开发上绑定了特定的开发语言,需要有强大的配置推送体系,并且需要有强大的运维团队来支持。当后台用的是MySQL数据库,或兼容MySQL协议的数据库时,就可以不用修改应用程序,使用OneProxy来承担TDDL、ZDAL的功能,将后端的多台MySQL虚拟成一台MySQL提供给上层应用,对应用相对透明地实现分库分表的需求,来快速获得MySQL上的水平扩展能力。
OneProxy里分库分表的概念和MySQL里分区表的概念非常接近,来看一下MySQL分区表的创建语法:1
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT NOT NULL,
store_id INT NOT NULL
)
PARTITION BY RANGE (store_id) (
PARTITION p0 VALUES LESS THAN (6),
PARTITION p1 VALUES LESS THAN (11),
PARTITION p2 VALUES LESS THAN (16),
PARTITION p3 VALUES LESS THAN (21)
);
只要给OneProxy提供分区的关键信息,保存到文件“part.txt”中,就可以实现分库分表了,配置信息如下所示:1
[
{
"table" : "empolyees",
"pkey" : "store_id",
"type" : "int",
"method" : "range",
"partitions":
[
{ "suffix" : "_0", "group": "default", "value" : 6 },
{ "suffix" : "_1", "group": "default", "value" : 11 },
{ "suffix" : "_2", "group": "default", "value" : 16 },
{ "suffix" : "_3", "group": "default", "value" : 21 }
]
}
]
然后用这个指定OneProxy的分区配置文件为“part.txt”,启动OneProxy即可。1
${ONEPROXY_HOME}/oneproxy --proxy-address=:3307 \
--proxy-master-addresses=192.168.1.119:3306 \
--proxy-user-list=test/1378F6CC3A8E8A43CA388193FBED5405982FBBD3@test \
--proxy-part-tables=${ONEPROXY_HOME}/part.txt \
--event-threads=8 --proxy-charset=gbk_chinese_ci \
--log-file=${ONEPROXY_HOME}/oneproxy.log \
--pid-file=${ONEPROXY_HOME}/oneproxy.pid
然后在对应的MySQL集群(“default”)里创建好“employees”表,创建表时需要加上后缀(参照“suffix”字段的值),即创建四张表:“employees_0”、“employees_1”、“employees_2”和“employees_3”就行了。也可以修改每个表的集群信息(参照“group”字段的值),让每个表位于不同MySQL主备集群中,来实现完整的分库分表的例子。发下图所示:1
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| employees_0 |
| employees_1 |
| employees_2 |
| employees_3 |
+----------------+
4 rows in set (0.00 sec)
并不需要登录到每一台机器,进行表的创建工作,通过OneProxy可以直接发送如下创建表命令,会自动定位到MySQL服务器并创建包含准确后缀的表。1
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT NOT NULL,
store_id INT NOT NULL
);
接下来可以运行一些DML语句和查询语句试试。1
mysql> insert into employees (id, fname, lname, job_code, store_id)
-> values (4, 'A','B',4,4);
Query OK, 1 row affected (0.00 sec)
mysql> insert into employees (id, fname, lname, job_code, store_id)
-> values (8, 'C','D',8,8);
Query OK, 1 row affected (0.00 sec)
mysql> select * from employees;
+----+-------+-------+------------+------------+----------+----------+
| id | fname | lname | hired | separated | job_code | store_id |
+----+-------+-------+------------+------------+----------+----------+
| 4 | A | B | 1970-01-01 | 9999-12-31 | 4 | 4 |
| 8 | C | D | 1970-01-01 | 9999-12-31 | 8 | 8 |
+----+-------+-------+------------+------------+----------+----------+
2 rows in set (0.00 sec)
mysql> select * from employees_0;
+----+-------+-------+------------+------------+----------+----------+
| id | fname | lname | hired | separated | job_code | store_id |
+----+-------+-------+------------+------------+----------+----------+
| 4 | A | B | 1970-01-01 | 9999-12-31 | 4 | 4 |
+----+-------+-------+------------+------------+----------+----------+
1 row in set (0.00 sec)
mysql> select * from employees_1;
+----+-------+-------+------------+------------+----------+----------+
| id | fname | lname | hired | separated | job_code | store_id |
+----+-------+-------+------------+------------+----------+----------+
| 8 | C | D | 1970-01-01 | 9999-12-31 | 8 | 8 |
+----+-------+-------+------------+------------+----------+----------+
1 row in set (0.00 sec)