基于 Thrift 的 Node.js 微服务

标签: node.js zookeeper thrift 微服务


当项目越来越大的时候,必然会做到服务化,而且大型项目下,极有可能调用跨语言服务。所以我写了这个通用的框架,用于发布/调用node服务, node-thrift-service

Thrift

Apache Thrift 是一款跨语言的服务框架,传输数据采用二进制格式,相对 XML 和 JSON 体积更小,对于高并发、大数据量和多语言的环境更有优势。

client<->server
client<->server

安装

Thrift 官网上下载相应的版本,按步骤一步一步安装即可。


类型

数据类型

Thrift 支持 8 种数据类型:

  • bool: true or false
  • byte: signed byte
  • i16/i32/i64: 16/32/64位 signed integer
  • double: 64位
  • 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
ZooKeeper

client 与 Zookeeper 服务器为 TCP 长连接,服务器为每个客户端生成一个 session,断开时则清理 session 。

在这样的机制下,可以使用 ZooKeeper 进行监控。

如上图所示,client 1、2、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结构
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 的调用。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容