Session是Zookeeper中的会话实体,代表了一个客户端会话。SessionID用来唯一标识一个会话,因此Zookeeper必须保证sessionID的全局唯一性,在每次客户端向服务端发起"会话创建"请求时,服务端都会为其分配一个sessionID。那么Zookeeper是如何实现的呢?
在SessionTracker初始化的时候,会调用initializeNextSession方法来生成一个初始化的sessionID,之后在Zookeeper的正常运行过程中,会在该sessionID的基础上为每个会话进行分配。
/** * Generates an initial sessionId. High order byte is serverId, next 5 * 5 bytes are from timestamp, and low order 2 bytes are 0s. */ public static long initializeNextSession(long id) { long nextSid = 0; nextSid = (System.currentTimeMillis() << 24) >>> 8; //这里的版本是3.4.6 nextSid = nextSid | (id <<56); return nextSid; }
?
上面这个方法就是Zookeeper初始化的算法。可以看出sessionID的生成可以分为以下5个步骤:
上面的算法就算完美吗?
答案是否定的,在zookeeper3.5.0以上的版本中对这个方法进行的修改。3.5.0版本的方法如下:
/**
* Generates an initial sessionId. High order byte is serverId, next 5
* 5 bytes are from timestamp, and low order 2 bytes are 0s.
*/
public static long initializeNextSession(long id) {
long nextSid;
nextSid = (Time.currentElapsedTime() << 24) >>> 8;
nextSid = nextSid | (id <<56);
return nextSid;
}
?
currentTimeMillis方法换成了另外一个方法。那么这个方法是什么呢?
/** * Returns time in milliseconds as does System.currentTimeMillis(), * but uses elapsed time from an arbitrary epoch more like System.nanoTime(). * The difference is that if somebody changes the system clock, * Time.currentElapsedTime will change but nanoTime won‘t. On the other hand, * all of ZK assumes that time is measured in milliseconds. * @return The time in milliseconds from some arbitrary point in time. */ public static long currentElapsedTime() { return System.nanoTime() / 1000000; }
?使用了System.nanoTime()方法。原因是如果一些人去主动修改系统的时间,这样可能会出现问题。
?
?
Zookeeper使用了2行代码完成了生成全局唯一值的方法。然而我们直接使用jdk1.5以上自带的UUID不是也能生成全局唯一的值吗?
下面我们看看UUID和Zookeeper自己实现方法的一些比较:
总结:
?
原文:http://xt00002003.iteye.com/blog/2302392