前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >hydra-microservice 中文手册(下篇)

hydra-microservice 中文手册(下篇)

作者头像
为少
发布2021-05-27 19:06:01
4.9K0
发布2021-05-27 19:06:01
举报
文章被收录于专栏:黑客下午茶黑客下午茶

使用 Hydra 监视服务

HydraMCP web 应用程序演示了如何监视 Hydra 服务。有两种监测方法:

  • 读取 hydra 服务写入 Redis 的数据
  • 使用 Hydra 方法接收聚合服务(aggregate service)数据。

后一种方法被推荐,因为它被认为对未来 Hydra 如何在 Redis 中存储数据的潜在变化更具弹性。

以下方法有助于服务的自省(introspection)和控制(control)。

Method

Description

getServices

检索已注册服务的列表。

findService

找到特定的服务。

getServicePresence

检索特定服务的存活状态

getServiceHealthAll

检索所有注册服务的健康信息和健康日志。

makeAPIRequest

向命名服务发出API请求。

有关 Hydra 功能的完整列表,请参阅本文档的最后部分。

messaging(消息传递)

Hydra 通过以下方式支持服务间通信:

  • 发现并直接使用服务器的网络信息(IP和端口)。
  • 通过使用 makeAPIRequest 方法。
  • 使用服务间(inter-service)消息传递。
  • 使用服务消息队列(service message queues)。

您使用哪种方法取决于您的应用程序的需求和您愿意做的额外工作的数量。使用 Hydra 的消息传递方法抽象了您可能需要处理的网络层功能。因此,它提供了一种更简单、更可靠的与远程服务交互的方式。

发现和直接使用该服务的网络信息很简单:

代码语言:javascript
复制
let apiRoute = '/v1/email/send';
hydra.findService('emailer')
  .then((service) => {
    let url = `http://${service.ip}:${service.port}/${apiRoute}`;
    let options = {
      headers: {
        'content-type': 'application/json',
        'Accept': 'application/json; charset=UTF-8'
      },
      method: 'post'
    };
    options.body = emailObject;
    fetch(url, options)
    :
    :

注意:在使用上述方法之前,应该使用 getServicePresence 方法检查服务是否可用。毕竟,我们希望确保服务已注册,并且当前可用。

在这里,使用 HydramakeAPIRequest 方法变得更容易且更不容易出错。 makeAPIRequest 方法接受一个对象,该对象包含服务的名称以及其他有用但可选的信息。该方法自动处理服务可用性检查,如果该服务暂时不可用,甚至可以将消息(请求)推送到服务的消息队列中。这是可选行为,并假定这对于发送方是可接受的,并且远程服务能够将请求作为排队的消息进行处理。

代码语言:javascript
复制
let message = hydra.createUMFMessage({
  to: 'emailer:/v1/email/send',
  from: 'website:backend',
  body: {
    to: 'user@someplace.com',
    from: 'marketing@company.com',
    emailBody: 'Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium'
    fallbackToQueue: true
  }
});
hydra.makeAPIRequest(message)
  then()
:

服务间的消息传递(Inter-service messaging

使用 Hydra,您可以在服务之间发送消息,甚至可以在一系列服务之间路由消息。这是 Hydra-Router 提供的功能之一。

内置消息通道(Built-in message channels

每个 hydra 服务都会自动监听两个内置通道,其他服务发送的消息会在其中到达。

一个通道监听发送到某一类型服务的任何消息,另一个通道监听指向特定服务实例的消息。因此,发送到 file-processing 的消息将被该服务的所有实例接收。而发送到5585f53bd1171db38eafd79bf16e02f4@file-processing 的消息只能由 ID5585f53bd1171db38eafd79bf16e02f4 的服务实例处理。

要将消息发送到服务,可以使用 sendMessage 调用。

代码语言:javascript
复制
let message = hydra.createUMFMessage({
  to: 'test-service:/',
  from: 'blue-service:/',
  body: {
    fileData: '{base64}'
  }
});
hydra.sendMessage(message);

第一个参数是要向其发送消息的服务的名称,第二个参数是包含消息的 UMF 格式的对象。

使用 sendMessage 时,会将消息发送到随机选择的可用服务实例。如果您需要指定特定实例,则可以使用其唯一的服务 ID 来简单地对服务进行寻址。这显示在下面的 “to” 消息字段中。

代码语言:javascript
复制
let message = hydra.createUMFMessage({
  to: 'cef54f47984626c9efbf070c50bfad1b@test-service:/',
  from: 'blue-service:/',
  body: {
    fileData: '{base64}'
  }
});
hydra.sendMessage(message);

您可以通过 getInstanceID()getServicePresence() 方法获得服务的唯一ID。

如果也需要,可以使用 sendBroadcastMessage 方法将消息发送到服务的所有可用实例。

警告:虽然,您可以使用 sendMessage 发送和响应消息 - 建议您在回复时使用 sendReplyMessage。这样做的原因是 sendReplyMessage 使用源消息正确填写健壮消息传递所需的 UMF 字段。这包括使用源 midfortofrom UMF 字段来制定回复消息。

您的服务可以通过将侦听器添加到已加载的 hydra 实例来接收消息。下面的示例演示了如何在必要时制定响应。

代码语言:javascript
复制
hydra.registerService();
hydra.on('message', function(message) {
  // message will be a UMF formatted object
  console.log(`Received object message: ${msg.mid}: ${JSON.stringify(msg)}`);

  // to send a reply message here or elsewhere in your service use the `sendReplyMessage` call.
  hydra.sendReplyMessage(message, hydra.createUMFMessage({
    body: {
      // response items
    }
  }));
});

UMF messaging(UMF 消息传递

在前面的示例中,我们使用了一个 UMF 样式的消息,它是由 Hydra createUMFMessage 方法创建的。 UMFUniversal Message Format 的首字母缩写,是为可路由和可排队的消息传递而设计的轻量级消息传递协议。

UMF 允许您有选择地指定将一条消息发送到一个服务, 然后依次将消息和/或(and/or)其他结果发送到另一个服务。这样,流程可以跨服务链接在一起。

让我们通过看看 createUMFMessage 实际上做了什么来揭开 UMF 的神秘面纱。

首先,该方法接受一个 message 对象。在这个对象中需要三个字段:

代码语言:javascript
复制
{
  "to":'serviceName',
  "from": 'sending-entity-name',
  "body": {}
}

createUMFMessage 方法采用该对象,并返回一个带有附加字段的新对象:

代码语言:javascript
复制
{
  "mid": "02d7e85b-5609-4179-b3af-fee60efc8ef0",
  "timestamp": "2016-03-28T15:40:05.820Z",
  "version": "UMF/1.2",
  "priority": "normal",
  "type": "msg",
  "to": "filewatcher",
  "from": "hydramcp",
  "body": {
    "actions": [
      "restart",
      "processBatch"
    ]
  }
}

附加字段由 UMF 规范定义,并帮助 Hydra 和其他分布式系统处理消息。

createUMFMessage 帮助程序方法有助于确保我们从格式正确的 UMF 兼容消息开始,并可以对其进行进一步扩展。

例如,在这里我们可以在将消息传递给 makeAPIRequest 方法之前更改消息的优先级(priority)和类型(type)。

代码语言:javascript
复制
message.priority = 'high';
message.type = 'service:control';

需要注意的是,我们可以将优先级(priority)和类型(type)字段添加到传递给 createUMFMessage 的原始消息中。该方法将使用您提供的字段来覆盖它在默认情况下创建的字段。因此,重要的是不要随意重写 midtimestamp

注意:有关 UMF 规范的详细信息,请访问:Universal Messaging Format

Hydra 消息队列

当涉及到消息传递和队列时,重要的是要考虑应用程序需要的底层交付保证的级别。Hydra 提供了“基本的”消息传递和排队功能,但并不打算替代 MQTTRabbitKafka 等服务器。因此,Hydra 并没有提供那些系统所具备的许多功能。

因此,接下来是对 Hydra “does” 提供的功能的解释。

像大多数 Hydra 一样,Hydra 排队依赖于内置在 Redis 中的功能。Hydra 使用了一种文档化的原子消息队列模式,这种模式在 Redis 用户中很流行。Redis 的 rpushrpoplpushlrem 函数用于管理代表队列的列表结构中的消息状态。这只是一些背景知识,不必担心,因为 Hydra 的目标是简化这些问题。

Hydra 排队通过将消息排队到现有服务的消息队列来工作。这意味着 Hydra 没有所有微服务都可以使用的共享队列的概念。相反,任何排队的消息都被放置在特定服务的消息队列中。

为了进一步探索这一点,让我们想象一个创建和发送电子邮件的 email-service

任何其他想要发送电子邮件的微服务都可以向 email-service 发送消息。

这样的信息可能是这样的:

代码语言:javascript
复制
{
  "to": "email-service:/",
  "mid": "2cae7508-c459-4794-86c6-42eb78f32573",
  "ts": "2018-02-16T13:34:51.540Z",
  "ver": "UMF/1.4.6",
  "bdy": {
    "to": "carlos.justiniano@gmail.com",
    "from": "accouting@xyzcorp.com",
    "htmlBody": "some html markup"
  }
}

该消息可以从(比方说) accounting service 发送到 email-service, 后者依次将消息排成队列等待最终的传递。

让我们根据我们的电子邮件示例来考虑 Hydra 的消息队列功能。

queueMessage

accounting-service 将使用 hydra queueMessage 函数在 email-service 队列中放置一条消息。实际的消息与我们之前看到的消息类似。

queueMessage 函数接收到 UMF 消息时,它将使用 to 字段的值并对其进行解析以提取服务名称。在我们这里的例子中,这就是电子邮件服务。服务名称在内部用于确定将消息放入哪个队列。hydra 源代码内部的外观显示,消息位于名为 hydra:service::{serviceName}:mqrecieved 的 Redis 列表中。key 的最后一部分是已接收(mqrecieved)队列。以后再说。

代码语言:javascript
复制
  /**
   * @name queueMessage
   * @summary Queue a message
   * @param {object} message - UMF message to queue
   * @return {promise} promise - resolving to the message that was queued or a rejection.
   */
  queueMessage(message)

getQueueMessage

通过将电子邮件放置在电子邮件服务的 mqrecieved 队列中,该服务现在能够提取一条消息并开始对其进行处理。

为此,我们的 email-service 使用服务名称简单地调用了 hydra getQueuedMessage。现在,这是一个重要的考虑因素。任何服务都可以调用 getQueuedMessage 并提供另一个服务的名称来帮助该服务处理消息!不建议这样做 - 但是可以的。它是为“知道自己在做什么”的开发人员设计的。在我们的例子中,我们的电子邮件服务将仅使用 getQueuedMessage('email-service') 来检索 accounting service 排队的消息。

代码语言:javascript
复制
  /**
   * @name getQueuedMessage
   * @summary retrieve a queued message
   * @param {string} serviceName who's queue might provide a message
   * @return {promise} promise - resolving to the message that was dequeued or a rejection.
   */
  getQueuedMessage(serviceName)

现在,您可能想知道,当我们有多个 email-service 实例时, 每个实例都在检查电子邮件队列中是否有排队的电子邮件,该怎么办?那不会导致重复的消息处理吗?

答案是否定的。因为 getQueuedMessage() 是原子的,对它的多次调用不会返回相同的消息。因此,多个服务实例可以同时尝试提取消息,但其中只有一个会接收到给定的消息。 Hydra使用 Redis rpoplpush 函数实现了这一点。其工作方式是从 mqrecieved 队列中读取一条消息,并将其放置在 mqinprogress 队列中。因此,对 getQueuedMessage 的下一个调用将不会在接收到的队列(received queue)中看到原始消息,因为它已被移动到进程队列(process queue)中。同样,这只是实现细节,而不是你需要担心的东西。

因此,一旦我们的电子邮件服务实例(email-service)构造并发送电子邮件, 它就将排队的消息标记为已成功处理。

markQueueMessage

因此,我们的电子邮件服务(email service)调用 markQueueMessage(message, completed, reason) 来发送实际的消息,后面跟着一个 completedtruefalse)和一个可选的 reason字符串。

代码语言:javascript
复制
  /**
   * @name markQueueMessage
   * @summary Mark a queued message as either completed or not
   * @param {object} message - message in question
   * @param {boolean} completed - (true / false)
   * @param {string} reason - if not completed this is the reason processing failed
   * @return {promise} promise - resolving to the message that was dequeued or a rejection.
   */
  markQueueMessage(message, completed, reason)

如果我们的电子邮件服务(email service)无法发送消息, 则可以调用 markQueueMessage 时,让参数 completedfalse。这将导致该消息被重新排队以尝试其他服务。

reason 字段用于指示为什么消息被标记为已完成(completed)或未完成(incompleted)。

将消息标记为已完成(true)将从 mqinprogress 队列中删除该消息。

提示和技巧

如前所述,Hydra 消息队列是最基本的功能, 但由于 Redis 的支持,它的功能也非常强大,速度也非常快。

考虑到对 Redis 的依赖,重要的是不要创建大型排队消息, 并且 Redis 的性能会受到大规模影响。解决此问题的一种方法是将一条小消息排队,该消息指向一条数据库记录或文件系统存储。

我们使用的一个很好的技巧是将一个服务队列消息(service queue messages)放入它自己的队列中。其用法如下……假设一个服务接收到一个不能或不需要立即处理的请求。服务可以通过将消息发送给自己来对消息进行排队,以便稍后进行处理。因为服务的其他实例可能正在检查队列,所以另一个服务将接收消息并处理它。这让我想起了排球比赛,一个地方把球推到空中,让另一个球员把球猛击过网。

如果您需要比 Hydra 提供的更多的消息队列相关功能,可以考虑使用 Kue。或者是广泛使用的完善的消息传递队列系统之一。

Hydra 网络

Hydra 支持许多联网选项。本节将探讨可用的选项以及您何时要使用它们。在以下示例中,我们将使用 Hydra-router 实例 中的 config.json 文件 - 但该配置可能来自任何其他启用了hydra 的应用程序。

代码语言:javascript
复制
{
  "externalRoutes": {},
  "routerToken": "",
  "disableRouterEndpoint": false,
  "debugLogging": true,
  "queuerDB": 3,
  "requestTimeout": 30,
  "hydra": {
    "serviceName": "hydra-router",
    "serviceDescription": "Service Router",
    "serviceIP": "",
    "servicePort": "80",
    "serviceType": "router",
    "plugins": {
      "logger": {
        "logRequests": false,
        "toConsole": false,
        "noFile": true,
        "redact": [
          "password"
        ],
        "elasticsearch": {
          "host": "",
          "port": 9200,
          "index": "hydra",
          "rotate": "daily"
        }
      }
    },
    "redis": {
      "url": "redis://prod.p45rev.ng.0001.usw2.cache.amazonaws.com:6379/15"
    }
  }
}

在上面的 config.json 文件中, 我们主要对 hydra.serviceIPhydra.servicePort 字段感兴趣。

servicePort 允许您指定想要 hydra 监听的 IP 端口。在上面的示例中,hydraRouter 正在监听端口 80。如果您未指定 servicePort(例如,如果 servicePort 为空), 那么 hydra 将选择一个大于 1024 的随机非特权端口。 servicePort 字段还支持指定端口范围。

在此示例中,将从 30004000 中选择一个随机服务端口。

代码语言:javascript
复制
"servicePort": "3000-4000"

另外,如果 hydra 检测到某个随机端口已在使用中,它将尝试使用指定范围内的另一个端口。

让我们关注 serviceIP 字段,如果该字段为空,hydra 将选择它找到的第一个 IPv4 地址。如果该字段包含IP地址(例如192.168.1.18),那么 hydra 将使用该地址。如果该字段包含文本,但不是有效的IP地址,则 hydra 假定您已指定 DNS 名称。

Hydra 启动时,它将查看所有可用的网络接口。启动 Hydra-router 时,我们可以看到这一点。

代码语言:javascript
复制
 _   _           _             ____             _
| | | |_   _  __| |_ __ __ _  |  _ \ ___  _   _| |_ ___ _ __
| |_| | | | |/ _` | '__/ _` | | |_) / _ \| | | | __/ _ \ '__|
|  _  | |_| | (_| | | | (_| | |  _ < (_) | |_| | ||  __/ |
|_| |_|\__, |\__,_|_|  \__,_| |_| \_\___/ \__,_|\__\___|_|
       |___/

Starting service hydra-router:1.4.18 on 10.255.0.13:80
Detected IPv4 IPs:
* lo: 127.0.0.1 255.0.0.0
* eth0: 10.255.0.13 255.255.0.0
* eth0: 10.255.0.12 255.255.255.255
* eth1: 172.18.0.3 255.255.0.0
* eth2: 10.0.9.3 255.255.255.0
* eth2: 10.0.9.2 255.255.255.255

如果您希望 Hydra 绑定到一个特定的地址, 那么可以通过 serviceInterface key 告诉 Hydra 应该 使用哪个接口(interface)和网络掩码(network mask)来标识它应该使用的IP。

您可以在 config.json 文件中使用 interfaceName/interfaceMask 的值执行此操作:

代码语言:javascript
复制
"serviceInterface": "eth2/255.255.255.0",

Hydra Methods(公开导出的方法)

以下是 Hydra 公开导出的方法。

作为一个模块,Hydra 被设计用来隐藏和阻止使用它的内部方法。这有助于确保 Hydra 在越来越多的服务中按照预期的方式运行。

下面的方法列表由以下各节组织。并非所有的应用程序和服务都需要使用列出的所有方法。

  • Setup - 模块设置和服务注册
  • Discovery - 服务发现
  • Presence - 存活状态检查
  • Health - 运行状况(健康)检查和日志记录
  • Messaging - 消息发送
  • Routing - 消息路由

Setup

init

用配置对象初始化 Hydra。

代码语言:javascript
复制
/**
 * @name init
 * @summary Initialize Hydra with config object.
 * @param {object} config - configuration object containing hydra specific keys/values
 * @return {object} promise - resolving if init success or rejecting otherwise
 */
init(config)

ready

返回在初始化完成时解析的 promise。

代码语言:javascript
复制
/**
* @name ready
* @summary returns promise that resolves when initialization is complete
* @return {object} promise - resolving if init success or rejecting otherwise
*/
ready()

shutdown

安全关闭 hydra

代码语言:javascript
复制
/**
* @name _shutdown
* @summary Shutdown hydra safely.
*/
shutdown()

registerService

将机器注册为 Hydra 实例。

代码语言:javascript
复制
/**
 * @name registerService
 * @summary Registers this machine as a Hydra instance.
 * @description This is an optional call as this module might just be used to monitor and query instances.
 * @return {object} promise - resolving if registration success or rejecting otherwise
 */
registerService()

Discovery

getServiceName

检索当前实例的服务名称。

代码语言:javascript
复制
/**
 * @name getServiceName
 * @summary Retrieves the service name of the current instance.
 * @throws Throws an error if this machine isn't a instance.
 * @return {string} serviceName - returns the service name.
 */
getServiceName()

getServiceNodes

检索服务列表(即使处于非活动状态)。

代码语言:javascript
复制
/**
 * @name getServiceNodes
 * @summary Retrieve a list of services even if inactive.
 * @return {promise} promise - returns a promise
 */
getServiceNodes()

getServices

检索可用实例服务的列表。

代码语言:javascript
复制
/**
 * @name getServices
 * @summary Retrieve a list of available instance services.
 * @return {promise} promise - returns a promise which resolves to an array of objects.
 */
getServices()

findService

查找服务。

代码语言:javascript
复制
/**
 * @name findService
 * @summary Find a service.
 * @param {string} name - service name - note service name is case insensitive
 * @return {promise} promise - which resolves with service
 */
findService(name)

Presence

getServicePresence

检索服务/实例的状态信息。

代码语言:javascript
复制
/**
 * @name getServicePresence
 * @summary Retrieve a service / instance's presence info.
 * @param {string} name - service name - note service name is case insensitive
 * @return {promise} promise - which resolves with service presence
 */
getServicePresence(name)

hasServicePresence

指示服务是否存在,表示该服务至少在一个节点中运行。

代码语言:javascript
复制
/**
 * @name hasServicePresence
 * @summary Indicate if a service has presence.
 * @description Indicates if a service has presence, meaning the 
 *              service is running in at least one node.
 * @param {string} name - service name - note service name is case insensitive
 * @return {promise} promise - which resolves with TRUE if presence is found, FALSE otherwise
*/
hasServicePresence(name)

getInstanceID

返回此进程的实例 id

代码语言:javascript
复制
/**
* @name getInstanceID
* @summary Return the instance id for this process
* @return {number} id - instanceID
*/
getInstanceID()

Health

sendToHealthLog

将消息记录到服务的运行状况日志队列中。

代码语言:javascript
复制
/**
 * @name sendToHealthLog
 * @summary Log a message to the service instance's health log queue.
 * @private
 * @throws Throws an error if this machine isn't a instance.
 * @param {string} type - type of message ('error', 'info', 'debug' or user defined)
 * @param {string} message - message to log
 */
sendToHealthLog(type, message)

getServiceHealthLog

获取此服务的运行状况日志。

代码语言:javascript
复制
/**
 * @name getServiceHealthLog
 * @summary Get this service's health log.
 * @throws Throws an error if this machine isn't a instance
 * @param {string} name - name of instance, use getName() if current service is the target.
 *                        note service name is case insensitive.
 * @return {promise} promise - resolves to log entries
 */
getServiceHealthLog(name)

getHealth

检索服务运行状况信息。

代码语言:javascript
复制
/**
 * @name getHealth
 * @summary Retrieve service health info.
 * @private
 * @return {object} obj - object containing service info
 */
getHealth()

getServiceHealthAll

检索所有实例服务的运行状况。

代码语言:javascript
复制
/**
 * @name getServiceHealthAll
 * @summary Retrieve the health status of all instance services.
 * @return {promise} promise - resolves with an array of objects containing instance health information.
 */
getServiceHealthAll()

Messaging

createUMFMessage

创建一个 UMF 样式消息。

代码语言:javascript
复制
/**
 * @name createUMFMessage
 * @summary Create a UMF style message.
 * @description This is a helper function which helps format a UMF style message.
 *              The caller is responsible for ensuring that required fields such as
 *              "to", "from" and "body" are provided either before or after using
 *              this function.
 * @param {object} message - optional message overrides.
 * @return {object} message - a UMF formatted message.
 */
createUMFMessage(message)

makeAPIRequest

向 hydra 服务发出 API 请求。

代码语言:javascript
复制
/**
 * @name makeAPIRequest
 * @summary Makes an API request to a hydra service.
 * @description If the service isn't present and the message object has its
 *              message.body.fallbackToQueue value set to true, then the
 *              message will be sent to the services message queue.
 * @param {object} message - UMF formatted message
 * @return {promise} promise - response from API in resolved promise or
 *                   error in rejected promise.
 */
makeAPIRequest(message)

sendMessage

向 Hydra 服务的所有当前实例发送消息。

代码语言:javascript
复制
/**
 * @name sendMessage
 * @summary Sends a message to all present instances of a  hydra service.
 * @param {string | object} message - Plain string or UMF formatted message object
 * @return {promise} promise - resolved promise if sent or
 *                   error in rejected promise.
 */
sendMessage(message)

sendReplyMessage

根据收到的原始消息发送回复消息。

代码语言:javascript
复制
/**
 * @name sendReplyMessage
 * @summary Sends a reply message based on the original message received.
 * @param {object} originalMessage - UMF formatted message object
 * @param {object} messageResponse - UMF formatted message object
 * @return {object} promise - resolved promise if sent or
 *                   error in rejected promise.
 */
sendReplyMessage(originalMessage, messageResponse)

Routing

registerRoutes

注册路由。

代码语言:javascript
复制
/**
* @name registerRoutes
* @summary Register routes
* @note Routes must be formatted as UMF To routes. https://github.com/cjus/umf#%20To%20field%20(routing)
* @param {array} routes - array of routes
* @return {object} Promise - resolving or rejecting
*/
registerRoutes(routes)

getAllServiceRoutes

检索所有服务路由。

代码语言:javascript
复制
/**
* @name getAllServiceRoutes
* @summary Retrieve all service routes.
* @return {object} Promise - resolving to an object with keys and arrays of routes
*/
getAllServiceRoutes()

matchRoute

将路由路径匹配到已注册路由列表。

代码语言:javascript
复制
/**
* @name matchRoute
* @summary Matches a route path to a list of registered routes
* @private
* @param {string} routePath - a URL path to match
* @return {boolean} match - true if match, false if not
*/
matchRoute(routePath)

Message queues

queueMessage

排队一个消息

代码语言:javascript
复制
/**
* @name queueMessage
* @summary Queue a message
* @param {object} message - UMF message to queue
* @return {promise} promise - resolving to the message that was queued or a rejection.
*/
queueMessage(message)

getQueuedMessage

检索排队的消息

代码语言:javascript
复制
/**
* @name getQueuedMessage
* @summary Retrieve a queued message
* @param {string} serviceName who's queue might provide a message
* @return {promise} promise - resolving to the message that was dequeued or a rejection.
*/
getQueuedMessage(serviceName)

markQueueMessage

将排队的消息标记为已完成或未完成

代码语言:javascript
复制
/**
* @name markQueueMessage
* @summary Mark a queued message as either completed or not
* @param {object} message - message in question
* @param {boolean} completed - (true / false)
* @param {string} reason - if not completed this is the reason processing failed
* @return {promise} promise - resolving to the message that was dequeued or a rejection.
*/
markQueueMessage(message, completed, reason)

Hydra Express

Hydra-Express 包使用 Hydra-core,是专门为利用 ExpressJS 的底层功能而设计的。

我们相信这是 ExpressJS 开发人员构建微服务最快最简单的方式。

上手指南

安装

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

代码语言:javascript
复制
$ npm install hydra-express

用法

代码语言:javascript
复制
'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 成员,允许您输出日志到控制台和日志文件。

代码语言:javascript
复制
hydraExpress.log('error', message);

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

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

服务静态 Web 内容

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

Hydra Cli

上手指南

首先,您需要安装 hydra-cli

代码语言:javascript
复制
$ sudo npm install -g hydra-cli

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

代码语言:javascript
复制
$ 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 实例。

代码语言:javascript
复制
$ hydra-cli config local

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

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

代码语言:javascript
复制
$ hydra-cli use staging

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

代码语言:javascript
复制
$ hydra-cli config list

与 hydra 配置文件一起工作

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

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

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

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

代码语言:javascript
复制
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。

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

代码语言:javascript
复制
$ hydra-cli cfg list myservice

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

代码语言:javascript
复制
$ hydra-cli cfg pull myservice:0.12.1

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

代码语言:javascript
复制
$ hydra-cli cfg pull myservice:0.12.1 
>
 config.json

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

代码语言:javascript
复制
$ hydra-cli cfg push myservice:0.12.2 config.json

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

列出服务信息

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

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

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

代码语言:javascript
复制
$ hydra-cli nodes

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

代码语言:javascript
复制
hydra-cli routes

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

代码语言:javascript
复制
$ hydra-cli health

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

代码语言:javascript
复制
$ hydra-cli health myservice

节点列表清理

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

代码语言:javascript
复制
$ hydra-cli refresh

快速连接到 Redis

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

代码语言:javascript
复制
$ hydra-cli shell

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

代码语言:javascript
复制
$(hydra-cli shell)

下一步

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

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

Hydra 生产器

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

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

快速上手

首先全局安装 Yeomangenerator

代码语言:javascript
复制
$ sudo npm install -g yo generator-fwsp-hydra

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

代码语言:javascript
复制
$ yo fwsp-hydra
? Name of the service (`-service` will be appended automatically) hello

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

代码语言:javascript
复制
Done!
'cd example-service' then 'npm install' and 'npm start'

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

代码语言:javascript
复制
{
  "environment": "development",
  "hydra": {
    "serviceName": "hello-service",
    "serviceIP": "",
    "servicePort": 5000,
    "serviceType": "hello",
    "serviceDescription": "says hello",
    "redis": {
      "url": "redis://127.0.0.1:6379/15"
    }
  }
}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-12-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 黑客下午茶 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • messaging(消息传递)
    • 服务间的消息传递(Inter-service messaging)
      • 内置消息通道(Built-in message channels)
        • UMF messaging(UMF 消息传递)
        • Hydra 消息队列
          • queueMessage
            • getQueueMessage
              • markQueueMessage
                • 提示和技巧
                • Hydra 网络
                • Hydra Methods(公开导出的方法)
                  • Setup
                    • Discovery
                      • Presence
                        • Health
                          • Messaging
                            • Routing
                              • Message queues
                              • Hydra Express
                              • 上手指南
                                • 安装
                                  • 用法
                                  • 日志记录和错误报告
                                  • 服务静态 Web 内容
                                  • Hydra Cli
                                  • 上手指南
                                  • 配置 hydra-cli
                                  • 与 hydra 配置文件一起工作
                                  • 列出服务信息
                                  • 节点列表清理
                                  • 快速连接到 Redis
                                  • 下一步
                                  • Hydra 生产器
                                    • 快速上手
                                    相关产品与服务
                                    云数据库 Redis
                                    腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
                                    领券
                                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档