当项目愈来愈大的时候,必然会作到服务化,并且大型项目下,极有可能调用跨语言服务。因此我写了这个通用的框架,用于发布/调用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 的调用。