其实百度的UidGenerator生成器也是基于snowflake算法的,在原生的项目中使用的基于数据库的,我改造成了基于zookpeer的,用zookpeer的序列号实现分布式seq的生成(代替了算法中的机器码);
关于uidgenerator我这里就不多说了,不了解的可以去看下资料http://blog.csdn.net/littlesmallless/article/details/69663640
修改的关键代码:
/**
* 提前创建好存储Seq的"/createSeq"结点 CreateMode.PERSISTENT
*/
public static final String SEQ_ZNODE = "/parent";
/**
* session失效时间
*/
public static final int SESSION_TIMEOUT = 3000;
/**
* connection连接时间
*/
public static final int CONNECTION_TIMEOUT = 3000;
@Value("${zookeeper.connection}")
public String connectString;
/**
* 通过znode数据版本实现分布式seq生成
*/
public long znodeSeq(){
ZkClient zkClient = new ZkClient(connectString, SESSION_TIMEOUT, CONNECTION_TIMEOUT);
Stat stat =zkClient.writeData(SEQ_ZNODE, new byte[0], -1);
long versionAsSeq = stat.getVersion();
System.out.println("obtain seq=" +versionAsSeq );
zkClient.close();
return versionAsSeq;
}
我这里已经修改好了jar包,可以去下载
http://download.csdn.net/download/gaoshili001/10217478
使用方法也比较简单:
1、在项目中的pom.xml文件中引入
<!-- 添加百度uid-generator -->
<dependency>
<groupId>com.baidu.fsg</groupId>
<artifactId>uid-generator</artifactId>
<version>1.0.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>
2、引入xml文件:我使用的是cached-uid-spring.xml
cached-uid-spring.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<!-- UID generator -->
<bean id="disposableWorkerIdAssigner" class="com.baidu.fsg.uid.worker.DisposableWorkerIdAssigner" />
<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="31"/>
<property name="workerBits" value="23"/>
<property name="seqBits" value="9"/>
<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="rejectedPutBufferHandler" ref="XxxxYourPutRejectPolicy"></property>-->
</bean>
</beans>
3、我使用的是springboot框架(其他框架的自行配置),在application.properties中配置zookpeer的连接地址:
## id生成器zookpeer地址
zookeeper.connection=192.168.40.23:2181
4、uid生成器配置
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
/**
* id生成器配置
*
* @author 高仕立
* @date 2017/12/21 21:34
*/
@Configuration
@ImportResource(locations = { "classpath:uid/cached-uid-spring.xml" })
public class UidConfig {
}
5、工具类
import com.baidu.fsg.uid.UidGenerator;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Set;
/**
* id生成器工具类
*
* @author 高仕立
* @date 2017/12/21 19:31
*/
@Component
public class UidGeneratorComponent {
@Resource
private UidGenerator uidGenerator;
public long doGenerate(Set<Long> uidSet) {
long uuid = 0;
long uid = uidGenerator.getUID();
boolean existed = uidSet.add(uid);
if (existed) {
uuid = uid;
}
return uuid;
}
}
6、项目中的配置完成了,只需要在服务中注入这个工具类就可以生成全局唯一id了,但是还需要比较重要的一步 ,这个跟
项目本身关系不大,我当时写工具类的时候没有封装的太好,zookpeer的parent节点需要在zookpeer中手动去创建,后续
有时间再改吧,先这样用。