/id_server

分布式id生成服务器,根据规则和命名空间创建唯一id,集群部署可实现高可用

Primary LanguageC++

系统概述

服务器的主要功能是根据预定义的规则和自定义的命名空间创建一定范围和周期内唯一ID 。 
为了保证高可用性,一般以集群方式运行,每个服务器是独立和对等的节点,即master-master模式。
客户端可以使用集群中任意选择一个服务器节点发起请求,失败则重试下一个。

系统实现

使用c++实现,运行在linux下,依赖mysqlclient库、lua库和tcmalloc库,
采用多线程异步模型,主线程处理请求,数据库线程组负责异步写数据库。
主线程和数据库线程采用eventfd + lockfree queue方式通信。
数据的持久化存储采用批量+预保存模式,减少数据库压力,保障数据落地的可靠性。

依赖库

mysql-devel-5.1
lua-devel-5.1
gperftools-devel-2.0

性能

性能测试做的比较简单,以php为客户端进行测试。
服务器为4核E5-2620 v2 @ 2.10GHz虚拟机。
客户端为4个php并发进程,每个进程不停发送20万个请求,测试结果:
total:200000 fail:0 min:0.000214 max:0.087330 avg:0.000393
total:200000 fail:0 min:0.000215 max:0.087129 avg:0.000391
total:200000 fail:0 min:0.000221 max:0.087252 avg:0.000391
total:200000 fail:0 min:0.000218 max:0.087484 avg:0.000391
说明  min : 最小耗时(秒) max : 最大耗时(秒) avg : 平均耗时(秒)
服务器TPS达到1万/秒时,平均延迟在0.3毫秒。

配置项

{
    "log_prefix" : "id_server" ,    //日志文件前缀
    "log_level" :3 ,                //日志级别

    "service_host" : "127.0.0.1",   //服务IP
    "service_port" : 1200 ,         //服务端口
    "thread_count" : 4 ,            //数据库线程
    "queue_size" : 100000 ,         //线程队列
    "id_step" : 2 ,                 // ID自增的步长,也可以理解为同时运行的服务器数量
    "id_offset" : 0 ,               // ID自增的偏移量,也可以理解为每个服务器的ID,从0开始,不能超过step

    "database": {"host":"localhost","port":3306,"user":"dev","password":"dev","charset":"utf8","dbname":"id_counter" }, 

    "rules" : [
        {"name": "order_id" , "lua_file":"order_id.lua", "batch_save":100 } , //batch_save表示批量预更新counter的数量
        {"name": "task" , "lua_file":"task.lua", "batch_save":100 }
    ]

}

ID规则定义

具体规则有lua脚本定义,修改脚本后需要reload生效,需要实现4个函数
min_counter :   计数器最小值
max_counter :   计数器最大值
reset_seconds : 计数器重置周期
create_id : 根据计数器、自定义参数和时间参数创建ID。
参见:
function min_counter()
    return 0
end
function max_counter()
    return 9999
end
function reset_seconds()
    return 86400
end
function create_id(counter,now,salt)
    local seq = counter:generate_counter()
    local new_id = string.format("%01d%02d%02d%04d",now:year()%10 ,now:month(),now:day(),seq)
    return new_id
end

接口

采用udp协议,数据格式为json ,字段定义:
action: 请求类型 get: 创建ID ,  monitor:监控
rule_name: 规则名字, 由服务端定义
app_name : 应用名或命名空间 , 客户端自定义,rule_name和app_name一起决定生成ID的唯一性
salt :  自定义参数 ,可选项 , 
seq : 自定义参数,可选项,原样返回


创建ID请求:  {"action":"get","rule_name":"o2o","app_name":"test"}  
响应:{"code":0,"message":"success","data":"505140001"}

监控请求:{"action":"monitor","rule_name":"o2o","app_name":"test"}   
响应:{"code":0,"message":"ok","data":{"counter":3,"node_offset":1}}

编译

$make release
$make install 
make install会将部署所需的文件拷贝到deploy目录下 。

创建数据库

$mysql < deploy/counter.sql

启动服务器

$deploy/server_ctl.sh start id_server 1
修改配置后使用控制脚本server_ctl.sh控制系统的启动和关闭。

系统控制脚本用法 ,可根据需要修改
server_ctl.sh start|stop|reload id_server {server_id}
载入的配置文件为 id_server_{server_id}.xml
修改配置后reload即可,为保证数据安全,只支持规则列表和日志的reload,其他配置修改后需要重启。