顺序全局id生成方案-flickr-进阶

flickr:http://wangxinchun.iteye.com/blog/2373125

目前flickr 方案存在的问题:

性能较差,每次都要连接数据库db,高并发下db吃力

新方案:

数据库每次批量返回多个id记录;双Buffer请求消峰,增加可用性

设计思路:

1、利用数据库的锁和事务

2、每次获取返回本次拿到min_id,max_id,step,batch_size,其中有效的记录是:id = min_id + n*step ,并且 id<=max_id

3、为了削弱波峰请求的影响,双Buffer机制,当id 取到 id > (min_id+max_id)/2 时,加载第二个Buffer

其中 2  和 3 需要服务的代理来实现

db 初始化数据如下:

DROP TABLE idg_1;
DROP TABLE idg_2;
DROP TABLE idg_3;


CREATE TABLE `idg_1` (
   `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
   `key` VARCHAR(100) DEFAULT '',
   `min_id` BIGINT(20) NOT NULL ,
   `max_id` BIGINT(20) NOT NULL DEFAULT '0',
   `step` INT(11) NOT NULL DEFAULT '3',
   `batch_size` INT(11) NOT NULL DEFAULT '3000',
   UNIQUE KEY `id` (`id`),
   UNIQUE KEY `idx_key` (`key`)
 ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
 
 
 CREATE TABLE `idg_2` (
   `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
   `key` VARCHAR(100) DEFAULT '',
   `min_id` BIGINT(20) NOT NULL ,
   `max_id` BIGINT(20) NOT NULL DEFAULT '0',
   `step` INT(11) NOT NULL DEFAULT '3',
   `batch_size` INT(11) NOT NULL DEFAULT '3000',
   UNIQUE KEY `id` (`id`),
   UNIQUE KEY `idx_key` (`key`)
 ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
 
 
 CREATE TABLE `idg_3` (
   `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  `key` VARCHAR(100) DEFAULT '',
   `min_id` BIGINT(20) NOT NULL ,
   `max_id` BIGINT(20) NOT NULL DEFAULT '0',
   `step` INT(11) NOT NULL DEFAULT '3',
   `batch_size` INT(11) NOT NULL DEFAULT '3000',
   UNIQUE KEY `id` (`id`),
   UNIQUE KEY `idx_key` (`key`)
 ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
 
 
 INSERT INTO idg_1(`key`,max_id,min_id,step,batch_size) VALUE ('nts',1,1,3,1000);
 INSERT INTO idg_2(`key`,max_id,min_id,step,batch_size) VALUE ('nts',2,2,3,1000);
 INSERT INTO idg_3(`key`,max_id,min_id,step,batch_size) VALUE ('nts',3,3,3,1000);
 
 
#模拟数据查询
BEGIN
UPDATE idg_1 t  SET t.min_id =t.max_id+step,  t.max_id = max_id + step*batch_size WHERE `key` = 'nts';
SELECT t.min_id,t.max_id,t.step,t.batch_size  FROM idg_1 t WHERE `key` = 'nts';
COMMIT;
END;

BEGIN
UPDATE idg_2 t  SET t.min_id =t.max_id+step,  t.max_id = max_id + step*batch_size WHERE `key` = 'nts';
SELECT t.min_id,t.max_id,t.step,t.batch_size  FROM idg_2 t WHERE `key` = 'nts';
COMMIT;
END;

BEGIN
UPDATE idg_3 t  SET t.min_id =t.max_id+step,  t.max_id = max_id + step*batch_size WHERE `key` = 'nts';
SELECT t.min_id,t.max_id,t.step,t.batch_size  FROM idg_3 t WHERE `key` = 'nts';
COMMIT;
END; 
 

后记:

如果需要扩容,也很简单,只需要修改min_id,max_id,step 即可

1、先改动batch_size 足够大,保证操作期间不会有请求

2、修改min_id,max_id,step

注意:

step:机器数目

min_id = 一个上次返回的最大值+new_step

max_id=min_id 即可

这个思路稍微改动DB,可以升级到redis方案

猜你喜欢

转载自wangxinchun.iteye.com/blog/2373191