基於 Thrift 的 Node.js 微服務

當項目愈來愈大的時候,必然會作到服務化,並且大型項目下,極有可能調用跨語言服務。因此我寫了這個通用的框架,用於發佈/調用node服務, node-thrift-servicejavascript

Thrift

Apache Thrift 是一款跨語言的服務框架,傳輸數據採用二進制格式,相對 XML 和 JSON 體積更小,對於高併發、大數據量和多語言的環境更有優點。java

client<->server


安裝

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'
});

API

// 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

ZooKeeper 是一個分佈式的,開放源碼的分佈式應用程序協調服務,是 Google 的 Chubby 一個開源的實現,是 Hadoop 和 Hbase 的重要組件。它是一個爲分佈式應用提供一致性服務的軟件,提供的功能包括:配置維護、域名服務、分佈式同步、組服務等。
ZooKeeper 的目標就是封裝好複雜易出錯的關鍵服務,將簡單易用的接口和性能高效、功能穩定的系統提供給用戶。
ZooKeeper 包含一個簡單的原語集,提供Java和C的接口。
ZooKeeper 代碼版本中,提供了分佈式獨享鎖、選舉、隊列的接口,其中分佈鎖和隊列有Java和C兩個版本,選舉只有Java版本。

詳細原理教程能夠參見官網

Node.js 的 ZooKeeper 版本爲 C 接口的封裝。


使用

Zookeeper 提供一個相似於文件系統的服務。
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 && Zookeeper 的微服務架構

將 Thrift Server 發佈 ZooKeeper 上(註冊臨時節點),Client 端根據 serviceName(alias) 在 ZooKeeper 上查找 Thrift Server 主機,鏈接全部提供該服務的 Thrift Server 主機,並自動管理全部的 TCP 鏈接。


ZooKeeper 結構

設置 Zookeeper 的結構以下,service 的每一個節點均爲臨時節點

zookeeper結構


Thrift Service 發佈

Thrift 的服務由 thrift 文件定義而成,service 建立以後,將 thrift.createServer 的 host:port 發佈到 ZooKeeper/Redis 上。

  • 自動獲取機器內網 ipv4 地址,eth0(linux) en0(osx)

  • 自動查找一個可用的 port

  • 發佈 Thrift 服務 或 JS 服務

  1. 對於 Thrift gen-js 的 service 單獨發佈

  2. 由於 JS 語言支持 .apply 方式的調用,因此調用 remote service 的時候,能夠只傳輸 alias action params,結果返回時,傳輸 err result,因此能夠用一個通用的 msg.thrift 用於傳輸。而且能夠管理 actions 的調用權限。


Thrift Client 訂閱

Client 鏈接ZooKeeper/Redis,根據 service alias 查找全部提供服務的 server 地址,並管理全部 server 鏈接。

  • action 調用權限控制。

  • 輪詢調用 alias 的全部鏈接。

  • 使用 Watcher 訂閱 ${service} 子節點的變化,並自動添加新 server 。

  • 清理失效的鏈接。

  • 調用服務:

  1. .call(alias, action, params[, callback]) 返回 js service 調用的結果。

  2. .call(alias[, callback]) 返回 Thrift client 供 gen-js 的調用。

相關文章
相關標籤/搜索