數據量上來後,單庫單表承受不住的時候,我們就需要引入分庫分表。 但是分庫分表後,主鍵id就不能依賴於MySQL,需要從外部去獲取id。
目前我們生產環境在用的DBLE作爲中分庫分表中間件, 其自帶了類似snowflake方案的全局id生成器,也可以基於數據庫來實現。
但是,在一個大點的公司裏面, 全局id 是一個用處很廣泛的服務,通常會獨立作爲一個公共服務對外提供。
這裏我們就以 美團點評出的 Leaf爲例,看下它的效果。
相關文檔:
https://tech.meituan.com/2019/03/07/open-source-project-leaf.html
https://tech.meituan.com/2017/04/21/mt-leaf.html
https://blog.csdn.net/bskfnvjtlyzmv867/article/details/90175306 源碼詳解
官方的2篇文檔,介紹的很詳細了,我們就不囉嗦了。
下面的演示,是基於數據庫做id分發 (數據庫的SLA可以使用MHA、pxc或mgr來保證)
0 環境
OS版本: CentOS7
node1 IP: 192.168.20.10
node2 IP: 192.168.20.17
MySQL地址: 192.168.20.10
1 創建數據庫表等
CREATE DATABASE leaf ; use leaf ; CREATE TABLE `leaf_alloc` ( `biz_tag` varchar(128) NOT NULL DEFAULT '', -- your biz unique name `max_id` bigint(20) NOT NULL DEFAULT '1', `step` int(11) NOT NULL, `description` varchar(256) DEFAULT NULL, `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`biz_tag`) ) ENGINE=InnoDB; -- 插入幾條需要分發id的服務的標識(我這裏在默認的基礎上,加了 卡券id、帖子id 這2個例子) insert into leaf_alloc(biz_tag, max_id, step, description) values('leaf-segment-test', 1, 2000, 'Test leaf Segment Mode Get Id'); insert into leaf_alloc(biz_tag, max_id, step, description) values('coupon', 1, 2000, 'Get coupon Id'); insert into leaf_alloc(biz_tag, max_id, step, description) values('tid', 1, 1000, 'Get tiezi id'); select * from leaf_alloc ; +-------------------+--------+------+-------------------------------+---------------------+ | biz_tag | max_id | step | description | update_time | +-------------------+--------+------+-------------------------------+---------------------+ | coupon | 1 | 2000 | Get coupon Id | 2019-10-12 17:47:23 | | leaf-segment-test | 1 | 2000 | Test leaf Segment Mode Get Id | 2019-10-12 17:47:00 | | tid | 1 | 1000 | Get tiezi id | 2019-10-12 17:48:21 | +-------------------+--------+------+-------------------------------+---------------------+ 3 rows in set (0.001 sec) -- 創建獨立的數據庫賬號 create user leaf@'%' identified by 'leaf1234'; grant select,update,delete,insert on leaf.* to leaf@'%';
2 編譯leaf-server
注意:需要在node1和node2上單獨執行編譯和啓動的操作,編譯+啓動 依賴到 maven 和 oracle-jdk
cd /usr/local/ git clone https://github.com/Meituan-Dianping/Leaf.git cd leaf mvn clean install -DskipTests cd leaf-server
vim leaf-server/src/main/resources/leaf.properties 修改配置文件中數據庫的連接方式
leaf.name=com.sankuai.leaf.opensource.test leaf.segment.enable=true leaf.jdbc.url=jdbc:mysql://192.168.20.10:3306/leaf?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8 leaf.jdbc.username=leaf leaf.jdbc.password=leaf1234 leaf.snowflake.enable=false #leaf.snowflake.zk.address= #leaf.snowflake.port=
3 啓動leaf-server:
cd /usr/local/leaf/leaf-server mvn spring-boot:run
4 測試
測試我上面插入的3個biz_tag的發號器情況:
curl http://192.168.20.10:8080/api/segment/get/leaf-segment-test
curl http://192.168.20.10:8080/api/segment/get/coupon
curl
http://192.168.20.10:8080/api/segment/get/tid5 其它
號段模式自帶了個監控界面:
http://192.168.20.10:8080/cache測試id的生成效果:
for i in {1..2000}; do curl http://192.168.20.17:8080/api/segment/get/coupon; done for i in {1..2000}; do curl http://192.168.20.10:8080/api/segment/get/coupon; done
然後,我們在for循環獲取id的時候,人爲的把MySQL關閉掉,可以看到如下的,可以看到剛開始leaf因爲號段+雙buffer的存在,可以繼續發號,但是當預分配的id都用光後,就會報錯了:
只要我們的MySQL數據庫故障切換的時候不要太久,並且配合設置不同biz_tag以不同大小的step,通不會對對leaf服務造成影響。
下面是雙buffer在web界面上的體現: