OneProxy :: 如何生成生成分库分表下的主键值?可以使用分布式Sequence服务!

上次分享的分布式主键生成机制非常不错,完全不依赖于数据库,但缺点是生成的数字至少是16位的,可能会导致主键值过长而浪费空间。有没有一种可以自定义的主键值生成机制,比如只生成单数或只生成偶数,并且可以从“1”开始?由于我们非常了解Oracle中Sequence对象的内部工作机制,可以轻松地在OneProxy中间件上实现一套类似的机制(也可以在MySQL端实现,只要敢用我们的定制MySQL版本)。和Oracle一样,需要在MySQL数据库中创建一张保存Sequence定议的表(表名:“oneproxy_sequence”,在Oracle中是系统表“seq$”),表结构如下所示(比Oracle的表结构定义要简单)。

 CREATE TABLE `oneproxy_sequence` (
  `seq_name` varchar(32) NOT NULL,
  `seq_start` bigint(20) NOT NULL,
  `seq_cache` bigint(20) NOT NULL,
  `seq_step` bigint(20) NOT NULL,
  PRIMARY KEY (`seq_name`)
) ENGINE=InnoDB;

然后需要向表中插入Sequence的定义,“seq_start”列表示初始值,“seq_cache”表示在中间件中的缓存大小(当中间件缓存中的值被用完时,会从后端MySQL中取一批出来,此选项值越大表示从MySQL上取值的机会越小,性能会越好),“seq_step”表示步长(下一个值 是当前值加上步长)。

mysql> select * from oneproxy_sequence;
+----------+-----------+-----------+----------+
| seq_name | seq_start | seq_cache | seq_step |
+----------+-----------+-----------+----------+
| default  |         1 |        10 |        2 |
+----------+-----------+-----------+----------+
1 row in set (0.00 sec)

接下来还需要在OneProxy中间件的配置文件中指定有哪些Sequence对象,请注意“proxy-sequence”选项。

[oneproxy]
keepalive     = 1
event-threads = 4
log-file      = log/oneproxy.log
pid-file      = log/oneproxy.pid

proxy-address = :3307
proxy-master-addresses.1 = 192.168.1.119:3306@server1
proxy-user-list = test/956C97523BADD23B6091B09E332A77B5CBDBBEEF@test

proxy-sequence.1 = default

然后就可以在OneProxy工作端口中使用“sequence”命令来取值了(格式:“SEQUENCE seq_name [seq_count]”)。在做数据批量装载时,还可以一次取多个值。

[root@rh4srv1]#  mysql -utest -p123 -h127.0.0.1 -P3307 -c -e "sequence default"
+----------+
| SEQUENCE |
+----------+
|        1 |
+----------+
[root@rh4srv1]#  mysql -utest -p123 -h127.0.0.1 -P3307 -c -e "sequence default 5"
+----------+
| SEQUENCE |
+----------+
|        3 |
|        5 |
|        7 |
|        9 |
|       11 |
+----------+

前面的例子中我们配置了一个单号Sequence,可以另外一个MySQL实例上配置双号Sequence。

mysql> select * from oneproxy_sequence;
+----------+-----------+-----------+----------+
| seq_name | seq_start | seq_cache | seq_step |
+----------+-----------+-----------+----------+
| default  |         2 |        10 |        2 |
+----------+-----------+-----------+----------+
1 row in set (0.00 sec)

然后将这两台MySQL实例归到同一个组,并且设置组策略为“write_balance”来做负载均衡,就可以防止Sequence数据库的单点故障了。

[oneproxy]
keepalive     = 1
event-threads = 4
log-file      = log/oneproxy.log
pid-file      = log/oneproxy.pid
proxy-address = :3307
proxy-master-addresses.1 = 192.168.1.119:3306@server1
proxy-master-addresses.2 = 192.168.1.120:3306@server1
proxy-user-list = test/956C97523BADD23B6091B09E332A77B5CBDBBEEF@test
proxy-group-policy=server1:write_balance

proxy-sequence.1 = default

当OneProxy中缓存的Sequence用光后,会从数据库中去获取一批进行缓存,缓存的大于取决于“seq_cache”列的值,越大(比如设置成1000个)性能会越好。当分为奇偶两个库时,会从任何一个库中去取数,因此并不保证Sequence是顺序生成的,能保证唯一,并且可以保证单个MySQL实例的不可用不会影响整体Sequence的可用性。也可以布署成三个或更多的,在同城多IDC的情况下,可以每一个IDC中放一个Sequence的MySQL实例,来做跨IDC的高可用。

mysql> select * from oneproxy_sequence;
+----------+-----------+-----------+----------+
| seq_name | seq_start | seq_cache | seq_step |
+----------+-----------+-----------+----------+
| default  |        21 |        10 |        2 |
+----------+-----------+-----------+----------+
1 row in set (0.00 sec)

OnePorxy本身也可以布署多台做7×24的高可用。当OneProxy意外停止或正常停止时,在缓存中没有使用的Sequence值会丢失,因此也不能保证连续,在使用时需要考虑到这一点。