Spring Boot集成全局惟一ID生成器 UidGenerator

 
流水號生成器(全局惟一 ID生成器)是服務化系統的基礎設施,其在保障系統的正確運行和高可用方面發揮着重要做用。而關於流水號生成算法數一數二的當屬 Snowflake雪花算法,然而 Snowflake自己很難在現實項目中直接使用,所以實際應用時須要一種可落地的方案。
Snowflake倉庫
https://github.com/twitter/sn...
UidGenerator 由百度用Java語言開發的, 基於 Snowflake算法的惟一ID生成器。UidGenerator以組件形式工做在應用項目中, 支持自定義workerId位數和初始化策略, 從而適用於docker等虛擬化環境下實例自動重啓、漂移等場景。
UidGenerator倉庫
https://github.com/baidu/uid-...
UidGenerator中文文檔
https://github.com/baidu/uid-...
0x01:先在 pom.xml中添加相關依賴
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!--for Mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
<version>8.0.12</version>
</dependency>
<!-- druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.9</version>
</dependency>
<!--必須放在最後-->
<dependency>
<groupId>cn.codesheep</groupId>
<artifactId>uid-generator</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
0x02: application.properties配置文件中添加配置(主要是 MySQL和 MyBatis配置)
server.port=9999
spring.datasource.url=jdbc:mysql://xxx.xxx.xxx.xxx:3306/xxx?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=xxx
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.configuration.map-underscore-to-camel-case=true
0x03:建立數據庫表
運行sql腳本以導入表WORKER_NODE, 腳本以下
DROP DATABASE IF EXISTS xxxx;
CREATE DATABASE xxxx ;
use xxxx;
DROP TABLE IF EXISTS WORKER_NODE;
CREATE TABLE WORKER_NODE
(
ID BIGINT NOT NULL AUTO_INCREMENT COMMENT 'auto increment id',
HOST_NAME VARCHAR(64) NOT NULL COMMENT 'host name',
PORT VARCHAR(64) NOT NULL COMMENT 'port',
TYPE INT NOT NULL COMMENT 'node type: ACTUAL or CONTAINER',
LAUNCH_DATE DATE NOT NULL COMMENT 'launch date',
MODIFIED TIMESTAMP NOT NULL COMMENT 'modified time',
CREATED TIMESTAMP NOT NULL COMMENT 'created time',
PRIMARY KEY(ID)
)
COMMENT='DB WorkerID Assigner for UID Generator',ENGINE = INNODB;
0x04:Spring配置
提供了兩種生成器: DefaultUidGenerator、CachedUidGenerator。如對UID生成性能有要求, 請使用CachedUidGenerator
對應Spring配置分別爲: default-uid-spring.xml、cached-uid-spring.xml
DefaultUidGenerator配置
<!-- DefaultUidGenerator -->
<bean id="defaultUidGenerator" class="com.baidu.fsg.uid.impl.DefaultUidGenerator" lazy-init="false">
<property name="workerIdAssigner" ref="disposableWorkerIdAssigner"/>
<!-- Specified bits & epoch as your demand. No specified the default value will be used -->
<property name="timeBits" value="29"/>
<property name="workerBits" value="21"/>
<property name="seqBits" value="13"/>
<property name="epochStr" value="2016-09-20"/>
</bean>
<!-- 用完即棄的WorkerIdAssigner,依賴DB操做 -->
<bean id="disposableWorkerIdAssigner" class="com.baidu.fsg.uid.worker.DisposableWorkerIdAssigner" />
CachedUidGenerator配置
<!-- CachedUidGenerator -->
<bean id="cachedUidGenerator" class="com.baidu.fsg.uid.impl.CachedUidGenerator">
<property name="workerIdAssigner" ref="disposableWorkerIdAssigner" />
<!-- 如下爲可選配置, 如未指定將採用默認值 -->
<!-- Specified bits & epoch as your demand. No specified the default value will be used -->
<property name="timeBits" value="29"/>
<property name="workerBits" value="21"/>
<property name="seqBits" value="13"/>
<property name="epochStr" value="2016-09-20"/>
<!-- RingBuffer size擴容參數, 可提升UID生成的吞吐量. -->
<!-- 默認:3, 原bufferSize=8192, 擴容後bufferSize= 8192 << 3 = 65536 -->
<property name="boostPower" value="3"></property>
<!-- 指定什麼時候向RingBuffer中填充UID, 取值爲百分比(0, 100), 默認爲50 -->
<!-- 舉例: bufferSize=1024, paddingFactor=50 -> threshold=1024 * 50 / 100 = 512. -->
<!-- 當環上可用UID數量 < 512時, 將自動對RingBuffer進行填充補全 -->
<property name="paddingFactor" value="50"></property>
<!-- 另一種RingBuffer填充時機, 在Schedule線程中, 週期性檢查填充 -->
<!-- 默認:不配置此項, 即不實用Schedule線程. 如需使用, 請指定Schedule線程時間間隔, 單位:秒 -->
<property name="scheduleInterval" value="60"></property>
<!-- 拒絕策略: 當環已滿, 沒法繼續填充時 -->
<!-- 默認無需指定, 將丟棄Put操做, 僅日誌記錄. 若有特殊需求, 請實現RejectedPutBufferHandler接口(支持Lambda表達式) -->
<property name="rejectedPutBufferHandler" ref="XxxxYourPutRejectPolicy"></property>
<!-- 拒絕策略: 當環已空, 沒法繼續獲取時 -->
<!-- 默認無需指定, 將記錄日誌, 並拋出UidGenerateException異常. 若有特殊需求, 請實現RejectedTakeBufferHandler接口(支持Lambda表達式) -->
<property name="rejectedTakeBufferHandler" ref="XxxxYourTakeRejectPolicy"></property>
</bean>
<!-- 用完即棄的WorkerIdAssigner, 依賴DB操做 -->
<bean id="disposableWorkerIdAssigner" class="com.baidu.fsg.uid.worker.DisposableWorkerIdAssigner" />
Mybatis配置,mybatis-spring.xml配置說明以下:
<!-- Spring annotation掃描 -->
<context:component-scan base-package="com.baidu.fsg.uid" />
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations" value="classpath:/META-INF/mybatis/mapper/M_WORKER*.xml" />
</bean>
<!-- 事務相關配置 -->
<tx:annotation-driven transaction-manager="transactionManager" order="1" />
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- Mybatis Mapper掃描 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="annotationClass" value="org.springframework.stereotype.Repository" />
<property name="basePackage" value="com.baidu.fsg.uid.worker.dao" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean>
<!-- 數據源配置 -->
<bean id="dataSource" parent="abstractDataSource">
<property name="driverClassName" value="${mysql.driver}" />
<property name="maxActive" value="${jdbc.maxActive}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="abstractDataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="filters" value="${datasource.filters}" />
<property name="defaultAutoCommit" value="${datasource.defaultAutoCommit}" />
<property name="initialSize" value="${datasource.initialSize}" />
<property name="minIdle" value="${datasource.minIdle}" />
<property name="maxWait" value="${datasource.maxWait}" />
<property name="testWhileIdle" value="${datasource.testWhileIdle}" />
<property name="testOnBorrow" value="${datasource.testOnBorrow}" />
<property name="testOnReturn" value="${datasource.testOnReturn}" />
<property name="validationQuery" value="${datasource.validationQuery}" />
<property name="timeBetweenEvictionRunsMillis" value="${datasource.timeBetweenEvictionRunsMillis}" />
<property name="minEvictableIdleTimeMillis" value="${datasource.minEvictableIdleTimeMillis}" />
<property name="logAbandoned" value="${datasource.logAbandoned}" />
<property name="removeAbandoned" value="${datasource.removeAbandoned}" />
<property name="removeAbandonedTimeout" value="${datasource.removeAbandonedTimeout}" />
</bean>
<bean id="batchSqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
<constructor-arg index="1" value="BATCH" />
</bean>
0x05:測試
@Resource
private UidGenerator uidGenerator;
@Test
public void testSerialGenerate() {
// Generate UID
long uid = uidGenerator.getUID();
// Parse UID into [Timestamp, WorkerId, Sequence]
// {"UID":"180363646902239241","parsed":{ "timestamp":"2017-01-19 12:15:46", "workerId":"4", "sequence":"9" }}
System.out.println(uidGenerator.parseUID(uid));
}java

相關文章
相關標籤/搜索