当前位置: 首页 > 科技观察

如何使用Redis构建轻量级微服务_0

时间:2023-03-16 15:01:56 科技观察

【.com快速翻译】Hydra是一个轻量级的NodeJS库,用于构建微服务等分布式计算应用程序。我们对轻量级的定义是:外部复杂度低,基础设施依赖性低。Hydra之所以基础设施依赖很少,是因为唯一的外部依赖是Redis。如果您正在阅读本文并且从未听说过Redis(这极不可能),请先查看redis.io。稍后再回到这篇文章。Hydra利用Redis丰富的数据结构来实现重要微服务所需要的功能,如存在、服务发现、负载均衡、消息传递、队列等。九头蛇也很轻。事实上,它的重量足以在5美元的RaspberryPiZero上运行。更多信息请参考:https://medium.com/flywheel-tech/embracing-microservices-11750470ba31。除了轻量级之外,Hydra还是构建微服务的最简单方法之一。虽然本文不会介绍Hydra,但是有很多介绍它的资源,但是会深入介绍Hydra如何使用Redis构建轻量级微服务。先免责声明。首先,本文描述的方法可能不是很适合你的项目。您可能需要更庞大的微服务。不要紧。我描述的方法已在FlywheelSports和许多其他公司得到验证。我之前写过一篇文章,详细介绍了我们构建Hydra的原因及其在构建全国性直播视频流服务中的作用。Hydra简介Hydra是一个NodeJS模块,可以导入到JavaScriptNode应用程序中,以赋予它们微服务功能。Hydra通过使用Redis来做到这一点。下面我们看到三个微服务,每个微服务都有一个连接到Redis的Hydra模块。在这个模型中,大部分服务并不直接联系Redis,而是底层的Hydra模块作为Redis的代理。图1该图的另一个重点是Hydra只是另一个导入模块,如图中的绿色框所示。Hydra仅在底部以蓝色显示,表明它的存在以及与Redis的连接。Hydra模块对外暴露了一个JS类接口,共有36个成员函数。图2的上图给出了我们使用的抽象机制的简单性。findService比sendMessage等成员函数要简单得多。Hydra是如何使用Redis的?这张幻灯片显示了一些重要的微服务问题。每个都是重要的微服务所必需的。我们将详细研究Hydra如何使用Redis来实现这些功能中的每一个。图3请记住,这里的目的是展示如何执行此任务,而不是每种方法都需要您弄清楚如何在您自己的服务中实现此功能。一个典型的例子是,虽然可以将微服务配置数据存储在Redis中或将Redis用作记录器,但这并不意味着您应该这样做。除非您确切地知道自己在做什么以及随之而来的缺点,否则不要这样做。另请记住,您不需要Hydra。Redis使这些功能中的每一个成为可能,您当然可以在自己的应用程序中做到这一点。我想指出的另一点是,其中一些功能只能组合使用。例如,请求和消息路由依赖于状态、健康、服务发现和负载平衡。如您所知,这些功能中的每一个都可以使用各种基础设施工具来实现。然而,Hydra的一大目标是简化微服务的构建,同时最大限度地减少对外部基础设施的需求。在构建生产就绪服务时,确定需要哪些Hydra功能以及可以从其他工具获得哪些功能。这不是一个二选一的选择,而是在你想要实现什么功能和你能多快上手之间取得平衡。话虽如此,看看如何仅使用Redis和您最喜欢的编程语言就可以实现这一切将会很有趣。Keyspace组织要了解Hydra如何使用Redis,第一步是分析它如何组织和管理Rediskeyspace的使用。Hydra使用的密钥由2到4个由冒号字符分隔的段标签组成。section标签被命名为:Prefix(前缀)、Servicename(服务名称)、InstanceID(实例ID)和Type(类型)。图4.Prefix部分允许过滤Hydra密钥与非Hydra密钥。因此,如果您经常使用Redis,那么能够针对特定键进行过滤非常重要。服务名称部分有助于过滤特定服务类型的键。服务类型,例如授权、用户或图像处理。实例ID段允许过滤唯一服务实例的键。在运行微服务时,您通常需要运行一个服务类型的多个实例。为每个服务实例分配唯一ID,这有助于区分它们。最后是Type部分,用于对密钥的用途进行分类。并非每个键都有所有段。例如,某些密钥不需要服务名称和实例ID。以下示例显示了用户服务的密钥。我们看到前缀是hydra:service后跟服务名称(在本例中为“user-svcs”)。接下来,我们看到唯一的实例ID。最后,我们看到这个键的类型是存在的。因此,我们说存在信息存储在这个关键地址中。图5前面的一个令人困惑的地方是键由名称组成,带有2到4个由冒号字符分隔的段标签。然而,在这里我们看到hydra:service也是用冒号字符分隔的。这个想法是可能有其他hydra:other类型,其中服务只是其中一种。还有另一个不一致涉及消息传递,这将在后面讨论。我们打算在Hydra2.0中解决这些问题,这将是重大变化,但内部更清洁。我们可以键入redis-cli并输入Redis命令来查看各种密钥。我们将在本演示文稿的其余部分介绍这方面的示例。图6是我们将使用的简短redis-cli示例:您将看到使用的key命令,而Hydra在内部使用Redis扫描命令。回顾一下,Hydra使用按段组织的键,这使得查询更加容易。此外,一致的组织结构使它们更易于扩展和维护。我们将在下面看到键如何在组织每个微服务的功能中发挥作用。让我们从存在开始。在微服务世界中,能够发现服务并了解它们是否健康和可路由是至关重要的。这些功能取决于了解特定服务实例实际存在并且可供使用。服务发现、路由和负载平衡等功能也需要此功能。每一秒,Hydra都会更新服务密钥的生存时间(TTL)。未能在3秒内更新将导致密钥过期并且主机应用程序被视为不可用。图7在这里我们可以看到使用的Redis命令是“get”和“setex”来设置密钥和到期日期。我们可以使用带有模式匹配的“keys”命令来查询现有的键。请注意,共有三个键。这告诉我们三个“asset-svcs”实例正在运行。如果我们尝试检索其中一个键的内容,我们可以看到它包含实例ID。对这个key使用TTL命令可以显示2秒后过期。图8回顾一下,可以使用自动过期的密钥来管理微服务的存在。Hydra代表托管服务自动更新密钥。这意味着这不是开发人员所做的事情。未能在3秒内更新密钥会导致服务被视为不可用。这可能意味着该服务不健康。这就引出了下一个话题……健康能够监控微服务的健康状况是另一个重要的特性。Hydra每5秒收集并写入一次健康信息快照。您可以查看快照以查看每个服务实例的运行状况。此外,HydraRouter仪表板等监控工具可以使用快照。这就是健康的纽带。请注意,唯一的新内容是“type”段,它标识密钥处于健康状态。图9当我们查看密钥的内容时,我们看到它包含一个字符串化的JSON对象。在这种情况下,它代表“project-svcs”。图10对JSON进行去字符串化可以更轻松地查看存储的内容。这包含很多有用的信息。图11因此,可以存储每个服务实例的健康信息。它使用包含字符串化JSON文本的字符串键进行管理。监视应用程序可以使用此信息。服务发现接下来,考虑服务发现,这是任何微服务架构的另一个必备功能。能够通过名称发现服务的IP和PORT位置大大简化了通信。其他优势包括不必管理DNS条目或创建固定的路由规则。服务发现信息存储在“节点”类型的RedisHash中。使用Hash可以实现快速查询。我们使用Redis的“hget”、“hset”和“hgetall”等命令来处理节点哈希。下面图12中的Redis操作可以用来实现服务发现功能。第一个操作是查询特定的服务类型。第二个操作是查询可用实例。第三个操作允许Hydra检索有关特定服务实例的信息。我们可以看到有用的信息,如服务版本、实例ID、IP地址和端口,最后是主机名。在此示例中,主机名也恰好是Docker容器ID。图13我们可以使用Redis的“hgetall”命令来检索有关所有可用实例的信息。这就是HydraRouter检索服务列表以显示在仪表板上的方式。图14为回顾。使用服务名称键字段查询Hydra以发现有关该服务的各种信息。可以使用RedisHash管理服务详细信息,这提供了极快的服务发现。接下来讨论路由。路由路由HTTP和消息(例如WebSocket或PubSub)需要对路由进行身份验证。微服务可以将路由发布到Redis。例如,HydraRouter使用发布的路由来实现服务感知动态路由。每个服务都在“service:routes”类型的键中发布路由。在这里,我们看到了“asset-svcs”路由的键。图15服务路由存储在Set结构中。这很好,因为您不需要重复的路由条目。使用SADD命令和SMEMBERS命令。顺便说一句,Redis丰富的数据结构集合是我能分享给大家的原因之一。回到路由。我们可以使用键模式来获取路由列表。在这里我们看到许多服务的路线。图16我们可以使用“smembers”命令来查看特定路由集的内容。顺便说一下,括号中的[get]、[post]和[put]部分表示HTTPREST端点。对于其他消息传递技术,可以忽略括号方法的使用。审查。每个服务将其路由发布到Redis集。访问单个路由会显示该服务的路由条目集合。路由使用Set数据结构存储在Redis中,避免路由重复。发布的路由可用于实现服务感知动态路由。接下来我们讨论负载均衡。负载平衡随着应用程序规模的增长,您需要在可用服务实例之间对请求进行负载平衡。这是通过Redis实现的,使用上面描述的服务存在和路由功能。在应用程序级别,使用Hydra,这就像使用“makeAPIRequest”或“sendMessage”调用一样简单。负载平衡发生在这些调用中,因为Hydra使用路由和状态信息来选择可用的目标实例。一个好处是,在路由期间,如果请求在特定实例上失败,Hydra能够在最终收到HTTP503ServerUnavailable错误之前在其他可用实例上重试。如您所见,负载均衡依赖于状态、服务发现和路由等其他功能。图17回顾一下,服务之间的负载平衡请求可以使用我们已经看到的状态、服务发现和路由等功能来完成。Redis字符串、哈希和集合使这成为可能。整体大于部分之和。消息分布式服务被迫通过底层网络相互通信。HTTPRest调用可能是最常见的,但套接字消息传递的效率要高得多。Hydra中的消息传递是使用RedisPub/Sub通道完成的,Redis通过套接字连接实现Pub/Sub。这是一个示例键。Hydra使用Redis命令,例如“订阅”、“取消订阅”和“发布”。图18此外,Hydra路由工具能够通过HTTP和WebSockets接受消息并将它们转换为发布/订阅消息。要了解其工作原理,请考虑两个服务:“asset-svcs”和“project-svcs”。每个服务创建两个密钥,一个是服务名称,另一个是服务名称和实例ID。每个服务监听两个频道。图19在大多数情况下,您不关心服务的哪个实例处理请求。在这种情况下,使用没有特定实例ID的通道。现在,当您需要向特定实例发送消息时,您可以使用带有实例ID的通道。值得注意的是,在进行负载均衡时,hydra会将对服务名称的请求转换为具有特定实例ID的请求。这确保只有一个实例处理特定的消息或请求。我们可以使用Redispub/subchannels命令查看频道键列表。请注意,我们这里有四个键。第一个键是“asset-svcs”的名称,由资产服务的所有实例共享。接下来,我们看到另外三个具有唯一实例ID的键。一个用于三个服务实例中的每一个。图20继续关注消息传递。为了确保微服务之间的互操作性,通用的通信格式必不可少。通用消息格式是一种基于JSON的文档格式,包括对消息传递、路由和队列的支持。这些消息作为JSON字符串化文本存储在Redis中。这是一个示例UMF消息。图21“to”、“frm”和“bdy”等字段是必填项,服务可以在“bdy”对象中自由包含自己的自定义字段。看看这实际上是如何使用的。在左侧,“client-svcs”向“project-svcs”发送消息。请注意,这只需要UMF创建调用和发送消息调用,此处以黄色显示。在右侧,“project-svcs”侦听消息并在必要时处理它们。这是使用事件消息侦听器完成的。请注意,在图22中,Hydra抽象出服务发现、负载平衡、路由和发布/订阅详细信息。发送和接收消息只涉及三个成员函数。这里需要暂停一下。花点时间考虑一下使用您最喜欢的体系结构这个例子会是什么样子。细看。发送消息的机制是解析消息中的“to”字段来确定目标服务名称。有了服务名称,下一步就是检查可用实例。目标实例就位后,消息将被字符串化并通过Redis的“发布”命令发送出去。图23我们再次列出Redis中的所有Pub/Sub通道。消息可以通过这些渠道发送并由听众检索。因此,通过一些编码,我们可以使用Redis通过一组整齐组织的通道来路由消息。图24总之,值得注意的是,消息传递最终是必不可少的,因为服务是物理分布的。Redis使用其发布/订阅功能进行消息传递。标准化通信支持服务之间的互操作性。我们还看到通过抽象服务发现、负载平衡、路由和发布/订阅的底层细节,在应用程序级别进行通信是多么容易。下面讨论消息队列。排队作业和消息队列是许多重要应用程序的另一个重要部分。Hydra使用Redis为每种服务类型维护动态队列。然后服务实例可以读取其队列和进程条目。队列消息的内容是UMF消息,它遵循用于消息传递的相同格式。互操作性也是最重要的!Hydra按服务类型自动创建三个队列。*“已接收”队列*“处理中”队列*“未完成”队列由于这些是列表,我们使用Redis的“lpush”、“rpush”、“rpoplpush”和“lrem”命令。该图显示了队列之间的消息流。队列之间的项目移动是Redis中的原子操作。所以不管你有多少微服务都是安全的。图25在左侧的下一个示例中,排队消息就像创建UMF消息并调用“queueMessage”来发送它一样简单。右下角的代码显示图像处理服务通过调用“getQueuedMessage”使消息出队,然后在处理完消息后调用“markQueueMessage”。这有多容易?图26回顾一下,有时期望立即响应是不现实的。在这种情况下,我们只需要将工作排队等待稍后处理。RedisList数据结构可以用作消息队列。像“lpush”和“rpoplpush”这样以原子方式操作的命令使这成为可能。在这里,我们再次看到使用更高级别的抽象实现基本队列操作是多么容易。日志记录分布式日志记录是任何微服务架构的另一个重要特性。但是,如果您了解Redis,您可能会对将其用作分布式记录器的想法感到惊讶。您可能会担心,这很正常。但是,您可以将它用作飞行记录器。您只存储最严重的错误,并使用“lpush”和“ltrim”来限制条目数。之后,至少你可以快速检查微服务出了什么问题。这就是钥匙的样子。请注意,密钥类型是health:log。图27这里我们看到health:log键类型实际上是一个“列表”数据结构。因此,我们可以使用Redis的“lrange”命令来查看“imageproc-svcs”的飞行记录器日志。图28回顾:微服务在几十台甚至上百台机器上都有日志是不可行的。分布式日志记录绝对是要走的路。使用Redis,您可以构建一个充当飞行记录器的轻量级记录器。使用Redis列表数据结构和方便的“lpush”和“ltrim”命令可以实现这一点。最后说一下配置管理。配置管理管理分布式微服务的配置文件具有挑战性。但是,您甚至可以使用Redis来存储服务的配置文件。这就是我们所做的,当时这似乎是个好主意。然而,我们开始放弃这种做法。由于主要缺点是在Redis中存储配置会使Redis有状态,这不太理想。但它有效,所以我想告诉你。让我们看看它是如何工作的。有一个配置键类型是哈希。此散列具有一个键,该键由服务版本和该版本的配置数据中设置的值组成。图29这是一个示例配置。对于这个例子,我们使用一个名为“hydra-cli”的命令行工具,它允许我们将配置文件推送到特定的服务版本。所有这一切都是为了创建一个哈希条目,该条目的键由服务名称和版本以及作为字符串化值的文件内容组成。请记住,您还可以使用shell脚本来驱动rediscli。我们可以使用配置版本的“hget”命令来拉取特定版本。图30作为简要回顾,我们看到了如何使用Redis来存储应用程序配置文件。RedisHash数据结构允许我们存储每种服务类型的配置。每个配置条目都由服务版本标签索引,内容简单地指向字符串化的JSON配置。不知不觉总结就写了这么多。但总的来说,我在这里分享的是一种使用JavaScript和NodeJS严重依赖Redis的方法。然而,没有什么可以阻止每个人用其他语言做同样的事情。由于Hydra是开源的(https://www.npmjs.com/package/hydra),它可以作为此类工作的参考平台。我很高兴地宣布,我们正在开发受Hydra启发的Golang版本,我们希望尽快将其开源。我们也在考虑开发Java版本。原标题:BuildingLight-weightMicroservicesusingRedis,作者:CarlosJustiniano