美文网首页笔戈 Web Team我爱编程
基于 Thrift 的 Node.js 微服务

基于 Thrift 的 Node.js 微服务

作者: xun | 来源:发表于2016-03-15 10:18 被阅读1931次

    标签: node.js zookeeper thrift 微服务


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

    Thrift

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

    client<->serverclient<->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 的『节点』均可以存放数据,并且可以对节点的权限进行控制。

    ZooKeeperZooKeeper

    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 的调用。

    相关文章

      网友评论

        本文标题:基于 Thrift 的 Node.js 微服务

        本文链接:https://www.haomeiwen.com/subject/xyehkttx.html