前言

由于作者才刚开始学习NodeJs,水平实在有限,本文更像是一篇学习笔记,适合同刚开始学习NodeJs的朋友阅读。

服务治理

如果你的团队正在探索微服务的搭建,那么你们可能就在寻找一种机制,这个机制让每个服务能动态的创建地址,同时调用方要能感知到这些服务地址的动态变化。服务注册与服务发现就是这其中一种机制,大概的流程为:

其中:

  • 注册中心:zookeeper
  • 服务提供者:NodeJs应用服务
  • 服务消费者:NodeJs API Gateway

ZooKeeper服务注册中心

ZooKeeper的身份是管理者,它是一个分布式数据一致性的解决方案,分布式任务可以基于它实现数据的发布与订阅、负载均衡、命名服务、分布式协调与通知、集群管理、领导选举、分布式锁、分布式队列等。本文并不会对所有的方面都展开讲解,因为作者也还没涉及到。我们的目标是利用ZooKeeper来实现一个服务的注册中心,如果你感兴趣,可以自己去研究看看,后面我研究了会再来分享的。

1、利用树状模型构建服务地址存储数据结构

zk内部有一个树状的内存模型,类似于文件系统,有若干目录,每个目录又可以有若干文件夹、文件,如下图:

zk有4种节点(会话指客户端连接zk的长连接):

  • 持久节点:当会话结束时,节点不会被删除
  • 持久顺序节点:当会话结束时,节点不会删除,节点名自带增数后缀
  • 临时节点:当会话结束时,节点会被删除
  • 临时顺序节点:当会话结束时,节点会被删除,节点名自带增数后缀

只有持久节点才能有子节点。

现在一般是集群部署应用,所以我们来看下集群部署下的服务地址状况。例如,当你拥有应用A,应用A部署在2台机器上,机器IP分别为:127.0.0.1和127.0.0.2,应用服务端口6666,应用A就有这么两个服务地址:127.0.0.1:6666、127.0.0.2:6666

我们指定一个节点来作为所有服务地址的根节点(类似命名空间),所以该节点应该为一个持久节点。我们有n个应用,每个应用下有n台机器,所以应用节点也拥有子节点,也应该是持久节点。每台机器在启动应用服务的时候要向zk注册一个地址,在服务下线的时候要删除zk中的地址,所以使用临时节点特点正好符合这个行为,同时可以使用顺序节点自动帮我们管理节点名称。

因为我们都是使用node操作,所以使用zk的node客户端node-zookeeper-client。

2、app启动前连接zk

本来我是用eggjs插件写的,这里将框架的东西剔除,其他提取出来,这样就不和框架挂钩了。

const { createClient, ACL, CreateMode } = require('node-zookeeper-client');const zkClient = createClient('127.0.0.1:2181');
const promisify = require('util').promisify;zkClient.connect();zkClient.once('connected', () => {registerService();
});// 让zkClient支持promise
const proto = Object.getPrototypeOf(zkClient);
Object.keys(proto).forEach(fnName => {const fn = proto[fnName];if (proto.hasOwnProperty(fnName) && typeof fn === 'function') {zkClient[`${fnName}Async`] = promisify(fn).bind(zkClient);}
});// host和port应该和部署系统结合分配
// serviceName要求唯一
const { serviceName, host, port } = config;async function registerService() {try {// 创建根节点,持久节点const rootNode = await zkClient.existsAsync('/services');if (rootNode == null) {await zkClient.createAsync('/services', null, ACL.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);}// 创建服务节点,持久节点const servicePath = `/services/${serviceName}`;const serviceNode = await zkClient.existsAsync(servicePath);if (serviceNode == null) {await zkClient.createAsync(servicePath, null, ACL.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);}// 创建地址节点,临时顺序节点,这样name就不需要我们去维护了,递增const addressPath = `${servicePath}/address-`;const serviceAddress = `${host}:${port}`;const addressNode = await zkClient.createAsync(addressPath, Buffer.from(serviceAddress), ACL.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);} catch (error) {throw new Error(error);}
}
复制代码

上面的代码其实很简单,就是连接zk后先判断根节点是不是创建,如果没有就创建(第一个应用),然后判断应用节点是否创建,没有就创建(集群第一台机器),最后就是创建机器节点,这里使用临时顺序节点,省去了我们维护唯一name的麻烦,让其递增,注意,host和port作为存储内容,这个需要app部署的时候部署系统提供(如果是使用自动部署系统的话),然后地址转为Buffer存起来。

这样其实服务注册就完成了。

NodeJs API Gateway 网关服务

上面已经在服务启动的时候都注册到zk中了,当前端调用接口访问服务的时候,我们需要知道服务的地址,这就是服务发现过程。

API Gateway如它的字面意思来看,是API的入口,用来路由请求。其实,不单单是路由请求,API Gateway还可以转换协议,整合数据、认证、限速等逻辑。

例如前端有个用户获取的请求,应该这样写:

fetch('/api/user/get', {method: 'POST',body: { id: 1 },headers: {// header的方式指定service'servive-name': 'user'}
})
复制代码

API Gateway本质也是是个服务,使用Eggjs编写,我们的服务发现封装成一个中间件,所以这里只展示中间件的内容,其他的自己看egg的文档。

const proxy = require('koa-proxies');module.exports = (options, app) => {return async (ctx, next) => {const serviceName = ctx.request.headers['servive-name'];if (!serviceName) {ctx.throw(404, 'no service found.');}const servicePath = `/services/${serviceName}`;const addressNodes = await app.zookeeper.getChildrenAsync(servicePath);const size = addressNodes.length;if (size === 0) {ctx.throw(404, 'no service found.');}let addressPath = `${servicePath}/`;if (size === 1) {addressPath += addressNodes[0];} else {// 这里你可以做负载均衡addressPath += addressNodes[parseInt(Math.random() * size)];}const serviceAddress = await app.zookeeper.getDataAsync(addressPath);if (!serviceAddress) {ctx.throw(404, 'no service found.');}await proxy('/', {target: `http://${serviceAddress}/`,})(ctx, next);};
};
复制代码

上面的中间件中根据headers中的service-name去获取到该应用下所有的服务地址,然后根据某个策略选择一个服务,使用代理转发到对应的服务。

总结

以上很简陋地实现了,虽然可以使用,还有很多细节要处理,比如API Gateway中对于已经拿到的服务地址可以缓存起来,然后订阅zk变化;比如在选择服务的时候可以做负载均衡。

NodeJs服务注册与服务发现实现相关推荐

  1. 什么是微服务架构?什么是服务注册与服务发现?

    文章目录 基础名词 分布式 高可用 集群 什么是微服务 服务注册与服务发现 SpringCloud Alibaba 服务关系以及调用关系 服务注册中心 Nacos服务发现的领域模型 Nacos元数据 ...

  2. 如何理解服务注册和服务发现

    服务注册.服务注册表.服务发现 三者的关系是:通过服务注册机制将启动服务的信息上传至服务注册表,服务发现机制通过服务注册表实时获取可用服务的信息. 服务注册的方式包括:自注册和第三方注册.自注册的意思 ...

  3. 微服务架构-实现技术之三大关键要素1服务治理:服务注册中心+服务发布与注册+服务发现与调用+服务监控

    目录 一.服务注册中心:注册中心核心功能+实现策略 1.注册中心核心功能 2.注册中心实现策略 二.服务发布与注册 三.服务发现与调用 四.服务监控 基本思路:日志埋点 基本目标: 基本定位: 基本策 ...

  4. 【Zookeeper】JAVA通过ZK实现服务注册和服务发现

    无意中发现了一个巨牛的人工智能教程,忍不住分享一下给大家.教程不仅是零基础,通俗易懂,而且非常风趣幽默,像看小说一样!觉得太牛了,所以分享给大家.点这里可以跳转到教程. 服务化现在已经是个很成熟的概念 ...

  5. 小白入门微服务(4) - 服务注册与服务发现

    概述 前言 什么是服务注册.服务发现 两种服务注册方式 两种服务发现方式 常见的第三方注册工具 后记 前言 好一阵子没有更新了,有些小伙伴在后台问我有没有更新,看来大家还是挺喜欢看我的文章的嘛.主要是 ...

  6. 服务注册与服务发现中心

    1.基本原理 服务注册和服务发现中心各自有多台机器,保证高可用 服务器注册:就是将周期性将自己的ip和端口号提供给注册中心,注册中心维护了(服务名称,ip和端口号的列表)一个映射关系. 服务发现:调用 ...

  7. 深入了解服务注册与服务发现

    1. 什么是服务注册与发现 我们先来看下什么是服务注册与服务发现? 服务注册,就是将提供某个服务的模块信息(通常是这个服务的ip和端口)注册到1个公共的组件上去(比如: zookeeper\consu ...

  8. 微服务2——服务的注册,调用(Nacos服务注册中心+服务调用+调用负载均衡)sca-comsumersca-provider

    一.Nacos的安装和构建  以及启动 其官网地址如下: Nacos官网 1.安装前提: 第一:确保你电脑已配置JAVA_HOME环境变量(Nacos启动时需要),例如: 第二:确保你的MySQL版本 ...

  9. Consul 服务注册与服务发现

    1. 服务注册 对 Consul 进行服务注册之前,需要先部署一个服务站点,我们可以使用 ASP.NET Core 创建 Web 应用程序,并且部署到 Ubuntu 服务器上. ASP.NET Cor ...

最新文章

  1. ​Keepalived双机热备
  2. Windows Xp Oracle 10g的安装
  3. Android热补丁之Robust(三)坑和解
  4. qt 中常见错误汇总
  5. WINDOWS下对音频的处理过程(转)
  6. apache.camel_Apache Camel 2.19发布–新增功能
  7. 安装php7的mysql扩展,php7安装mysql扩展的方法是什么
  8. java开发实战经典
  9. lora终端连接云服务器_物联网通讯技术三足鼎立形成:NB-IoT、eMTC、LoRa各有千秋...
  10. (08)Verilog HDL同步复位
  11. STM32F103单片机输出相位可调PWM波
  12. c语言———链表的创建
  13. 搜狗推送工具-搜狗批量提交软件
  14. 固定偏置放大电路为何不能保证静态工作点的稳定性?
  15. the owning Session was closed
  16. 24点小游戏(C语言实现)
  17. 构建CA证书详解过程步骤
  18. CDN边缘智能助力5G
  19. linux服务器移动硬盘挂载,linux挂载命令mount及U盘、移动硬盘的挂载
  20. 【软件测试】python完成接口测试示例

热门文章

  1. 关于夜神模拟器,你该了解这些
  2. 描述性统计分析都用到哪些可视化图表?
  3. MSP430F2274IRHAR超低功耗微控制器 封装:QFN40
  4. Android项目练手
  5. 瑞·达利欧:驾驭算法成人工智能时代基础能力
  6. CoOS使用教程——消息队列
  7. 华为无线部署案例+radius认证
  8. KVM修改虚拟机配置
  9. Unity3D技术之深入了解光照贴图详解
  10. RZ/G2L核心板CPU温升测试