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

踢开绊脚石:微服务服务调用难的解决方法

时间:2023-03-21 10:06:48 科技观察

微服务已经成为越来越多企业IT部门的研究对象,并逐渐趋于热门,但作为新兴技术,难免遇到这样或者那样的问题,我们来看看今天微服务的难点之一:服务调用的解决方案。微服务有很多困难,比如分布式系统:本文作者与红帽的顶级战略客户密切合作,帮助他们成功驾驭这些困难的部分,实施服务框架以保持竞争力,并基于创新创造商业价值。非常接近开源社区中技术的快速发展。他们中的大多数人一直在使用过时的方法来解决这些问题,并一直在寻找“如何让开发人员编写能够交付价值的业务逻辑并尝试抽象分布式系统”的解决方案。之前做的是通过抽象的网络和本地接口(CORBA、DCOM、ejb等),让服务调用看起来像本地调用,但后来发现这不是一个好办法,后来改用WSDL/SOAP/代码生成类似的东西可以摆脱这些其他协议的脆弱性,但仍然使用相同的做法(SOAP客户端代码生成),有些人确实让这些协议起作用了,但还有很多不足之处,这里看看什么时候简单一些调用服务时会遇到的问题:错误或延迟重试路由服务发现可观察性错误或延迟当我们向服务发送消息时会发生什么?出于本次讨论的目的,请求被分成小块并通过网络路由传递。因为这个“网络”,我们处理分布式计算的错误思路,应用程序通过异步网络进行通信,这意味着对时间没有单一统一的理解,服务以自己对“时间意义”的理解工作”,这可能不同于其他服务,更重要的是,这些异步网络根据路径的可用性、拥塞、硬件拍手等来路由数据包,不能保证消息会在有限的时间内到达其接收者(注意,这种相同的现象发生在“同步”网络对时间没有统一的理解)。这实际上是非常糟糕的,现在无法确定它是错误的还是太慢了,如果客户要求在票务网站上搜索音乐会,他们不想永远等待响应,在某个时候,请求失败,需要增加服务的超时时间,但不限于增加服务时间。在处理下游请求时,不应该因为Down-Stream网络交互速度而变慢。您应该花一些时间考虑设置:建立到下游服务的链接需要多长时间,以便您可以发送请求并收到回复补充说明:构建system-as-a-的巨大优势服务架构就是速度,包括对系统做改动的速度,重视自主性和系统的频繁部署,但是在做的时候,你会很快发现,在各种奇怪的情况下,加班都做不好。考虑到客户端应用程序设置了3个超时并得到了推荐引擎的响应,但是推荐引擎也咨询了相关引擎,所以它发出了一个设置为2S的超时调用,这应该没有问题,因为仍然有服务调用最多等待3个,但是如果关联引擎必须与提升服务对话怎么办?如果超时设置为5S呢?我们测试的关联引擎(unit,local,integration)似乎通过了所有的测试,甚至在potential操作下,因为超时设置为5S,所以推广服务不会花那么长时间,或者超时后,关联引擎适当地结束调用。当大量调用进入时,您最终会遇到一个麻烦的、难以调试的状态(这可能随时发生,因为网络是“异步的”),超时是一个大问题。重试由于分布式系统中确实没有任何弹性时间保证,当任务耗时过长时需要超时,现在的情况是“超时后怎么办?”不是抛出错误的HTTP5XX吗?接受一些使微服务具有弹性、承诺理论和回调的建议?还是我们重试?如果我们重试,如果调用更改了下游服务的数据会怎样?作者在其他文章中提到,微服务最难的部分之一也是数据端。但更有趣的是,如果下游服务开始失败并最终重试所有请求怎么办?如果具有10个或100个实例的推荐引擎调用关联引擎并且关联引擎超时怎么办?你最终遇到了ThunderingHerdProblem的变体,当尝试修复并缓慢恢复受影响的服务时,即使我们尝试修复并缓慢恢复受影响的服务,这也会结束服务的DDoS。需要注意重试策略。指数重试的回退会有所帮助,但您可能仍会遇到同样的问题。路由因为服务的部署考虑了弹性,所以理想的是在不同的容错区域运行多个实例,这样一些区域可以发生故障而不降低服务的可用性,但是当事件开始发生故障时,需要有一种方法绕过这些故障,但在容错区域,服务路由可能有其他原因。也许某些“区域”被实现为备份服务的地理部署;从延迟的角度来看,在正常操作期间让我们的流量访问备份实例可能太昂贵了。也许您想像这样路由客户端流量,但是服务间通信呢?为了满足客户端请求,服务之间必须进行反向对话,那么路由是如何选择的呢?容错区之剑的一次路由变化可能是路由和负载均衡请求,而这些请求是在可能存在周期性异常服务的情况下发出的。希望能把路由调整到能和服务调用一致的服务上。将流量发送到无法跟上有意义的服务并没有错。在讨论如何部署新版本的服务时,应该考虑更难的问题。如前所述,您希望在服务之间保持一定程度的自治,以便您可以快速迭代和推送更改,并且您不希望破坏依赖的服务,因此,如果可以将某些流量路由到新版本并与构建和发布策略(即蓝/绿、A/B测试、金丝雀发布)相关联,这很快就会变得复杂,如何确定路由?也许正在做的是在一个特殊的“暂存环境”中进行测试,也许只是做一个未宣布的DarkLaunch,也许是A/B测试,但如果有某种状态,数据模式需要考虑Evolution,多版本数据库实现,等等服务发现除了前面讨论的一些弹性注意事项之外,在Expect失败的环境中,您如何发现协作服务?你怎么知道他们在哪里以及你如何与他们沟通?在痛苦的静态拓扑中,应用程序将被配置为需要讨论服务的URL/IP,还将构建这些依赖服务以“永不失败”,但不可避免地,它们会以一些不可接受的方式失败(或部分失败),但在一个有弹性的环境,下游服务可以自动扩展,改装到不同的容错区域,或者简单地被一些自动化系统删除并重新启动,这些服务的客户端需要能够在运行时发现它们并无论如何使用它们拓扑看起来像。这不是一个需要解决的新问题,但在DNS之类的东西不起作用的弹性环境中变得困难(除非在Kubernetes中运行)。相信你自己的服务架构本文把最重要的考虑/问题放在最后,微服务可以快速改变系统架构,如果你不能相信你的系统,那么你会犹豫改造它,这会减慢发布速度,如果部署较慢,将意味着更长的周期时间,导致可能尝试部署的变更更大,团队之间的协调更多,你会觉得“这是我们一贯的态度”,是不是听起来很熟悉?你需要对你的系统有信心,去信任它,可能有基础设施(物理/虚拟/私有云/公有云/混合云/容器)的复杂组合,有大量的中间件、服务、框架,语言和每个服务的部署。如果请求很慢,你从哪里开始?在系统中,需要非常“可观察”的、有用的、有效的Logging、Measurement、Tracking,如果快速迭代发布服务,需要数据驱动,理解变更的影响,回滚的意义,或者快速发布新版本来应对负面影响,系统的各个部分都需要能够提供可靠的可观察性(日志/指标/监控),你越相信这些数据,就越能相信自己的服务架构,而更有信心根据情况做出改进。回顾一下,当一个服务调用其他服务时,需要解决的问题:服务发现自动适配路由/客户端负载均衡自动重试超时控制限速指标/统计数据收集监控A/B测试服务重构/请求跟踪服务Deadline/TimeoutEnforcementforCross-ServiceCallsSecurityServiceEdgeGateway/RouterEnforcedServiceIsolation/OutlierDetectionInternalVersion/DarkStartSolution/Netflix的家伙解决了这个问题,你会看到他们解决的很暴力,基本上说:我们将使用Java/c++/Python,并将无数的工程力量投入到构建库中,以帮助开发人员解决这个问题。“所以Google创建了Stubby,Twitter创建了Finagle,Netflix创建并开源了NetflixOSS,等等,其他所有人都这样做了。但对于其他所有人来说,这种方法存在一个主要问题:你不是这些大公司。投入大量的人力资源来解决这些问题是不切实际的。一些对微服务感兴趣的公司其实是对价值的方向和创新的速度感兴趣,但是他们没有专业的领域知识。也许他们的解决方案可以重复使用?但这也导致了另一个问题:最终,您将得到一个非常复杂的、临时的、部分实现的解决方案。举个例子,笔者与很多做Java店的客户打交道,他们考虑为Java服务解决这个问题。自然会被Netflix的OSS或者SpringCloud吸引,但是NodeJS服务呢?Python服务呢?遗留应用程序呢?Perl脚本呢?每个语言都有自己对这些问题的实现,每个实现的质量都不一样,不是随便抓个开源库塞进应用那么简单,每个都要测试验证需要负责的实现不是这些库,但服务架构和可能的实现扩散/语言/版本很快就会变得难以逾越的复杂性。作者在应用层实现底层网络功能。我喜欢OliverGould提到这些问题(比如路由、重试、限速、断路等)。使这些事情复杂化?一直试图通过创建库(服务发现、跟踪、不同的数据收集、做更复杂的路由等)和干扰应用程序空间(依赖、传递库调用等)来解决这些问题的应用程序,如果服务开发人员忘记添加该实现的一部分(例如跟踪)?因此,每个开发人员都有责任实现这些功能,引入正确的库,将它们写入代码等。更不用说在Java环境中使用注释配置来缓解这些情况的一些框架,信任的目标,这种方法忽略了可观察性、可调试性等。作者更喜欢一种更优雅的方式来做到这一点:恕我直言,如果可以解决这些约束,这就是服务代理/Sidecar模式可以提供帮助的地方:减少任何应用程序级别的感知,如果有的话,到微不足道的库来实现所有这些功能集中在一个地方,而不是分散依赖项的转储区使可观察性成为一流的设计目标使其对包括遗留服务在内的服务透明对任何或所有语言/框架工作的开销/资源影响都非常低堆栈级别(见上文)