當項目愈來愈大的時候,必然會作到服務化,並且大型項目下,極有可能調用跨語言服務。因此我寫了這個通用的框架,用於發佈/調用node服務, node-thrift-service 。javascript
Apache Thrift 是一款跨語言的服務框架,傳輸數據採用二進制格式,相對 XML 和 JSON 體積更小,對於高併發、大數據量和多語言的環境更有優點。java
在 Thrift 官網上下載相應的版本,按步驟一步一步安裝便可。node
Thrift 支持 8 種數據類型:linux
bool: true or falsegit
byte: signed bytegithub
i16/i32/i64: 16/32/64位 signed integershell
double: 64位apache
binary: byte array數組
string服務器
3 種容器:
list<t1>: 排序數組,能夠重複
set<t1>: 集合,每一個元素惟一
map<t1, t2>: t1 惟一
支持命名空間(Namespaces)// 如 Java 的包名,C++ 的 namespaces
namespace cpp com.hello namespace java com.hello
能夠引用其餘 thrift 文件
include "hello.thrift" ...
const i32 GOOD = 1024; const list<string> ABC = ["a", "b", "c"];
struct Animal { 1: required double age; 2: required double weight; } struct Cat { 1: required string name; 2: required string food; 3: required Animal common; 8: optional bool curl; }
Thrift 經過語法規範定義接口,形式相似於僞代碼,例如:
exception TypeError { 1: required string err 2: optional string message } service Hello { string say(1: string name); Cat getCat(1: string name) throws (1: TypeError err) }
更詳細的教程能夠看這裏。
上述代碼定義了一個 Hello
服務,將其保存爲 hello.thrift
。
使用 thrift
命令能夠生成代碼。
thrift --gen <language> <Thrift filename> // nodejs // ls ./gen-nodejs => Hello.js hello_types.js thrift --gen js:node hello.thrift // java // ls ./gen-java => Animal.java Cat.java Hello.java TypeError.java thrift --gen java hello.thrift
'use strict'; const thrift = require('thrift'); const Hello = require('./gen-nodejs/Hello'), types = require('./gen-nodejs/hello_types'); ... let server = thrift.createServer(Hello, { say(name, callback){ callback(null, 'Hello ' + name); } ... }, {}); server.listen(7800); server.on('error', console.error); server.on('listening', () => { let conn = thrift.createConnection('127.0.0.1', 7800); let client = thrift.createClient(Hello, conn); client.say('Thrift', console.log); // null 'Hello Thrift' });
// processor 即生成的 ./gen-nodejs/Hello.js // handler 爲接口的實現,參數在 hello.thrift 定義的基礎上多一個 callback(error, result) // options 能夠定義 傳輸協議 以及 tls // var transport = (options && options.transport) ? options.transport : TBufferedTransport; // var protocol = (options && options.protocol) ? options.protocol : TBinaryProtocol; let server = thrift.createServer(processor, handler, options) // 這個就一目瞭然,options 與 server 建立時的 options 用法一致 let connection = thrift.createConnection(host, port, options) let client = thrift.createClient(processor, connection)
ZooKeeper 是一個分佈式的,開放源碼的分佈式應用程序協調服務,是 Google 的 Chubby 一個開源的實現,是 Hadoop 和 Hbase 的重要組件。它是一個爲分佈式應用提供一致性服務的軟件,提供的功能包括:配置維護、域名服務、分佈式同步、組服務等。
ZooKeeper 的目標就是封裝好複雜易出錯的關鍵服務,將簡單易用的接口和性能高效、功能穩定的系統提供給用戶。
ZooKeeper 包含一個簡單的原語集,提供Java和C的接口。
ZooKeeper 代碼版本中,提供了分佈式獨享鎖、選舉、隊列的接口,其中分佈鎖和隊列有Java和C兩個版本,選舉只有Java版本。
詳細原理教程能夠參見官網。
Node.js 的 ZooKeeper 版本爲 C 接口的封裝。
Zookeeper 提供一個相似於文件系統的服務。
Zookeeper 每一級節點分爲永久節點和臨時節點,只有永久節點才能夠建立子節點,相似於文件系統一級一級的『目錄』。
Zookeeper 的『節點』都可以存放數據,而且能夠對節點的權限進行控制。
client 與 Zookeeper 服務器爲 TCP 長鏈接,服務器爲每一個客戶端生成一個 session,斷開時則清理 session 。
在這樣的機制下,可使用 ZooKeeper 進行監控。
如上圖所示,client 一、二、3 在鏈接 Zookeeper 服務器能夠註冊一個臨時節點,斷開鏈接時 Zookeeper 就會清理臨時節點,這樣便能作到監控。
ZooKeeper 對三類操做提供監視器註冊(Watches):
getData()
getChildren()
exist()
監視器均爲一次觸發!若是一直要監控節點變化,則須要在監視器觸發後,再次註冊監視器!
監視器事件:
ZOO_CREATED_EVENT // 節點被建立(此前該節點不存在)
ZOO_DELETED_EVENT // 節點被刪除
ZOO_CHANGED_EVENT // 節點發生變化
ZOO_CHILD_EVENT // 子節點事件
ZOO_SESSION_EVENT // 會話丟失
ZOO_NOTWATCHING_EVENT // 監視被移除。
None // None事件會觸發,可是不會使當前監視器失效
將 Thrift Server 發佈 ZooKeeper 上(註冊臨時節點),Client 端根據 serviceName(alias) 在 ZooKeeper 上查找 Thrift Server 主機,鏈接全部提供該服務的 Thrift Server 主機,並自動管理全部的 TCP 鏈接。
設置 Zookeeper 的結構以下,service 的每一個節點均爲臨時節點。
Thrift 的服務由 thrift 文件定義而成,service 建立以後,將 thrift.createServer 的 host:port 發佈到 ZooKeeper/Redis 上。
自動獲取機器內網 ipv4 地址,eth0(linux) en0(osx)
自動查找一個可用的 port
發佈 Thrift 服務 或 JS 服務
對於 Thrift gen-js 的 service 單獨發佈
由於 JS 語言支持 .apply
方式的調用,因此調用 remote service 的時候,能夠只傳輸 alias
action
params
,結果返回時,傳輸 err
result
,因此能夠用一個通用的 msg.thrift
用於傳輸。而且能夠管理 actions
的調用權限。
Client 鏈接ZooKeeper/Redis,根據 service alias
查找全部提供服務的 server 地址,並管理全部 server 鏈接。
action
調用權限控制。
輪詢調用 alias 的全部鏈接。
使用 Watcher
訂閱 ${service}
子節點的變化,並自動添加新 server 。
清理失效的鏈接。
調用服務:
.call(alias, action, params[, callback])
返回 js service 調用的結果。
.call(alias[, callback])
返回 Thrift client 供 gen-js 的調用。