当前位置: 首页 > 网络应用技术

完整的原则和实践

时间:2023-03-08 10:24:29 网络应用技术

  Java 8提供了完整的图。这是实现异步的工具类。起步很难并且具有强大的功能。它支持通过功能编程为各种操作的合并安排。Meituan收购商人API。我希望帮助或激发参与相关发展的学生。

  随着订单数量的继续增加,Meituan Take -Out系统服务的压力也在增加。作为外卖链接的核心链接,商人提供了一系列核心功能,例如接收订单和分销和分销,以及系统吞吐量的要求越来越高。商家API服务是流入入口。所有商家的侧面流量将被安排和汇总,以向外部的商人提供功能界面,以及每个下游服务的内部调度以获取数据。包装)功能。随着当前的每日订单量表达到1000万个关卡,使用同步加载方法已经逐渐出现,因此我们开始考虑将同步加载更改为并行加载的可行性。

  外卖商人API服务是典型的I/O强度类型(I/O BOUND)服务。此外,Meituan外卖商人的交易业务有两个相对较大的特征:

  在如此大的流量链接下,以确保商人的用户体验,确保界面的高性能并从下游获得数据,这是不可避免的。

  并行从下游获取数据,并将其分为同步模型和异步模型。

  每种服务中最常见的信息是同时调用,如下图所示:

  在同步调用的情况下,接口消耗很长,性能很差,接口响应持续时间t> t1+t2+t3+...+tn。目前,为了缩短接口的响应时间,线程池的数据通常并行使用。订单卡的组装使用此方法。

  由于以下两个原因,资源利用率相对较低:

  在同步模型下,它将导致硬件资源不可用,系统吞吐量将很容易到达瓶颈。

  我们主要使用以下两种方法来减少线程池的开销和阻塞时间:

  我们首先对行业流行解决方案进行了横向调查,主要包括未来,完整的注释2,RXJAVA和反应堆。其特征的特征如下:

  组合(组合)?????1AsynChronousStrong,它们提供了更多功能调用以支持更多功能,但它们也带来了更高的学习成本。这次我们需要的最需要的功能是“异步”和“组合”。在全面考虑之后,我们选择学习相对较低的完整图。

  3.1.1 Java 8引入了Java8,在Java8之前,我们通常在未来实现异步。

  以下将表明,我们可以通过可听图和完整形式实现异步差异。避免使用STEP1,STEP2,Step3的三个操作,存在依赖关系关系,STEP3的执行取决于STEP1和Step2的结果。

  Future(listableFuture)实现(回调地狱)如下:

  完整形式的实施如下:

  显然,完整未来的实施更简洁,更好地阅读。

  3.1.2完整形式的定义

  完整形式实现了两个接口(如上图所示):未来,完整阶段。FUTURE代表异步计算的结果。完成阶段用于在异步执行过程中表示一个步骤(阶段)。此步骤可能是由另一个完成者触发的。随着当前步骤的完成,也可以触发其他系列的称赞。完整阶段接口定义了此功能。我们可以通过结合当时的,thencose和其他功能编程方法提供的功能编程方法来结合这些步骤。

  让我们解释一下如何通过示例使用完整的未图。使用完整的未来也是建造依赖树的过程。完整图的完成将触发另一个依赖其完整图的执行:

  如上图所示,这是业务界面的一个过程,包括5个步骤,包括CF1CF2CF3CF4CF5,并描述了这些步骤之间的依赖关系。每个步骤都可以是RPC调用,数据库操作或局部区域。用户呼叫等。当使用完整的future时,图中的每个步骤都会生成一个完整的future对象,最终结果将由一个复杂的布莱。

  根据可完成的依赖性的数量,可以将其分为以下类别:零依赖性,一个 - 美元依赖性,二进制依赖性和多元化依赖性。

  3.2.1零依赖性:创建完整的future,让我们首先看看如何创建一个新的完整形式,而无需依赖其他完整的future:

  如上上面的红色链接所示,接口接收请求后,首先启动两个异步调用CF1和CF2。有三个主要方法:

  第三种方法的典型用途方案之一是将回调方法转换为完整future,然后依靠完整版的呼叫和安排能力。示例如下:

  3.2.2一个元的依赖性:依赖CF

  如上上面的红色链接所示,CF3和CF5分别取决于CF1和CF2。可以通过当时,随后的thencompose的方法来实现对单个完整未来的这种依赖性。

  3.2.3双重依赖性:对两个CF的依赖性

  如上上面的红色链接所示,CF4同时取决于两个CF1和CF2。这种双重依赖性可以通过调整终结的调整来实现,如以下代码所示:

  3.2.4不同的依赖性:对多个CF的依赖性

  如上上面的红色链接所示,整个过程的末尾取决于三个步骤CF3,CF4和CF5。可以通过或方法实现这种多样化的依赖性。在完成后可以使用其中一个,如以下代码所示:

  完整的图包含两个字段:结果和堆栈。用于存储当前CF的结果。堆栈(完成)表示需要在当前CF完成后需要触发的因动作(依赖项),以触发以Treiber堆栈形式存储的取决于其CF.CF的计算,堆栈表示顶部。堆栈的元素。

  该方法类似于“观察者模型”,而依赖的动作动作被封装在单独的完成子类中。BELOW是完成的结构结构图。完整图中的EAVEAD方法对应于图中完成的子类。完成本身是观察者的基类。

  3.3.1完整的图的设计思想基于类似于“观察者模型”的设计思想。对原理的分析可以从“观察者”和“观察者”的两个方面开始。所有类型的回调。如下所示:

  3.3.1.1观察者

  3.3.1.2观察者

  完整的future支持许多回调方法,例如TheAccept,然后进行,异常,异常等。这些方法接收函数类型F,生成一个生成完整类型FN的对象(IE观察者),并将输入函数f分配给成员变量FN FN FN FN FN FN FN FN然后检查当前CF是否已经处于状态(即结果!= null)。如果直接触发FN,否则将添加到CF观察者链中并重试。执行完成后的通知触发器。

  3.3.2总体过程3.3.2.1一个元依赖性

  这仍然是一美元依赖性的过程:然后以示例为例:

  初步过程设计如上图所示。这里有几个有关注册和通知的问题。您可以考虑一下:

  问题1:在观察者注册之前,如果已执行CF并已发出通知,则不会因为错过通知而不会触发观察者?A1:NO.检查CF依赖项在注册期间是否已完成。如果是未完成(即结果== null),观察者输入到堆栈中。

  Q2:在“输入堆栈”之前,将会有“结果== null”判断。这两个操作是非原子操作,并且实现完整的FUFURE并未锁定这两个操作。这两个操作之间的完成时间。观察者仍然无法通知,是否仍然不可能触发?

  A2:不。进入堆栈后,请检查CF是否再次完成,如果完成,则将触发。

  Q3:依靠多个CF时,观察者将被压入所有依赖的CF堆栈中,并且在完成每个CF时将执行每个CF。它会导致多次执行操作吗?如下图所示,当CF1和CF2同时完成时,如何避免CF3多次触发。

  A3:完整未来的实现是解决此问题:观察者将在执行前通过CAS操作设置状态位,并将状态从0设置为1。如果执行观察者,则CAS操作将失败,并且执行将被取消。

  通过分析以上三个问题,可以看出,当完整的图处理并行问题时,整个过程中都没有锁定操作,从而大大提高了程序的实施效率。我们考虑合并并行问题后,我们可以完成一个完整总体流程图如下所示:

  完整的图支持回调方法非常丰富,但是由于上一章中提到的上一章的总体流程图,它们的整体过程是一致的。所有回调的重复用途都在同一一组过程体系结构中使用,并且通过不同的恢复主管通过策略模型。

  3.3.2.2二元依赖性

  我们以终结者为例来解释二进制依赖性:

  骨b的操作表明两个完整的未图。观察者实现类是双式的。如上图所示,Biapply取决于SRC和SND属性依赖的两个CF。fn属性的类型是双链接。与单个依赖关系不同,在依赖项的未完成的CF的情况下,Thencombine将尝试将Biapply压入这两个CF堆栈中。每个依赖的CF将尝试触发观察者的biapply.biapply将检查两个依赖项是否已完成。在解决重复触发器的问题的顺序中,同样的用途也是上一章中提到的CAS操作。执行后,状态位将通过CAS设置,以避免重复触发器。

  3.3.2.3多样化的依赖性

  依赖多个可完成的future的回调方法包括,不同的是观察者实现类是birelay,并且所有依赖的CF都需要执行回调。TRIGGER.TRIGGER.TRIGGER。两者的实现是构建许多依赖的CFS,这些CFS依赖于平衡的二进制树,并逐图通知执行结果,直到触发根节点以返回监督为止。

  3.3.3本章的摘要是实施完整目的原则的科学普及,该原则旨在不粘贴源代码,而是通过结构图,流程图和文本描述来告诉完整未图的实施原理。“整体过程”一章流程图的来源,并结合了并发处理的逻辑,以促进每个人的理解。

  在异步API的过程中,我们遇到了一些问题。其中一些问题将更加隐藏。以下内容是从这些问题的处理经验中排除的。希望帮助更多的同学,您可以踩更少的位置。

  4.1.1在代码上执行哪个线程?为了合理地控制线程资源,最基本的先决条件是清楚地知道编写代码时将执行哪个线程。LET查看完整future的执行线程。

  完整的图将实现完成阶段接口。通过大量回调方法,它支持各种合并的操作。每个组合场景都有两种方法:同步和异步。

  有两种同步方法的情况(即没有异步后缀)。

  异步方法(即带有异步后缀的方法):您可以选择是否传递在指定的线程池中运行的线程池参数执行器;当执行人未通过时,forkjoinpool中的公共线程池(普通池的大小为CPU核编号-1。如果是IO密集的应用,则线程数可能会成为瓶颈)。

  例如:

  4.2.1应该在线程池前面引入异步回调,异步回调方法可以选择是否传递线程池参数执行程序。在这里,我们建议根据实际情况进行强制性通过池和隔离线池。

  当不通过线程池时,您将使用forkjoinpool commonpool中的公共线程池。这里的所有调用将共享线程池,核心线程的数量=处理器1的数量(单核核心线程的数量为1)。公共池,核心和非核心业务在同一线程中竞争同一池可以轻松成为系统瓶颈。线程池参数的手动传输可以更方便地调整参数,并可以将不同的线程池分配给不同的业务,以便过时资源并减少不同业务之间的相互干扰。

  4.2.2线程池周期参考将导致死锁

  如上面的代码块所示,Doget方法的第三行请求通过SupplyAsync从ThreadPool1进行线程,并且内部任务从ThreadPool1.threadPool1中请求线程的大小为10。当同时达到10个请求时,ThreadPool1已满,并且子任务请求输入阻止队列。无法完成父亲的任务。主线程执行CF1.JOIN()进入阻止状态,无法恢复。

  为了修复此问题,需要使用子任务来隔离线程池。两个任务请求不同的线程池,以避免循环依赖性引起的阻塞。

  4.2.3异步RPC调用注释请勿在IO线程池服务的异步RPC调用之后阻止异步RPC调用的结果。目前,您需要注意启用to IT是由IO线程设置的,即,回调方法是由IO线程触发的,并且完整的Future同步(例如异步后缀,例如当时的Appapply,ThenAccept).on。顶部,整个服务只有一个IO线程池。目前,有必要确保没有时间累积的逻辑,例如同步回报中的阻塞。

  4.3.1由于异步执行任务而引起的异常处理,在其他线程上执行,异常信息存储存储在线程堆栈中。因此,当前线程无法通过TryCatch捕获异常,除非它被阻止并等待返回。

  需要注意的是,回调方法中的可完整的包装异常。大多数异常将被封装在完整的exception中并将其扔掉。真正的异常存储在原因属性中。因此,如果调用了回调方法,则需要真正的异常来使用throwable.getcause()方法。但是,在某些情况下,将直接返回实际异常(堆栈溢出的讨论)。最好使用工具类提取异常,如以下代码所示:

  上面的代码使用自定义工具类异常用于完整的提取。当使用彻底的future进行异步编程时,该工具类可用于处理异常。实现代码如下:

  4.3.2在实践过程中引入工具方法的引入,我们促进了一些通用工具方法。您可以在使用完整的未来开发时直接使用它。有关详细信息,请参见“附录”。

  通过异步转换,Meituan Merchant -Side API系统的性能得到了显着改善,与转换之前相比的好处如下:

  注意1:“增加同步”是指商客户端和服务器之间的顺序增量数据同步协议。客户使用该协议获得带有新订单和状态变化的订单。

  注2:本文中涉及的所有技术点的Java版本均为JDK 8,并且由完整future支持的特征分析也基于此版本。

  长发,Xu Meng和Xiang Peng都来自Meituan外卖商人小组的技术团队。

  Meituan外卖商人服务的技术团队将通过技术手段为数百万的商人提供服务,涵盖客户,合同,商品,交易,增长和其他业务方向,以建立商家 - 末端系统,同时提高数字运营水平餐饮和外卖商人帮助Meituan集体建立大量供应,以为用户提供更丰富和多样化的选择性。

  Meituan外卖商人系统既有在数百万日订单的命令和B端独有的企业的复杂性下面临的稳定挑战。它也是创新的,并在商人生态学,商人操作,智能硬件和其他方向的方向上进行了探索。通过以高可用性,现场驱动设计和微服务等技术方向进行连续实践,我们积累了丰富的技术经验。

  欢迎加入Meituan外卖商人集团的技术团队。有兴趣的学生可以将简历发送到pingxumeng@meituan.com

  阅读更多技术文章收藏的Meituan技术团队

  前端|算法|数据|安全|操作和维护|ios |Android |测试

  |在公共帐户菜单列对话框[2021商品],[2020 CARGO],[2019年商品],[2018年商品],[2017年商品]和其他关键字,您可以多年来查看Meituan技术团队的技术文章收集。

  |本文由Meituan技术团队制作,其版权属于Meituan。WELCOME重印或将本文内容用于非商业目的,例如共享和交流。请指出“内容是从Meituan技术团队复制的”。本文不允许未经许可转载或使用它。对于任何商业行为,请发送电子邮件至tech@meituan.com申请授权。

  原始:https://juejin.cn/post/7098727514725416967