Thrift 個人實戰--RPC服務的釋出訂閱實現(基於Zookeeper服務)
基礎架構:
RPC服務往平臺化的方向發展, 會遮蔽掉更多的服務細節(服務的IP地址叢集, 叢集的擴容和遷移), 只暴露服務介面. 這部分的演化, 使得server端和client端完全的解耦合. 兩者的互動通過ConfigServer(MetaServer)的中介角色來搭線.
注: 該圖源自dubbo的官網
這邊藉助Zookeeper來扮演該角色, server扮演釋出者的角色, 而client扮演訂閱者的角色.
Zookeeper基礎:
Zookeeper是分散式應用協作服務. 它實現了paxos的一致性演算法, 在命名管理/配置推送/資料同步/主從切換方面扮演重要的角色.
其資料組織類似檔案系統的目錄結構:
每個節點被稱為znode, 為znode節點依據其特性, 又可以分為如下型別:
1). PERSISTENT : 永久節點
2). EPHEMERAL : 臨時節點, 會隨session(client disconnect)的消失而消失
3). PERSISTENT_SEQUENTIAL
4). EPHEMERAL_SEQUENTIAL : 臨時節點, 其節點的名字編號是單調遞增的
注: 臨時節點不能成為父節點
Watcher觀察模式, client可以註冊對節點的狀態/內容變更的事件回撥機制. 其Event事件的兩類屬性需要關注下:
1). KeeperState : Disconnected,SyncConnected,Expired
2). EventType : None,NodeCreated,NodeDeleted,NodeDataChanged,NodeChildrenChanged
RPC服務端:
作為具體業務服務的RPC服務釋出方, 對其自身的服務描述由以下元素構成.
1). product : 產品名稱
2). service : 服務介面, 採用釋出方的類全名來表示
3). version : 版本號
借鑑了Maven的GAV座標系, 三維座標系更符合服務平臺化的大環境.
*) 資料模型的設計
具體RPC服務的註冊路徑為: /rpc/{product}/{service}/{version}, 該路徑上的節點都是永久節點
RPC服務叢集節點的註冊路徑為: /rpc/{product}/{service}/{version}/{ip:port}, 末尾的節點是臨時節點
*) RPC服務節點的配置和行為
服務端的配置如下所示:
<register>
<server>{ip:port => Zookeeper的地址列表}</servers>
<application>{application name => 服務的應用程式名}</application>
</register>
<server>
<interface>{interface => 服務介面名}</interface>
<version>{version => 服務版本號}</version>
<class>{class => interface的具體實現Handler類}</class>
<port>{提供服務的監聽埠}</port>
</server>
服務端的註冊邏輯:
Zookeeper zk = new Zookeeper("127.0.0.1:2181", timeout, null);
while ( !application exit ) {
Stat stat = zk.exists("/rpc/{product}/{service}/{version}/{ip:port}", false);
if ( stat == null ) {
zk.create("/rpc/{product}/{service}/{version}/{ip:port}", Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
}
Thread.sleep(wait_timeout);
}
注: zookeeper client與zookeeper的斷開會導致臨時節點的丟失, 因此需要重新構建, 這邊採用開啟一個迴圈執行緒, 用於定時輪詢.
RPC客戶端:
客戶端的簡單註冊配置:
<register>
<server>{ip:port => Zookeeper的地址列表}</servers>
<application>{application name => 服務的應用程式名}</application>
</register>
<service>
<interface>{interface => 服務介面名}</interface>
<version>{version => 服務版本號}</version>
</sevice>
客戶端的程式碼:
1). 初始獲取server列表
Zookeeper zk = new Zookeeper("127.0.0.1:2181", timeout, null);
List<String> childrens = zk.getChildren(path, true);
2). 註冊Watcher監聽, EventType.NodeChildrenChanged事件, 每次回撥, 重新獲取列表
class WatcherWarpper implements Watcher {
public void process(WatchedEvent event) {
if ( event.getType() == EventType.NodeChildrenChanged ) {
List<String> childrens = zk.getChildren(path, true);
// notify Thrift client, rpc service的server ip:port列表發生了變化
}
}
}
總結:
這部分其實涉及thrift點並不多, 但該文確實是rpc服務平臺化的理論基礎. 服務端作為服務的釋出方, 而客戶端藉助zookeeper的watcher機制, 來實現其對服務列表的訂閱更新功能. 從而達到解耦, 邁出服務平臺化的一步.
後續: 後續文章講解Thrift client連線池的實現, 也是比較基礎的一部分, 敬請期待.