hydra-microservice 中文手册(完整篇)(二)

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
日志服务 SLS,月写入数据量 50GB 1个月
简介: hydra-microservice 中文手册(完整篇)(二)

上手指南



安装


要在另一个项目中安装和使用:


$ npm install hydra-express


用法


'use strict';
const config = require('./config/properties').value;
const version = require('./package.json').version;
const hydraExpress = require('hydra-express');
function registerRoutesCallback() {
  hydraExpress.registerRoutes({
    '/v1/offers': require('./offers-v1-api')
  });
}
function registerMiddlewareCallback() {
  let app = hydraExpress.getExpressApp();
  app.use((req, res, next) => {
    console.log('req.headers', req.headers);
    next();
  });
}
hydraExpress.init(config, version, registerRoutesCallback, registerMiddlewareCallback)
  .then((serviceInfo) => {
    console.log('serviceInfo', serviceInfo);
  })
  .catch((err) => {
    console.log('err', err);
  });


在上面的示例中,then 语句上的 serviceInfo 返回一个对象, 其中包含 serviceNameservicePort 和其他有用值。


日志记录和错误报告



HydraExpress 包含一个 log 成员,允许您输出日志到控制台和日志文件。


hydraExpress.log('error', message);


log 的第一个参数是日志消息的类型:fatalerrordebuginfo。第二个参数是要存储的字符串消息。强烈建议您利用这个机会创建描述性很强的日志消息,因为此函数不记录堆栈跟踪。


此外,将 fatalerror 类型的日志消息发送到 hydra-core, 以便在服务运行状况检查(health check)日志中进行日志记录。


服务静态 Web 内容



hydra-express 服务可以服务静态 Web 内容。只需创建一个名为 public 的文件夹,然后将网站文件复制到其中即可。可以在 demo/webserver 文件夹中找到一个示例。


Hydra Cli



上手指南


首先,您需要安装 hydra-cli


$ sudo npm install -g hydra-cli


您只需在终端中输入程序名称即可查看 hydra-cli 的所有选项。


$ hydra-cli
hydra-cli version 0.5.7
Usage: hydra-cli command [parameters]
See docs at: https://github.com/flywheelsports/hydra-cli
A command line interface for Hydra services
Commands:
  help                         - this help list
  cfg pull label               - download configuration file
  cfg push label filename      - update configuration file
  cfg list serviceName         - display a list of config versions
  config instanceName          - configure connection to redis
  config list                  - display current configuration
  use instanceName             - name of redis instance to use
  health [serviceName]         - display service health
  healthlog serviceName        - display service health log
  message create               - create a message object
  message send message.json    - send a message
  nodes [serviceName]          - display service instance nodes
  refresh node list            - refresh list of nodes
  rest path [payload.json]     - make an HTTP RESTful call to a service
  routes [serviceName]         - display service API routes
  services [serviceName]       - display list of services
  shell                        - display command to open redis shell


如您所见,hydra-cli 可以做很多事情。


配置 hydra-cli


要使用大多数 hydra-cli 命令,您首先需要对其进行配置,方法是将其指向您正在使用的 Redis 实例。


$ hydra-cli config local


config 命令需要一个你想要关联到 Redis 连接信息的名称。这允许您为多个环境存储配置设置。例如,您可能已经为您的项目 localstagingproduction 存储了设置。


在存储的设置之间切换很容易:


$ hydra-cli use staging


您可以使用 config list 命令查看当前选择的设置。


$ hydra-cli config list


与 hydra 配置文件一起工作


Hydra 配置文件,不要与 hydra-cli 配置设置混淆,服务在初始化 hydra 或 hydra-express 时会使用它们。


这些配置文件通常在运行时加载,并将其内容传递给 Hydra。

在启动过程中,如果 Hydra 看到 HYDRA_REDIS_URLHYDRA_SERVICE 环境变量, 则 Hydra 会向指定的 Redis 实例询问其配置文件的副本。

应该通过以下方式定义环境变量:


HYDRA_REDIS_URL='redis://10.0.0.2:6379/15'
HYDRA_SERVICE='myservice:0.12.1'


这通常用于 Docker 容器中启用 hydra 的应用。

Hydra-cli 提供 cfg 命令,用于列出(listing)、加载(loading)和上传(uploading)配置文件数据到 Redis。

你可以使用下面的命令来获取配置列表:


$ hydra-cli cfg list myservice


为了存储配置,您必须指定由冒号和服务版本分隔的服务名称。


$ hydra-cli cfg pull myservice:0.12.1


使用上面的 cfg pull 命令,检索到的配置将显示在终端中。要将调出的配置保存到一个文件中,你可以使用:


$ hydra-cli cfg pull myservice:0.12.1 
>
 config.json


要上传一个配置,你可以使用 cfg push 命令:


$ hydra-cli cfg push myservice:0.12.2 config.json


列出配置,检索一个配置并将其保存到文件中——然后在上传之前修改它,这就是管理服务配置的方法。


列出服务信息


Hydra 的一个非常好的特性是, 运行 Hydra 的每个应用程序都会发出运行状况(health)和存活状态(presence)信息。使用 hydra 的任何应用程序都可以检查这些信息。


hydra-cli 程序实际上只是一个运行 Hydra 的命令行客户端——它的大部分功能都是由 Hydra 提供的。


我们可以使用 nodes 命令查看节点列表:


$ hydra-cli nodes


许多 Hydra 驱动的应用程序导出 API 路由。我们可以使用以下方法查看服务路由列表

hydra-cli routes


您可以使用 health 命令检索服务的健康状态。


$ hydra-cli health


如果指定了服务名称,则只能看到该服务的运行状况信息。


$ hydra-cli health myservice


节点列表清理


如果您启动和停止服务,最终将看到不再处于活动状态的服务。这出现在 hydra-cli 节点命令期间。这个列表没有被自动清除的关键原因是它对于调试和监视非常有用。您必须使用 refresh 命令手动清除死服务列表。


$ hydra-cli refresh


快速连接到 Redis


如果需要,您可以要求 hydra-cli 提供与 redis-cli 客户端一起使用的连接字符串。


$ hydra-cli shell


在运行 Mac 或 Linux 的计算机上,您可以发出以下命令来自动调用 redis-cli


$(hydra-cli shell)


下一步


hydra-cli。我们发现它是使用 Hydra 应用程序时必不可少的工具。

阅读项目仓库中的完整文档


Hydra 生产器


Hydra Generator 是一个命令行工具,可让您快速构建 Hydra 或 Hydra-Express 应用程序的完整脚手架。生成器依赖于称为 Yeoman 的工具。


生成器的伟大之处在于,您可以在不到15秒的时间内构建微服务。然后,您可以继续自定义生成的代码以适合您的特定需求。


快速上手


首先全局安装 Yeomangenerator


$ sudo npm install -g yo generator-fwsp-hydra


要使用生成器,只需使用生成器的名称调用 yeoman 即可。在我们的案例中,hydra-generator 被称为 fwsp-hydra。您收到的第一个提示要求您为服务命名。


$ yo fwsp-hydra
? Name of the service (`-service` will be appended automatically) hello


在出现许多其他问题(您可以选择 default )之后,该过程以关于如何构建和启动新项目的说明结束。


Done!
'cd example-service' then 'npm install' and 'npm start'


请记住 Hydra 服务需要使用 Redis 实例。所以在你运行你的应用程序之前,你需要 redis 可用。默认情况下,Hydra 生成器将创建一个配置文件,该文件需要一个本地的 Redis 实例。


{
  "environment": "development",
  "hydra": {
    "serviceName": "hello-service",
    "serviceIP": "",
    "servicePort": 5000,
    "serviceType": "hello",
    "serviceDescription": "says hello",
    "redis": {
      "url": "redis://127.0.0.1:6379/15"
    }
  }
}


Hydra-Router


Hydra Router 是一种服务感知路由器,可以将 HTTPWebSocket 消息请求定向到已注册的服务。


尝试 Hydra-router


尝试使用 hydra-router 的最简单方法是获取现成的Docker容器。


$ docker pull flywheelsports/hydra-router


尽管以上命令将起作用,但我们建议您访问 https://hub.docker.com/r/flywheelsports/hydra-router/tags/ 并提取特定版本,例如:


$ docker pull flywheelsports/hydra-router:1.3.3


运行容器要求您具有正在运行的 Redis 本地实例, 并且需要使用计算机上的 ifconfigipconfig 工具标识计算机的 IP 地址。


$ docker rm -f hydra-router
$ docker run -d -p 5353:5353 --add-host host:10.1.1.175 --name hydra-router flywheelsports/hydra-router:1.3.3


然后,您应该能够将Web浏览器指向 http://10.1.1.175:5353 并发出路由器请求,例如:


http://10.1.1.175:5353/v1/router/version


拉取最新的 Docker 容器


Hydra-router docker 镜像被存储在这里:https://hub.docker.com/r/flywheelsports/hydra-router/tags/


从源码构建


您还可以获取 hydra-router 源代码并在本地使用它。

https://github.com/flywheelsports/hydra-router


简介


使用 HydraRouter 外部客户端可以连接到服务,而不需要知道它们的IP或端口信息。HydraRouter 负责服务发现和路由。


此外,HydraRouter 还可以路由到由某个服务托管的网站。 如果使用服务名作为第一个 url 路径段访问路由器,并且请求是 HTTP GET 调用, 那么请求将被路由到一个可用的服务实例。


当一种服务类型存在多个服务实例时,通过 HydraRouter 发出的请求将在可用实例之间进行负载平衡。

Hydra 路由器还公开了 RESTful 端点,可用于查询服务运行状况(health)和存活状态(presence)信息。


使用 Hydra 微服务可以使用 findServicesendServiceMessagemakeAPIRequest 等函数相互定位。 这一切都运行得很好,不需要 DNS 或 service router

但是,当远程API请求到达云基础架构时,确定如何灵活地路由针对上游服务的请求就成为问题。 考虑服务可以使用不同的IP和/或随机端口启动。 为了满足这些要求,一种方法涉及使用DNS,弹性负载均衡器和弹性IP。 仍然必须管理连接到每个负载均衡器的机器, 并且在一台机器上运行多种服务会使情况进一步复杂化。

这是动态服务注册和路由器起作用的地方。它们旨在通过感知服务并执行智能路由来简化上述要求。


Hydra-Router 使用 Hydra 来实现动态服务注册表和路由器。 为此,它使用启用了 Hydra 的服务在其启动和初始化阶段发布的路由信息。 然后,它将传入的消息直接路由到服务,而不考虑以下挑战:


  • 可能有一个或多个服务实例可用于处理特定请求。
  • 服务可以来来去去,每次都以不同的IP地址或端口开始。
  • 随着服务的添加或改进,服务路由可能会更改(更新或删除)。
  • 不需要对基础设施进行任何更改来解决上述问题。

那么这是如何运作的呢?


如前所述,在启动期间,Hydra 服务执行自动注册。 这是在调用 hydra.registerService 方法时在后台完成的。 使用 Hydra-Express 构建服务时,可以在初始化阶段自动注册服务的路由。服务的路由可以在初始化阶段自动注册。


hydraExpress.init(config, version, () => {
  hydraExpress.registerRoutes({
    '/v1/offers': require('./offers-v1-api')
  });
});


然后,HydraRouter 使用生成的服务注册信息将消息路由到特定服务。

服务可以在网络上的任何机器上启动,无论是否使用随机 IP 端口。 因为每个服务都是自己注册的-它可以被一个 HydraRouter 定位。这是动态服务注册表位。


但它真的是 router 吗?是的! Hydra-Router 使用 route-parser — 一种基于 AST 的树解析器来匹配路由。


当消息被发送到 HydraRouter 时,它会检查请求是否与已注册的路由匹配。如果是,则将请求消息路由到注册了该路由的服务的活动实例。当一个服务存在多个服务实例时,Hydra-Router 将对请求进行负载平衡,以将负载分布在可用的服务之间。

这里的一个关键要点是,这是自动发生的,不需要更新配置和基础设施。 这可以使用 Hydra 内置的服务发现和路由功能。


消息网关


除了将普通的 HTTP 消息路由到它们指定的服务之外,HydraRouter 还为其他传入消息公开一个 HTTP 端点。


/v1/router/message


消息预期采用UMF消息格式,因此可以路由到网络中的其他微服务。


网站流量透传


Hydra-router 能够将站点请求路由到微服务。 因此,除了响应 RESTful API 调用和处理消息外,微服务还可以为网站提供服务。此特性并不适用于高流量使用的场景。 相反,该特性用于管理页面、状态页面和其他低流量的情况。 虽然可以提供图像和其他二进制资产——建议您使用CDN来卸载对公共静态资产的请求。


使用此特性的好处是,您可以在任意IP上的动态端口上启动服务,并利用路由器查找各个服务实例。 通过这种方式,网站请求可以由多个负载均衡的服务实例来处理。


HTTP 代理透传


HydraRouter 允许您指定到非 hydra 服务的路由。 本质上,这允许外部客户端通过 hydra 向后端服务器发出 API 请求。


要启用此功能,只需在配置文件中的 externalRoutes 键下定义外部路由。 externalRoutes key 由url对象和它们的路由数组组成。


:
'externalRoutes': {
  'https://someotherservice.com': [
    '[post]/api/v2/token/create',
    '[get]/api/v2/user/self.json'
  ]
},
:


WebSockets


Hydra Router 支持 WebSocket 连接。支持以下方案:


  • 客户端连接到 hydra-router 并将消息发送到后端服务
  • 后端服务可以将异步消息发送回特定客户端
  • 客户端可以通过 hydra-router 向彼此发送消息


有关构建此类应用程序的更多信息,请参见 Hydra Router Message Client 文档。

不过,这里有一个问题——只支持 stringified UMF 格式的消息。


let ws = new WebSocket('ws://127.0.0.1:5353');
ws.on('open', () => {
  let msg = {
    'to': 'a-hydra-service:/',
    'version': 'UMF/1.4.3',
    'from': 'tester:/',
    'mid': '4736ef3d-fcbb-46aa-80a0-f4f3493e1d74',
    'timestamp': '2017-01-12T20:16:29.157Z',
    'body': {}
  };
  ws.send(JSON.stringify(msg));
});


您可以使用 Hydra UMFMessage helper class 创建 UMF 消息。


WebSocket 重连接和消息传递


如果客户端的 WebSocket 连接中断,Hydra-Router 支持为您的 WebSocket 客户端提供消息队列。 您的客户端仅需要重新连接并发出重新连接消息即可开始接收以前的消息。


初始连接后,您的 WebSocket 客户端将收到一条类似于以下内容的消息:


{
  "to": "2945p8eigxz@client:/",
  "frm": "c274b25909aee5cbec2857361f425fa7@hydra-router:/",
  "mid": "dffc2949-0e2a-4417-8f28-46addb5fc716",
  "ts": "2017-01-12T19:31:54.831Z",
  "typ": "connection",
  "ver": "UMF/1.4.3",
  "bdy": {
    "id": "2945p8eigxz"
  }
}


bdy.id 值是 WebSocket session ID。 如果您的客户端死亡并且需要重新连接,它可以发出一条重新连接消息,例如:


{
  "to": "hydra-router:/",
  "frm": "client:/",
  "mid": "e173a0da-2785-4f83-8b39-0dea954dd91b",
  "typ": "reconnection",
  "ver": "UMF/1.4.3",
  "bdy": {
    "id": "2945p8eigxz"
  }
}


上面有三件事要注意。首先,消息被发送到 hydra-router,后者管理实际的 WebSocket 连接。 其次,bdy.id 与客户端崩溃或失去连接之前所拥有的 WebSocket 会话ID相同。 第三,我们使用“reconnection”的消息类型(typ)。

收到这样的消息后,Hydra-Router 将加载排队的消息(如果有)并将其开始发送到新连接的客户端。


保护 Websocket 消息


Hydra-Router 支持使用加密签名的UMF消息。 启用此功能后,仅接受签名的消息。 未签名的消息将导致底层 socket 连接终止。


签名的消息仅确保消息是由已知客户端创建的,而其本身并不对消息内容进行加密。 要加密消息内容,请考虑使用其他加密方法并转换为 BASE64。


要启用签名消息,请在 config.json 文件中添加两个字段。 确保 forceMessageSignture 设置为 true,并且 signatureSharedSecret 包含 UUID 或密码


"forceMessageSignature": true, 
"signatureSharedSecret": "d632dd6d-fb75-44cc-bdbf-ee1364f3716c",


HydraRouter 使用 HMAC SHA-256 通过提供的 signatureSharedSecret 对消息进行签名。


crypto
  .createHmac('sha256', signatureSharedSecret)
  .update(JSON.stringify(this.message))
  .digest('hex');


因为 Websocket 消息是从外部客户端发送的, 所以每个客户端必须能够使用 HMAC SHA-256, 使用与 HydraRouterconfig.json 文件中存储的相同的共享 secretUMF 消息进行签名。 由于很难在 Web浏览器客户端中保护 secret,因此不建议将其用于 Web 客户端。 建议编译并能够使用安全存储的微服务和移动应用程序。

1.4.28 版本开始,Hydra 支持对 UMF 消息进行签名, 从而可以轻松保护微服务之间的消息。 为 IOSAndroid 编写的客户端应用程序需要使用加密库。

在 Hydra 中,您可以使用:


'use strict';
const WebSocket = require('ws');
const hydra = require('hydra');
const signatureSharedSecret = 'd632dd6d-fb75-44cc-bdbf-ee1364f3716c';
let ws = new WebSocket('http://localhost:5353');
ws.on('open', () => {
  let umf = hydra.createUMFMessage({
    'to': 'hydra-router:[GET]/v1/router/list/nodes',
    'from': 'client:/',
    'body': {}
  });
  umf.signMessage('sha256', signatureSharedSecret);
  ws.send(JSON.stringify(umf));
});
ws.on('message', (data, flags) => {
  console.log(data);
});


路由仪表板


Hydra-Router 可以显示一个仪表板,以显示其自身和其他服务的状态。 仪表板每15秒更新一次,红色显示有问题的服务。


要访问路由器,只需将浏览器指向 hydra-router 的根目录即可:


http://localhost:5353/



如果您需要停用或限制对仪表板的访问,请参阅保护 hydra-router 一节。


可选的 Router API


Hydra-Router 提供了 HTTP API,以公开其正在使用的路由和服务。 这是完全可选的,旨在用于调试和监视方案。


Router version: /v1/router/version

查询 Hydra-Router 的版本。


$ curl -X 'GET' 'http://localhost:8000/v1/router/version'


响应:


{
  'status': 200,
  'statusText': 'Success',
  'result': {
    'version': '1.0.0'
  }
}


Listing routes: /v1/router/list/routes

用于显示已注册路由的列表。请注意,Hydra-Router 本身是一种服务,它显示自己的 API


{
  'status': 200,
  'statusText': 'Success',
  'result': [
    {
      'serviceName': 'hydra-router',
      'routes': [
        '/v1/router/version',
        '/v1/router/refresh',
        '/v1/router/list/:thing',
        '/v1/router/message',
        '/v1/router/refresh/:service'
      ]
    },
    {
      'serviceName': 'red-service',
      'routes': [
        '/v1/red/hello',
        '/v1/red/say'
      ]
    },
    {
      'serviceName': 'blue-service',
      'routes': [
        '/v1/blue/hello',
        '/v1/blue/say'
      ]
    }
  ]
}


Listing services: /v1/router/list/services

显示活动服务实例。 在这里,我们可以看到服务存活状态信息(presence),包括健康(health)和正常运行时间(uptime)等数据点。 如果服务崩溃,它将不再出现在响应中。


{
  'status': 200,
  'statusText': 'Success',
  'result': [
    {
      'serviceName': 'blue-service',
      'instanceID': 'bd579b2384701aba617af40c0ff75580',
      'updatedOn': '2016-05-22T00:21:11.908Z',
      'processID': 51947,
      'ip': '127.0.0.1',
      'port': 3686,
      'sampledOn': '2016-05-22T00:21:11.908Z',
      'architecture': 'x64',
      'platform': 'darwin',
      'nodeVersion': 'v4.2.4',
      'memory': {
        'rss': 28045312,
        'heapTotal': 31148896,
        'heapUsed': 26754472
      },
      'uptime': '2 minutes, 7.358 seconds',
      'usedDiskSpace': '82%',
      'log': []
    },
    {
      'serviceName': 'hydra-router',
      'instanceID': '4d5831c3de6feb69a6b150946753065c',
      'updatedOn': '2016-05-22T00:21:11.103Z',
      'processID': 51755,
      'ip': '127.0.0.1',
      'port': 8000,
      'sampledOn': '2016-05-22T00:21:11.103Z',
      'architecture': 'x64',
      'platform': 'darwin',
      'nodeVersion': 'v4.2.4',
      'memory': {
        'rss': 27168768,
        'heapTotal': 18740576,
        'heapUsed': 17638920
      },
      'uptime': '3 minutes, 2.337 seconds',
      'usedDiskSpace': '82%',
      'log': [
        {
          'ts': '2016-05-22T00:18:10.383Z',
          'serviceName': 'hydra-router',
          'type': 'info',
          'processID': 51755,
          'message': 'Starting hydra-router service hydra-router on port 8000'
        }
      ]
    },
    {
      'serviceName': 'red-service',
      'instanceID': 'a3e9a88912b49238e7254ef3cec2e4cd',
      'updatedOn': '2016-05-22T00:21:09.766Z',
      'processID': 51759,
      'ip': '127.0.0.1',
      'port': 1185,
      'sampledOn': '2016-05-22T00:21:09.767Z',
      'architecture': 'x64',
      'platform': 'darwin',
      'nodeVersion': 'v4.2.4',
      'memory': {
        'rss': 30908416,
        'heapTotal': 31148896,
        'heapUsed': 27060712
      },
      'uptime': '2 minutes, 47.579 seconds',
      'usedDiskSpace': '82%',
      'log': [
      ]
    }
  ]
}


Listing nodes: /v1/router/list/nodes

列表节点请求显示可能存在也可能不存在的节点(服务的实例)。 此调用与 /list/services 调用的不同之处在于,将显示不活动的实例。


$ curl -X 'GET' 'http://localhost:8000/v1/router/nodes'


{
  'statusCode': 200,
  'statusMessage': 'OK',
  'statusDescription': 'Request succeeded without error',
  'result': [
    {
      'serviceName': 'music',
      'serviceDescription': 'Music service',
      'version': '0.0.9',
      'instanceID': '07eb06f8f8b346a78704a5d9e672a780',
      'updatedOn': '2016-07-27T19:38:28.773Z',
      'processID': 2209,
      'ip': '10.1.1.176',
      'port': 5000,
      'elapsed': 2
    },
    {
      'serviceName': 'hydra-router',
      'serviceDescription': 'Service Router',
      'version': '1.1.1',
      'instanceID': 'ecf72192389ff6212bf88da03802adc9',
      'updatedOn': '2016-07-27T19:38:29.705Z',
      'processID': 2864,
      'ip': '10.1.1.176',
      'port': 5353,
      'elapsed': 1
    },
    {
      'serviceName': 'auth-service',
      'serviceDescription': 'Authentication service',
      'version': '0.0.10',
      'instanceID': '5b3ade39a70aba675223edc46d8c710c',
      'updatedOn': '2016-07-27T19:38:13.371Z',
      'processID': 2487,
      'ip': '10.1.1.176',
      'port': 1337,
      'elapsed': 17
    }
  ]
}


Route Refresh: /v1/router/refresh/:service

当基于 hydra 启用的 web 服务它们在线自动启用。

示例路由透传:


通过 Hydra-Router 将消息发送到称为 red-service 的服务的示例:


$ curl -X 'GET' 'http://localhost:8000/v1/red/hello'


响应:


{
  'code': 200,
  'result': {
    'message': 'Hello from red-service'
  }
}


您可能已经注意到上面的响应中有一点不一致。 前面的示例显示 statusstatusTextresult JSON 字段。 上面的例子不是这样的!原因是 Hydra-Router 返回从服务端点发送的确切的(未翻译的)服务器响应。


保护 router


默认情况下,路由器API是公开的。 在生产部署中,您可能会禁用或限制对路由器 API 的访问权限。 您可以通过在 config.json 文件中定义两个 key 来完成此操作:


"disableRouterEndpoint": false,
"routerToken": "",


如果 disableRouterEndpoint 设置为 true, 则将禁用对路由器 API 的访问,并且调用者将收到 HTTP 404 响应。 如果启用,则对路由器 API 的访问取决于 routerToken 的值。 如果令牌为空,则允许访问-如果存在值,则它必须是 UUIDv4 token。


"disableRouterEndpoint": false,
"routerToken": "098ebe18-7e1b-4ddd-ae2a-cc6521e5b641",


破折号和段的大小很重要,并使用正则表达式进行了验证。

Hydra-Router 将搜索 token 的存活状态(presence)作为查询字符串参数。


http://localhost:5353/v1/router/list/routes?token=098ebe18-7e1b-4ddd-ae2a-cc6521e5b641


问题


当服务更改了它的路由时会发生什么?

好问题! 启动服务时,除了注册自身和发布其路由外,它还会向所有 Hydra-Router 服务广播一条消息, 以便它们可以为新更新的服务更新其路线信息。 这是基于每个服务完成的,因此其他服务路由不会受到影响。

如果服务实例不可用怎么办?


如果找不到服务的活动实例,则 Hydra-Router 会回复并显示标准 HTTP 503(HTTP_SERVICE_UNAVAILABLE)错误。

那么有什么问题吗?


HydraRouter 只能与启用了 Hydra 的服务一起使用,并且只能路由 JSON 消息有效负载。 但是,支持最常见的 HTTP 动词,因此您可以发送 GET,POST,DELETE 和 PUT 请求。


Hydra Router 消息客户端


注意:hrmc 需要 hydra-router 1.6.0 或更高版本

作为一个消息传递网关,Hydra Router 支持 WebSocket 连接和消息路由到连接的客户端和微服务。 在开发基于消息的客户端和服务时,有必要测试消息流。 这使得我们创建了一个名为 hrmc 的工具 —— Hydra Router Message Client。 HRMC 是基于 NodeJS 的 REPL,您可以在其中交互式地连接到 Hydra Router,以发送消息。


$ hrmc
Hydra Router Message Client v.1.0.3
Use client.help() for help.
Use client members or .exit to close repl.


hrmc REPL 导出一个名为 client 的类, 其中包含用于将消息连接并发送到 Hydra Router 实例的成员函数。 例如,要打开与在本地主机端口 5353 上运行的 hydra router 实例的连接,请执行以下操作:


➤ client.open('ws://localhost:5353')


关闭连接:


➤ client.close()


安装 hrmc


您可以使用 NPM 安装 hrmc:


$ npm install -g hrmc


我们应该使用 -g 全局标志来安装它,以确保它可以从您的任何项目中启动。hrmc 项目托管在github上:https://github.com/cjus/hrmc


使用 hrmc


使用 hrmc 之前,请确保您正在运行 hydra-router 实例。 如前所述,您可以使用客户端对象的成员函数在 Hydra Router 上打开和关闭连接。


要获取可用命令的列表,请使用:


➤ client.help()


可用的客户成员列表包括:openclosereopencreateMessagesendMessage

让我们通过一个示例 session 来了解这一切是如何工作的。 在这个 session 中,我们将连接到 hydra router 并调用其内部API。 然后我们将与 user service 对话。


我们首先连接到 hydra-router。在这个例子中,我正在连接 192.168.1.221:5482hydra router


➤ client.open('ws://192.168.1.221:5482')


为了保持一致,所有 hrmc client 函数都需要一个参数-期望该参数为字符串! 因为 JSON 使用双引号,所以我们将使用单引号字符。

返回的响应为:


➤ Connection established: 27ce6oxplm5
{"to":"27ce6oxplm5@client:/","frm":"5d77f8ac3d784bc2946e4d2a2f806805@hydra-router:/","mid":"72ffb790-6634-4e97-8e48-276c223b7b0f","ts":"2018-02-19T14:43:37.407Z","typ":"connection","ver":"UMF/1.4.6","bdy":{"id":"27ce6oxplm5","ip":"::ffff:192.168.1.221"}}


上面的代码可能有点难以阅读,所以您可以使用 client.jsonPrint() 函数来漂亮地打印 JSON。


{
  "to": "27ce6oxplm5@client:/",
  "frm": "5d77f8ac3d784bc2946e4d2a2f806805@hydra-router:/",
  "mid": "72ffb790-6634-4e97-8e48-276c223b7b0f",
  "ts": "2018-02-19T14:43:37.407Z",
  "typ": "connection",
  "ver": "UMF/1.4.6",
  "bdy": {
    "id": "27ce6oxplm5",
    "ip": "::ffff:192.168.1.221"
  }
}


这就是 hydra-router 的响应。 JSON 文档采用一种名为 UMF 的格式,hydra 使用该格式进行消息传递。

有关更多信息,请参见 hydra消息传递

to 字段中,我们看到消息被视为来自 27ce6oxplm5@client:/ 您将注意到来自 @clientID。 这是我们连接的 hrmc 的唯一客户端 ID。它与我们在上面建立连接时返回的 ID 相同。


frm 字段告诉我们,以上消息是从具有唯一服务ID 5d77f8ac3d784bc2946e4d2a2f806805 的 hydra-router 发送的,该消息的 bdy 正文部分特别重要,因为它为客户端分配了唯一的ID 27ce6oxplm5

让我们继续前进。 接下来,我们将创建一条新消息以发送到 Hydra Router。


➤ client.createMessage()
{"to":"hydra-router:/","frm":"27ce6oxplm5@client:/","mid":"c677bf50-80be-4d2e-87e1-4d048c372b47","ts":"2018-02-19T15:26:35.835Z","ver":"UMF/1.4.6","bdy":{}}


这将创建一条基本消息,我们可以将JSON复制到编辑器并对其进行自定义。 更新 to 字段到 hydra-router:[get]/v1/router/version

当我们使用 client.jsonPrint() 函数获取响应并查看它时,我们看到:


{
  "to": "27ce6oxplm5@client:/",
  "frm": "5d77f8ac3d784bc2946e4d2a2f806805@hydra-router:/",
  "mid": "312da70c-8b72-48a9-a481-77d32653e867",
  "ts": "2018-02-19T15:35:34.114Z",
  "ver": "UMF/1.4.6",
  "bdy": {
    "version": "1.6.0-experimental"
  }
}


在撰写本文时,我使用的是 Hydra-Router 的实验版本 1.6.0。

现在,让我们谈谈 user service。

我们可以使用 client.createMessage 创建另一个消息,然后将 to 字段更改为:user-service:[get]/v1/user/health

因此,在我们要发送给 Hydra Router 的新消息中, 我们将要求它将其传递给名为 user-service 的服务, 并请求 v1/user/health 端点。 使用 client.jsonPrint() 函数查看时,响应类似于:


{
  "to": "27ce6oxplm5@client:/",
  "frm": "user-servcie:[get]/v1/user/health",
  "mid": "1a92789c-e6e4-43e8-b4ad-c08999c26141",
  "rmid": "c677bf50-80be-4d2e-87e1-4d048c372b47",
  "ts": "2018-02-19T15:58:25.440Z",
  "ver": "UMF/1.4.6",
  "bdy": {
    "result": {
      "serviceName": "user-svcs",
      "instanceID": "a125395c70f643dfb6743dc5aba32e17",
      "hostName": "dac3865f9fd0",
      "sampledOn": "2018-02-19T15:58:25.454Z",
      "processID": 1,
      "architecture": "x64",
      "platform": "linux",
      "nodeVersion": "v8.0.0",
      "memory": {
        "rss": 54370304,
        "heapTotal": 28356608,
        "heapUsed": 25279784,
        "external": 66409
      },
      "uptimeSeconds": 287.767
    }
  }
}


更高级的例子


现在,如果我们希望后端服务将消息异步发送回连接的客户端,该怎么办?

后端服务只需要知道客户端ID即可路由消息!这是消息的格式。


{
  "to": "hydra-router:/",
  "frm": "abackend-service:/",
  "fwd": "27ce6oxplm55@client:/",
  "mid": "5cc4e3f5-ad72-41f3-a23f-212bdabc331f",
  "ts": "2018-02-17T16:02:48.902Z",
  "ver": "UMF/1.4.6",
  "bdy": {
    "msg": "Hello from a backend service"
  }
}


后端服务只需在 to 字段中指定网络中任何可用的 hydra-router 实例。 然后,您的服务将在 frm 字段中标识自己。 然后它将使用 fwd(转发)字段指定应接收消息的客户端实例。 消息的 bdy 将包括您的服务要发送的任何 JSON 负载。 接收 hydra-router 实例将确保将消息路由到适当的客户端。


这种路由机制也允许客户端互相发送消息:


{
  "to": "hydra-router:/",
  "frm": "1objkd63kfd@client:/",
  "fwd": "27ce6oxplm55@client:/",
  "mid": "5cc4e3f5-ad72-41f3-a23f-212bdabc331f",
  "ts": "2018-02-17T16:02:48.902Z",
  "ver": "UMF/1.4.6",
  "bdy": {
    "msg": "Hello from 1objkd63kfd"
  }
}


因此,客户端又会通过 hydra-router 发送打算发送给另一个客户端的消息。

重要的是要注意,客户端不是直接与对方通话,而是通过 hydra router。

由于 Hydra-Router 旨在与其他 hydra-routers 进行通信, 因此可以将消息路由到客户端和服务,无论它们连接到哪个 hydra-router。 自然地,所讨论的 hydra-routers 和服务需要在同一网络或可访问的网络上。


因此,在此示例中,尽管客户端 1objkd63kfd27ce6oxplm55 没有连接到相同的 Hydra-Router,但上面的相同消息仍将被路由。

支持以下方案:

  • 客户端连接到 hydra-router 并将消息发送到后端服务
  • 后端服务可以将异步消息发送回特定客户端
  • 客户端可以通过 hydra-router 向彼此发送消息


在 Docker 上使用 Hydra


Hydra 和 HydraExpress 应用程序需要使用 Redis 服务器。 如果您在 Docker 容器中运行启用了 hydra 的微服务,则需要确保您的服务可以访问 Redis。

如:hello-service

用作 docker 容器时,您需要更新服务的配置文件,因为正在运行的容器将具有与主机不同的IP地址。 这样就不会在容器内找到 Redis!

有几种方法可以解决此问题。


方法1:在容器生成上使用硬编码 config.json


第一种方法是简单地用 Redis 服务器的硬编码配置条目构建容器。


方法2:使用 DNS 条目


另一个选择是在配置文件中指定一个 DNS 条目,它映射到你的 Redis 服务器。参见下面的 redislocation 条目。


{
  "environment": "development",
  "hydra": {
    "serviceName": "hello-service",
    "serviceIP": "",
    "servicePort": 5000,
    "serviceType": "hello",
    "serviceDescription": "says hello",
    "redis": {
      "url": "redis://redislocation:6379/15"
    }
  }
}


接下来,使用上面的配置重建容器,然后可以使用以下命令运行它:


$ docker run -it -d -p 5000:5000 \
  --name hello-service \
  --add-host redislocation:192.168.1.186 \
  --workdir=/usr/src/app \
  cjus/hello-service:0.0.7


然后,您可以使用以下方法测试访问容器的服务:


$ curl localhost:5000/v1/hello/test
{"statusCode":200,"statusMessage":"OK","statusDescription":"Request succeeded without error","result":{"msg":"hello from hello-service - da3a2e99becc03abed949080d8fa3185"}}


方法3:映射虚拟文件夹


然而,另一种方法是运行带有映射卷的容器。在本例中,本地项目文件夹 ~/dev/hello-service/config 映射到容器的内置 /usr/src/app/config 文件夹上。因此,运行中的容器将使用您在项目文件夹中指定的配置文件。这样一来,您就可以将 config.json 文件保留在容器中,并在容器外部对其进行覆盖。


$ docker run -it -d -p 5000:5000 \
  --name hello-service \
  --workdir=/usr/src/app \
  -v ~/dev/hello-service/config:/usr/src/app/config \
  cjus/hello-service:0.0.7


相关文章
|
3月前
|
负载均衡 数据可视化 NoSQL
强烈推荐,好用的时序图开源插件PlantUML!
PlantUML这个开源时序图插件,它通过简单的语法和自动化的图形线条关联解决了传统画图软件中对齐困难、逻辑判断不易表示等问题,并提供了美观的图形和易于修改的特点,特别适合新入职场的开发者快速上手绘制高质量的时序图。
强烈推荐,好用的时序图开源插件PlantUML!
Minecraft Fabric 教程 #4 添加分组
在 ItemGroup 显示 使用 FabricItemGroupBuilder
56 0
|
应用服务中间件 nginx
Phalcon如何创建多模块并能进行访问 《Phalcon入坑指南系列 四》(1)
Phalcon如何创建多模块并能进行访问 《Phalcon入坑指南系列 四》
198 0
Phalcon如何创建多模块并能进行访问 《Phalcon入坑指南系列 四》(1)
|
容器
Phalcon如何创建多模块并能进行访问 《Phalcon入坑指南系列 四》(2)
Phalcon如何创建多模块并能进行访问 《Phalcon入坑指南系列 四》
174 0
Phalcon如何创建多模块并能进行访问 《Phalcon入坑指南系列 四》(2)
ReactiveCocoa(FRP)-进阶篇(下)
ReactiveCocoa(FRP)-进阶篇(下)
154 0
ReactiveCocoa(FRP)-进阶篇(下)
|
消息中间件 存储 NoSQL
hydra-microservice 中文手册(完整篇)(一)
hydra-microservice 中文手册(完整篇)(一)
346 0
|
消息中间件 存储 NoSQL
hydra-microservice 中文手册(下篇)(一)
hydra-microservice 中文手册(下篇)(一)
196 0
|
存储 NoSQL 安全
hydra-microservice 中文手册(下篇)(二)
hydra-microservice 中文手册(下篇)(二)
146 0
|
负载均衡 NoSQL JavaScript
hydra-microservice 中文手册(上篇)
hydra-microservice 中文手册(上篇)
197 0
|
存储 负载均衡 前端开发
hydra-microservice 中文手册(中篇)
hydra-microservice 中文手册(中篇)
265 0