問題及需求
單庫下?般使用Mysql自增ID,但是分庫分表后,會(huì)造成不同分片上的數(shù)據(jù)表主鍵會(huì)重復(fù)
需求:性能強(qiáng)勁、全局唯一、防止惡意用戶規(guī)矩id的規(guī)則來獲取數(shù)據(jù)
常用ID解決方案
數(shù)據(jù)庫自增ID
利用自增id, 設(shè)置不同的?增步長:auto_increment_offset
、auto-increment-increment
DB1: 單數(shù)
//從1開始、每次加2
DB2: 偶數(shù)
//從2開始,每次加2
缺點(diǎn):
- 依靠數(shù)據(jù)庫系統(tǒng)的功能實(shí)現(xiàn),但是未來擴(kuò)容麻煩
- 主從切換時(shí)的不?致可能會(huì)導(dǎo)致重復(fù)發(fā)號
- 性能瓶頸存在單臺sql上
UUID
性能非常高,沒有網(wǎng)絡(luò)消耗
缺點(diǎn):
- 無序的字符串,不具備趨勢自增特性
- UUID太長,不易于存儲,浪費(fèi)存儲空間,很多場景不適用
Redis發(fā)號器
利用Redis的INCR和INCRBY來實(shí)現(xiàn),原子操作,線程安全,性能比Mysql強(qiáng)勁
缺點(diǎn):
- 需要占用網(wǎng)絡(luò)資源,增加系統(tǒng)復(fù)雜度
Snowflake雪花算法
- twitter 開源的分布式 ID生成算法,代碼實(shí)現(xiàn)簡單、不占用寬帶、數(shù)據(jù)遷移不受影響
- 生成的 id 中包含有時(shí)間戳,所以生成的 id按照時(shí)間遞增
- 部署了多臺服務(wù)器,需要保證系統(tǒng)時(shí)間?樣,機(jī)器編號不?樣
缺點(diǎn):
- 依賴系統(tǒng)時(shí)鐘(多臺服務(wù)器時(shí)間?定要?樣)
分布式 ID 生成算法Snowflake原理
關(guān)于bit與byte
bit(位):電腦中存儲的最小單位,可以存儲?進(jìn)制中的0或1
byte(字節(jié)):?個(gè)byte由8個(gè)bit組成
常規(guī)64位系統(tǒng)??java數(shù)據(jù)類型存儲字節(jié)大小
int:4 個(gè)字節(jié)
short:2 個(gè)字節(jié)
long:8 個(gè)字節(jié)
byte:1 個(gè)字節(jié)
float:4 個(gè)字節(jié)
double:8 個(gè)字節(jié)
char:2 個(gè)字節(jié)
科普:數(shù)據(jù)類型在不同位數(shù)機(jī)器的平臺下長度不同
16位平臺 int 2個(gè)字節(jié)16位
32位平臺 int 4個(gè)字節(jié)32位
64位平臺 int 4個(gè)字節(jié)32位
雪花算法的位數(shù)
雪花算法生成的數(shù)字,long類,所以是:8個(gè)byte,64bit
表示的值 -9223372036854775808(-2的63次方)~9223372036854775807(2的63次?-1)
生成的唯?值?于數(shù)據(jù)庫主鍵,不能是負(fù)數(shù),所以值為0~9223372036854775807(2的63次方-1)
- 第一個(gè)bit位代表符號位,正數(shù)是0,負(fù)數(shù)是1,ID為正數(shù),所以固定為0
- 毫秒級時(shí)間戳部分占41bit,不是存儲當(dāng)前時(shí)間的時(shí)間截,服務(wù)上線的時(shí)間毫秒級的時(shí)間戳(為當(dāng)前時(shí)間-服務(wù)第一次上線時(shí)間)
- 工作機(jī)器 id占10bit,可支持210 =1024個(gè)節(jié)點(diǎn)
- 序列號部分占12bit,可允許同一毫秒生成212 =4096個(gè)Id,則理論上一秒就可生成4096*1000 = 400萬個(gè)ld
- 組合起來剛好是64位,Long類型
Snowflake必須注意的地方
全局唯?、不能重復(fù)
分布式部署就需要分配不同的workId, 如果workId相同,
可能會(huì)導(dǎo)致?成的id相同
保證各個(gè)系統(tǒng)時(shí)間一致
分布式情況下,需要保證各個(gè)系統(tǒng)時(shí)間?致,如果服務(wù)器的時(shí)鐘回?fù)?,就?huì)導(dǎo)致?成的 id 重復(fù)
什么時(shí)候會(huì)系統(tǒng)回?fù)埽?/strong>
- 人工去生產(chǎn)環(huán)境做了系統(tǒng)時(shí)間調(diào)整
- 業(yè)務(wù)需求,代碼里面做了系統(tǒng)時(shí)間同步
Snowflake雪花算法實(shí)現(xiàn)
配置文件
增加:
#配置workId
spring.shardingsphere.sharding.tables.product_order.key-generator.props.worker.id=1
方式一:訂單id使用MybatisPlus的配置,ProductOrder類配置
@TableId(value = "id", type = IdType.ASSIGN_ID)
默認(rèn)實(shí)現(xiàn)類為DefaultIdentifierGenerator雪花算法
方式二:使用Sharding-Jdbc配置文件,注釋DO類里面的id分配策略
#id?成策略
spring.shardingsphere.sharding.tables.product_order.key-generator.column=id
spring.shardingsphere.sharding.tables.product_order.key-generator.type=SNOWFLAKE
方式三 進(jìn)階:動(dòng)態(tài)指定sharding jdbc 的雪花算法中的屬性work.id屬性
使用sharding-jdbc中的使用IP后幾位來做workId,但在某些情況下會(huì)出現(xiàn)生成重復(fù)ID的情況
解決辦法: 在啟動(dòng)時(shí)給每個(gè)服務(wù)分配不同的workId, 引?redis/zk都行,缺點(diǎn)就是多了依賴
配置文件完整
spring.application.name=xdclass-sharding-jdbc
server.port=8080
# 打印執(zhí)行的數(shù)據(jù)庫以及語句
spring.shardingsphere.props.sql.show=true
# 數(shù)據(jù)源 db0
spring.shardingsphere.datasource.names=ds0,ds1
# 第一個(gè)數(shù)據(jù)庫
spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://10.24.201.232:3306/xdclass_shop_order_0?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=root
# 第二個(gè)數(shù)據(jù)庫
spring.shardingsphere.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds1.jdbc-url=jdbc:mysql://10.24.201.232:3306/xdclass_shop_order_1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=root
#配置workId
spring.shardingsphere.sharding.tables.product_order.key-generator.props.worker.id=1
#id生成策略
spring.shardingsphere.sharding.tables.product_order.key-generator.column=id
spring.shardingsphere.sharding.tables.product_order.key-generator.type=SNOWFLAKE
# 指定product_order表的數(shù)據(jù)分布情況,配置數(shù)據(jù)節(jié)點(diǎn),行表達(dá)式標(biāo)識符使用 ${...} 或 $->{...},
# 但前者與 Spring 本身的文件占位符沖突,所以在 Spring 環(huán)境中建議使用 $->{...}
spring.shardingsphere.sharding.tables.product_order.actual-data-nodes=ds0.product_order_$->{0..1}
# 指定product_order表的分片策略,分片策略包括【分片鍵和分片算法】
spring.shardingsphere.sharding.tables.product_order.table-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.tables.product_order.table-strategy.inline.algorithm-expression=product_order_$->{user_id % 2}
雪花算法測試結(jié)果
文章來源:http://www.zghlxwxcb.cn/news/detail-483961.html
可以看出id全局不重復(fù),并呈現(xiàn)出遞增增長文章來源地址http://www.zghlxwxcb.cn/news/detail-483961.html
到了這里,關(guān)于掌握MySQL分庫分表(六)解決主鍵重復(fù)問題--Snowflake雪花算法的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!