OneProxy:只需修改少量SQL语句,也可以实现快速实现分库分表的可扩展方案(转)

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)

Via:http://www.onexsoft.com/?page_id=378