時間戳服務器: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來監控和拉起服務。