Core
Hydra(core)
是为 Hydra
项目提供动力的 NPM 包。如果您正在使用 ExpressJS
构建您的服务, 您应该检查看 Hydra-Express package 包, 它是专门为利用 ExpressJS 的底层功能而设计的。
本节介绍了核心 Hydra 模块,该模块旨在使微服务的构建和/或使非服务(non-service
)应用程序能够发现和利用微服务。因此,Hydra 在构建分布式应用程序时可帮助解决各种问题。
虽然 Hydra 是为 NodeJS 实现的,但它支持的功能也可以在其他平台上实现。
核心服务依赖于共享的 Redis 实例或集群,比如 Amazon 的 ElasticCache
- 要了解更多关于 Redis 的信息,请查看我们的快速入门教程 并访问 Redis.io
作为一个 Node module,Hydra 提供了嵌入式(drop-in
)功能,旨在解决以下微服务问题:
- 服务注册(
Service Registration
):允许服务在上线时注册自己并发布它们的HTTP API
路由。 - API 可路由性(
API Routability
):允许将API调用路由到微服务。 - 消息传递通信(
Messaging Communication
):通过发布和订阅通道以及消息队列进行的服务间通信。 - 服务负载平衡(
Service Load Balancing
):基于可用的(现有的)微服务实例自动平衡请求。 - 服务发现(
Service Discovery
):在不需要硬编码其IP地址和端口信息的情况下定位服务。 - 运行状况报告(
Health Reporting
):自动运行状况检查报告,用于回答以下问题:应用程序是否健康?它运作正常吗? - 存在状态报告(
Presence Reporting
):服务实例实际可用吗?
在本文档中,我们将引用服务(services
)和服务实例(service instances
)。服务实例和服务节点指的是同一件事。服务只是赋予一个或多个服务实例的名称,将其视为服务的一类。例如,我们可能有一个服务来处理图像大小调整,而我们可以简单地调用该服务 image-resizer
。在我们的云基础架构中,为了响应高需求,我们可能会运行三个 image-resizer
服务实例。每个实例都是服务实例或节点。
在 Hydra 中,服务实例仅仅是使用 Hydra 处理微服务问题的过程。
安装和初始化 Hydra
要从另一个项目中使用 Hydra
:
$ npm install hydra
导入 Hydra
const hydra = require('hydra');
初始化
导入时,会加载 Hydra 模块,但必须先将其初始化才能使用。
hydra.init(initObject);
初始化对象包含以下字段:
{ serviceName: 'hydramcp', serviceDescription: 'Hydra Master Control Program', serviceIP: '', servicePort: 0, serviceType: 'mcp', redis: { host: '127.0.0.1', port: 6379, db: 0 } }
所有显示的字段都是必需的。但是,如果您的应用程序不打算作为服务运行,那么下面的值可以为空并将被忽略。如果您不打算使用这些值,那么最好将它们空白。但是,此时 serviceName
不能为空。
serviceDescription: '', serviceDNS: '', serviceIP: '', servicePort: 0, serviceType: '',
重要:
- 当
Hydra
在一个服务中使用时,如果serviceIP
等于一个空字符串(''),那么将使用该机器的本地IP,否则需要一个四段IP地址(52.9.201.160)
。如果servicePort
等于0
,那么 Hydra 将选择一个随机端口。在需要微服务使用特定端口地址的情况下设置servicePort
。 hydra.serviceDNS
条目允许您指定服务 DNS 而不是 IP 地址。
这使您可以将服务放置在外部负载平衡器(例如 Nginx
或 Docker Swarm
的内部 DNS
)之后。存在值时,serviceDNS
条目将忽略 serviceIP
字段-即使它包含一个值。
- 对于集群中的所有网络服务,必须将
hydra.redis.dbvalue
设置为相同的值。
不这样做会影响服务的可发现性和监视。在 Hydra 中未对 redis 数据库值进行硬编码的原因是, 不能保证 Redis 实例上存在的数据库数量在提供商之间是相同的。因此,最终服务实现者(您?)需要设置此值的灵活性,从而承担责任。
在一个实际的生产系统中 Hydra JSON
可能被嵌入到一个更大的配置文件中,比如 properties.js
文件:
exports.value = { appServiceName: 'hydramcp', cluster: false, environment: 'development', maxSockets: 500, logPath: '', hydra: { serviceName: 'hydramcp', serviceDescription: 'Hydra Master Control Program', serviceVersion: '1.0.0', serviceIP: '', serviceDNS: '', servicePort: 0, serviceType: 'mcp', serviceWorker: false, redis: { host: '127.0.0.1', port: 6379, db: 0 } } };
当使用这种方法时,只需在初始化过程中传递 hydra 分支:
hydra.init(config.hydra);
如果要在要初始化文件的同一文件中使用 hydra
, 则可以先等待 hydra.init()
返回的 promise
,然后再使用其他 hydra
方法。
// index.js hydra.init({...}) .then(...);
但是,如果从单独的文件导入 hydra
实例,则需要调用 hydra.ready()
方法。
hydra.ready()
返回与 hydra.init()
完全相同的 promise
,尽管这样做无需重新初始化 hydra
实例。
// my-hydra.js import hydra from 'hydra'; hydra.init({...}); export default hydra;
// service.js import hydra from './my-hydra.js'; hydra.ready().then(...);
调用 hydra.init()
之后,可以随时使用 hydra.ready()
来等待初始化完成。
Redis 配置
除了 host
、port
和 db
,你可以通过 node redis client createClient
方法支持的任何选项。
retry_strategy
是一个例外,它在 redis.createClient
中带有一个函数参数。 Hydra
提供了 retry_strategy(hydra._redisRetryStrategy)
,它是通过hydra.redis.retry_strategy
选项配置的,而不是直接传递给 redis.createClient
:
redis: { host: "127.0.0.1", port: 6379, db: 15, retry_strategy: { maxReconnectionPeriod: 15, maxDelayBetweenReconnections: 5 } }
您还可以选择使用 url
参数代替 host
,port
,db
和 password
。有关详细信息,请参见 IANA registration。以下等效于上面的 host/port/db
:
redis: { url: 'redis://127.0.0.1:6379/15' }
注意:如果你传入一些 host
、port
、db
和 password
的组合,url
中的值会被更具体的条目覆盖:
redis: { url: 'redis://127.0.0.1:6379/15', db: 10 }
这将连接到数据库 10
,而不是数据库 15
。
通过 unix socket
连接
{ "redis": { "path": "/tmp/redis.sock" } }
Hydra 模式
Hydra
可配置为两种使用模式之一:
- 服务模式(
Service mode
)—— 充当服务和其他服务的消费者。 - 消费者模式(
Consumer mode
)—— 只能充当服务消费者,而不能成为服务。
服务模式(Service mode
)
要在 Service mode
下使用 Hydra,您必须先使用以下方式注册:
hydra.registerService();
注意:如果您的应用程序不需要成为服务,那么您就不需要执行此注册。
注册服务后,hydra 会在生成日志事件或消息到达时发出 NodeJS 事件。您可以按以下方式监听这些事件:
hydra.registerService(); hydra.on('log', function(entry) {}); hydra.on('message', function(message) {});
消费者模式(Consumer mode
)
如果消费者模式
应用程序调用与服务模式
相关的方法, 将导致异常(exception
)或 promise
失败。每个调用都在本文档的最后被清楚地记录下来,以帮助避免误用。但是始终要确保您的应用程序经过了充分的测试。
Service Discovery(服务发现)
服务(Service
)和消费者(Consumer
)模式应用程序都可以发现其他服务。但是请记住,消费者模式应用程序本身无法被发现。只能发现注册的服务。
使用 findService()
方法发现服务(Services
)。 findService()
方法接受服务名称,并返回一个 promise
, 该 promise
将 resolve
为服务信息对象;如果找不到该服务,则返回一个被拒绝的 promise
。
hydra.findService('imageprocessor') .then((service) => { console.log(service); }) .catch((err) => { console.log('catch err', err); });
返回的服务对象可能如下所示:
{ "serviceName": "imageprocessor", "processID": 25246, "registeredOn": "2016-03-26T18:26:31.334Z", "ip": "10.0.0.4", "port": 9001, "type": "image:processing" }
然后,应用程序可以使用 ip
和 port
信息来调用 imageprocessor
服务上的 API
。
Presence(存活状态)
仅仅因为可以找到服务并不意味着它当前已在线且处于活动状态。在不幸的情况下,所讨论的服务可能会失败和/或暂时不可用。
Hydra 提供了 getServicePresence()
方法来确定服务当前是否可用。如果可用,则返回这样的对象:
{ "updatedOn": "2016-03-28T01:43:45.756Z" }
如果不可用,则 getservicepresence()
返回一个被拒绝的 promise
。
健康检查(Health
)与存活状态(Presence
)
将 Hydra
配置为服务模式(service mode
)后, 它将自动在指定的 Redis
服务器中记录机器和应用程序级别的信息。此外,Hydra
还发送存活状态(Presence
)信息。不幸的是,如果主机应用程序崩溃,那么 Hydra 自然会停止更新存活状态信息。
此外,Hydra
会维护一个内部日志,用于存储检测到的问题。我们可以将其视为黑匣子飞行记录器(flight recorder
)。
尽管所有这些都是自动发生的, 但是您的应用程序可以使用 Hydra
的 sendToHealthLog()
方法来扩充存储的信息。您还可以使用 getServiceHealthLog()
方法检索日志。
记住,您还可以通过在服务注册期间注册日志事件侦听器,在这些日志条目发生时直接接收它们。