クラスタ環境における雪花アルゴリズムのグローバル一意マシンIDポリシーの生成
雪花アルゴリズムはデータidを生成するのに非常に良い方法であり、機械idは雪花アルゴリズムの不可分な一部である.しかし、クラスタアプリケーションでは、異なるマシンに自動的に異なるマシンidを生成させる従来の方法は、各マシンに対して個別の構成を行うことであるが、これはクラスタレベルの拡張に不利であり、操作過程が非常に複雑であるため、各マシンはクラスタ環境下で頭が痛い問題である.現在spring+redisを借りて、勝手なレベルの拡張をサポートし、肥腸が使いやすい戦略を提供しています.大まかな戦略は4つのステップに分けられる:1.マシンipに対してhashを行い、ある(あなたのマシンの個数より大きい)数を型取り、初期のマシンIDとする.2.マシンidをredisに格納する(登録).3.このように,各機器が初期化されたときにredisに1つの数を登録し,この数が登録されていれば+1を再登録する.4.springコンテナの破棄時にredisから登録情報を削除します.次に、実装コードを示します.
@Service("machineIdUtil")
public class MachineIdUtil {
//
private static Logger logger = LogUtil.getLogger(MachineIdUtil.class);
/**
*redis
*/
@Autowired
private Cluster jimClient;
/**
* id
*/
public static Integer machine_id;
/**
* ip
*/
private static String localIp;
private static TimeUnit timeUnit = TimeUnit.DAYS;
/**
* hash IP ID
*/
@PostConstruct
public void initMachineId() throws Exception {
localIp = IpUtil.getInet4Address();
Long ip_ = Long.parseLong(localIp.replaceAll("\\.", ""));
// 128, Ip 。
machine_id = ip_.hashCode()% 128;
// ID
createMachineId();
logger.info(" machine_id :{}", machine_id);
SnowFlakeGenerator.initMachineId(machine_id);
}
/**
*
*/
@PreDestroy
public void destroyMachineId() {
jimClient.del(RedisConstant.OPLOG_MACHINE_ID_kEY + machine_id);
}
/**
* : id
*
* @return
*/
public Integer createMachineId() {
try {
// redis ,
Boolean aBoolean = registMachine(machine_id);
//
if (aBoolean) {
//
updateExpTimeThread();
// Id
return machine_id;
}
// . ,
if (!checkIfCanRegist()) {
// ,
Profiler.businessAlarm("medicine-oplog-createMachineId", System.currentTimeMillis(), "128 !");
return machine_id;
}
logger.info("createMachineId->ip:{},machineId:{}, time:{}", localIp, machine_id, DateUtil.getDate());
//
createMachineId();
} catch (Exception e) {
getRandomMachineId();
return machine_id;
}
getRandomMachineId();
return machine_id;
}
/**
*
*
* @return
*/
private Boolean checkIfCanRegist() {
Boolean flag = true;
// 0~127 IP
for (int i = 0; i <= 127; i++) {
flag = jimClient.exists(RedisConstant.OPLOG_MACHINE_ID_kEY + i);
// 。 。 i
if (!flag) {
machine_id = i;
break;
}
}
return !flag;
}
/**
* 1.
* , ip
*/
private void updateExpTimeThread() {
// :
//1. 23
new Timer(localIp).schedule(new TimerTask() {
@Override
public void run() {
// ip ip , , ID
Boolean b = checkIsLocalIp(String.valueOf(machine_id));
if (b) {
logger.info(" ip:{},machineId:{}, time:{}", localIp, machine_id, DateUtil.getDate("yyyy-MM-dd HH:mm:ss"));
jimClient.expire(RedisConstant.OPLOG_MACHINE_ID_kEY + machine_id, 1, timeUnit);
} else {
logger.info(" ID ip:{},machineId:{}, time:{}", localIp, machine_id, DateUtil.getDate("yyyy-MM-dd HH:mm:ss"));
// ID, ID
getRandomMachineId();
// id
createMachineId();
// ID
SnowFlakeGenerator.initMachineId(machine_id);
//
logger.info("Timer->thread->name:{}", Thread.currentThread().getName());
this.cancel();
}
}
}, 10 * 1000, 1000 * 60 * 60 * 23);
}
/**
* 1~127
*/
public void getRandomMachineId() {
machine_id = (int) (Math.random() * 127);
}
/**
* ID
*/
public void incMachineId() {
if (machine_id >= 127) {
machine_id = 0;
} else {
machine_id += 1;
}
}
/**
* @param mechineId
* @return
*/
private Boolean checkIsLocalIp(String mechineId) {
String ip = jimClient.get(RedisConstant.OPLOG_MACHINE_ID_kEY + mechineId);
logger.info("checkIsLocalIp->ip:{}", ip);
return localIp.equals(ip);
}
/**
* 1.
* 2.
*
* @param mechineId 0~127
* @return
*/
private Boolean registMachine(Integer mechineId) throws Exception {
return jimClient.set(RedisConstant.OPLOG_MACHINE_ID_kEY + mechineId, localIp, 1, TimeUnit.DAYS, false);
}
}