时间戳服务器:XiaoMi Chronos
Chronos,在古希腊语意为时间,是小米公司开发的实现高可用、高性能、提供全局唯一而且严格单调递增timestamp的服务。
Chronos 采用主备架构,主服务器挂了以后备服务器迅速感知并接替服务,从而实现系统的高可用。服务端使用Thrift框 架,经测试每秒可处理约60万次RPC请求,客户端单线程每秒可请求6万次(本地服务器),保证高性能与低延时。全局只有唯一的 ChronosServer提供服务,分配的timestamp保证严格单调递增,并且将已分配的值持久化到ZooKeeper上,即使发生 failover也能保证服务的正确性。
原理
Chronos依赖ZooKeeper实现与HBase类 似的Leader Election机制,ChronosServer启动时将自己的信息写到ZooKeeper的Master临时节点上,如果主服务器已经存在,那么就记 录到BackupServers节点上。一旦Master临时节点消失(主服务器发生failover),所有备服务器收到ZooKeeper通知后参与 新一轮的选主,保证最终只有一个新的主服务器接替服务。
ChronosServer运行时会启动一个Thrift服务器,提供getTimestamp()和getTimestamps(int)接口, 并且保证每次返回的timestamp都是严格单调递增的。返回的timestamp与现实时间有基本对应关系,为当前Unix time乘以2的18次方(足够使用1115年),由于我们优化了性能,所以如果存在failover就不能保证这种对应关系的可靠性。
ChronosClient启动时,通过访问ZooKeeper获得当前的主ChronosServer地址,连接该服务器后就可以发送 Thrift RPC请求了。一旦主服务器发生failover,客户端请求失败,它会自动到ZooKeeper获得新的主ChronosServer地址重新建立连 接。
使用
Chronos服务端
- 进入chronos-server目录,通过
mvn clean package -DskipTests
编译源码。 - 进入target里面的conf目录,编辑chronos.conf,填写依赖的ZooKeeper配置。
- 进入target里面的bin目录,执行
sh ./chronos.sh
既可运行ChronosServer。
Chronos客户端
- 进入chronos-client目录,通过
mvn clean package -DskipTests
编译源码。 -
客户端在pom.xml添加chronos-client的依赖(请使用对应的Thrift版本)。
<dependency> <groupId>com.xiaomi.infra</groupId> <artifactId>chronos-client</artifactId> <version>1.2.0-thrift0.5.0</version> </dependency>
-
创建ChronosClient对象,如
new ChronosClient("127.0.0.1:2181", "default-cluster")
。 - 发送RPC请求,如
chronosClient.getTimestamp()
或chronosClient.getTimestamps(10)
。
快速体验
- 参考ZooKeeper文档,编译ZooKeeper并运行在127.0.0.1:2181上。
- 获得chronos源代码,执行
mvn clean packge -DskipTests
编译(需要安装Thrift)。 - 进入chronos-server的bin目录,执行
sh ./chronos.sh
运行ChronosServer。 - 进入chronos-client目录,执行
mvn exec:java -Dexec.mainClass="com.xiaomi.infra.chronos.client.ChronosClient" -Dexec.args="127.0.0.1:2181 default-cluster"
。
场景
- 提供全局严格单调递增的timestamp,用于实现Percolator等全局性事务。
- 提供全局唯一的值,相比snowflake不依赖NTP服务,并且提供failover机制。
工具
- 提供list_servers.rb脚本,可监控当前的所有运行的ChronosServer状态。
- 提供translate_timestamp.rb脚本,可将timestamp转化为可读的世界时间。
- 提供process_benchmark_log.rb脚本,可处理Benchmark程序产生的日志。
测试
- 性能测试
客户端线程数 | 平均QPS | 平均Latency(毫秒) | 平均Failover时间(秒) | 服务端总QPS |
---|---|---|---|---|
1 | 10792.757 | 0.093 | 3.056 | 32378.271 |
10 | 7919.679 | 0.127 | 3.053 | 237590.370 |
20 | 6676.801 | 0.164 | 3.952 | 400788.060 |
50 | 3954.026 | 0.255 | 4.044 | 593103.900 |
100 | 1791.251 | 0.605 | 5.470 | 537375.300 |
50(最优) | 3993.749 | 0.251 | 0.000 | 599062.350 |
- Failover测试
持续杀掉ChronosServer和ZooKeeper进程没有发现正确性问题,failover时间符合预期。
注意,Failover时间可通过ZooKeeper的tickTime和Chronos的sessionTimeout来设置,线上部署时应配合Supervisor或者God来监控和拉起服务。