一個基於RMI的ID生成器簡單模型 1. 概述 2.接口定義 3. 服務端 4.客戶端調用 5.小結

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獲取。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章