1. 概述
ID生成器是IM,电商系统中绕不过去的一个组件。对于系统中发生的每个事件,如IM发送的每一条消息,电商平台的每个订单都需要生成一个ID,这个ID成为事件的唯一标识,提供之后的跟踪与检索工作。网络上微信与美团等知名厂商都分享了自己的ID生成算法,对于大型系统,ID生成算法都是分布式ID算法,基础算法使用了snowflake或分段自增等算法。
ID生成器的调用通常为RPC方式,目前常用的使用方式有GRPC,HTTP等调用方式。本文介绍如何使用JAVA RMI的方式快速实现一个简单ID生成器。
2.接口定义
RMI的接口供ID生成器和调用ID生成器的客户端使用,定义如下:
package com.kedacom.rmiinterface;
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
* @author zhang.kai
*
*/
public interface IIdGen extends Remote{
public long getNextId() throws RemoteException;
}
3. 服务端
服务端实现ID的分发,这里使用一个简单的自增算法,可以设定ID的初始值(这里简单地以服务初始化时间作为初始值),定义如下:
package com.kedacom.rmiserver.service;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.concurrent.atomic.AtomicLong;
import com.kedacom.rmiinterface.IIdGen;
/**
* @author zhang.kai
*
*/
public class IdGenService extends UnicastRemoteObject implements IIdGen{
private static final long serialVersionUID = -3742466067930952734L;
private final AtomicLong idSeed ;
/**
* @param port
* @throws RemoteException
*/
public IdGenService() throws RemoteException {
super();
idSeed = new AtomicLong(getInitValue());
}
@Override
public long getNextId() throws RemoteException {
return idSeed.getAndIncrement();
}
/**
* 获取ID的初始值
* @return
*/
private long getInitValue() {
return System.currentTimeMillis();
}
}
服务对象的注册代码如下:
@Override
public void run(ApplicationArguments args) throws Exception {
//设置rmi服务端的hostname,该值与远程调用对象绑定,用于客户端寻址
System.setProperty("java.rmi.server.hostname",rmiSvrHostname);
//创建注册中心
Registry reg = LocateRegistry.createRegistry(RmiConfigConsts.RMI_REGISTRY_PORT);
log.info("registry:"+reg);
//注册远程对象
IdGenService idgObj = new IdGenService();
log.info("remote obj:{}",idgObj);
Registry registry = LocateRegistry.getRegistry(RmiConfigConsts.RMI_REGISTRY_PORT);
registry.bind(RmiConfigConsts.IDGEN_RMI_OBJECT_NAME, idgObj);
log.info("idgen rmi obj ready!");
}
4.客户端调用
客户端调用代码比较简单,如下:
@Override
public void run(ApplicationArguments args) throws Exception {
// TODO Auto-generated method stub
// 获取注册中心
Registry registry = LocateRegistry.getRegistry(rmiSvrHostname, RmiConfigConsts.RMI_REGISTRY_PORT);
log.info("get registry");
// 在注册中心中查找远程对象
IIdGen idgen = (IIdGen) registry.lookup(RmiConfigConsts.IDGEN_RMI_OBJECT_NAME);
log.info("get idgen:{}", idgen);
// 循环调用该接口
for (int i = 0; i < 10; i++) {
log.info("{} remote idgen:{}", i, idgen.getNextId());
}
}
5.小结
JAVA RMI是JDK提供的一种原生RPC方式,使用的对象序列化方式为JAVA对象的序列化方式,从测试的效率来看,在网络环境下,一次调用的时间开销在1ms以内。从实现方式上来看,代码也比较简单,缺点是与JAVA语言强绑定。本文只是示例了一个最简单的ID生成算法,如果有更复杂逻辑在算法中,应考虑线程安全问题。本文的示例代码可从https://github.com/solarkai/IdGenRmi获取。
网友评论