文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

聊聊项目实战中的异步设计

2024-11-30 02:01

关注

图片

当你准备寄送一个包裹时,通常你可以有两种寄件方式:

  方案一、你亲自前往快递服务点,填写寄件单、交付包裹、等待工作人员处理,最后得到一张寄送单据。你必须在服务点等待直到所有步骤都完成。这个过程是同步的。

  方案二、你可以选择在线预约快递上门取件服务,填写相关信息后,你的请求就被提交给系统。此时,你可以继续进行其他事情,而不需要等待快递员到达。系统会在后台异步处理你的请求,安排合适的快递员前来取件。这样,你就可以在等待的过程中做其他事情,无需阻塞在快递服务点。

  这种寄件方式提高了效率,让用户可以更加灵活地安排自己的时间。在后台系统中,快递公司可以通过合理的任务调度,处理多个异步请求,提高寄件服务的整体吞吐量。这种方式类似于在后端异步处理任务,而用户无需等待任务完成,可以继续进行其他操作,提高了整个寄件过程的并发性和响应性。这个过程就是异步。

同步和异步

我们通过这个例子抽象出同步模型和异步模型:

图片

小结

同步模型:一个任务做完做下一个任务,阻塞

异步模型:做当前任务,只需要开启而不需要关心另一个任务如何执行,非阻塞

设计理念

  有了上边的模型,对于同步和异步的概念就有了初步的认识。事实上,在架构设计中,异步思想是指通过异步处理来提高系统的性能、可伸缩性和响应速度。

以下是SpringColud微服务架构的基本套件:

图片

在架构设计中,异步思想可以应用在多个方面。常见的异步实践包括:

  1. 消息队列:通过消息队列实现异步通信,将消息发送到队列中,然后由消费者异步地处理这些消息。这种方式可以实现解耦和削峰填谷的效果。
  2. 事件驱动:系统中的各个组件通过事件进行通信,当事件发生时,系统中的其他组件可以异步地响应这些事件,从而实现松耦合和高内聚。
  3. 非阻塞I/O:在网络编程中,采用非阻塞I/O可以使系统在等待I/O操作完成的同时继续处理其他任务,提高系统的并发能力和吞吐量。

......

场景应用

  接下来,我们针对实际项目中的异步设计逐个探究。可能做不到面面俱到,但是可以为真实的场景中的方案设计打开思路。

场景一、基于异步非阻塞模型的业务网关Spring Cloud Gateway

  Spring Cloud Gateway基于Project Reactor反应式编程和WebFlux框架,通过路由、过滤器、事件等机制实现了灵活的网关服务。它适用于构建微服务架构中的业务网关,具有高性能、可扩展性和丰富的功能。

官网地址:https://spring.io/projects/spring-cloud-gateway/

图片

性能比较

  对 Zuul/Spring Cloud Gateway 的一些性能分析可以参考 Spring Cloud Gateway 作者 Spencer Gibb 提供的项目:https://github.com/spencergibb/spring-cloud-gateway-bench。

图片

摘自SpringCloud GateWay作者spencergibb 提供的一个压测报告

  总的来说,Gateway在处理IO密集型请求场景下有着更大的优势。原因是: 随着Spring 5 推出的WebFlux,它是完全异步且非阻塞的,底层也是基于Netty实现的。我们分别对Reactor模型和Netty做一个简单介绍。

  1. 基于Reactor的反应式编程:

图片

  其中:mainReactor主要负责连接处理(不参与数据处理),而subReactor负责数据的读取(不参与连接). 不再是单线程模型那样,接收请求和处理数据都是在一个Reactor下进行。

  1. WebFlux框架:

核心主要是基于NIO的Netty框架,原理说明如下:

组件关系:

图片

概念说明:

每个服务器中都会有一个 Boss(老板),会有一群做事情的WorkerBoss(员工) 会不停地接收新的连接,将连接分配给一个个 Worker 处理连接

执行过程:

图片

Netty 执行过程:

关于SpringCloud GateWay的使用,请自行查阅官网。这里只介绍如何体现NIO异步非阻塞原理的。

场景二、基于消息队列-数据同步

场景分析:

  比如:商城首页菜单树。一般这种场景我们允许在一定时间数据不一致性。那么就可以使用定时任务+消息队列。如每隔5分钟同步一次,达到数据最终一致。

图片

注意事项:

  这种数据同步方案主要适用于数据实时性要求不高的场景,因为:定时任务处理存在一定时间间隔,会有同步延时。同时在时间窗口期数据可能发生变更。还有就是数据最终一致性的保证,主要取决于MQ的可靠性。

场景三、基于消息队列-数据交互

场景分析:

  三方平台交互,上游系统(A)的数据和下游系统(B)的数据进行接口规范转化。此处可能涉及到很多业务转到同一个平台或者不同平台。而我们接口转化的功能是一致的。当然你可以使用Feign直接调用。但是流量增加、网络阻塞时可能会出现调用失败,导致未能成功送达下游。因此我们可以这样设计:

注意事项:

  这种异步设计一方面为了系统内部服务之间解耦,另一方面起到了削峰填谷的作用。但是引入消息队列和转化服务,增加了系统的复杂性。因为链路较长,出现问题时排查起来比较困难。因此要在数据库中尽可能存留记录明细,方便审查。另外,也可能出现消息积压等问题。当然这是消息队列存在的共性问题。

场景四、基于消息队列-短信功能

场景分析:

  日常我们会遇到很多这种发短信的情况。比如,

  1. 手机订购流量套餐,发短信提醒生效日期
  2. 快递达到指定地点,短信同步收件信息
  3. 银行转账成功,提醒交易明细
  4. 上班扫码刷地铁,通知扣费情况
  5. 会员注册满一年,会在前一个月发短信到期提醒。

......

那么对于短信场景,我们如何设计呢?

图片

注意事项:这种异步设计一方面为了将发送短信的功能独立出来。

场景五、基于消息队列-日志采集

场景分析:

  在业务系统中,一般我们会进行日志采集和可视化展示。ELK 是由 Elasticsearch、Logstash 和 Kibana 组成的一套日志管理和分析解决方案。结合 Kafka 使用时,通常用于搭建一个高效的日志处理系统。

图片

ELK 工作流程并结合 Kafka 的工作流程描述:

  1. 生产者发送日志到 Kafka:
  1. Logstash 消费 Kafka 中的日志:
  1. Logstash 处理日志并发送到 Elasticsearch:

  1. Elasticsearch 存储和索引日志数据:

  1. Kibana 可视化和查询:

整个工作流程如下:

+----------------------+       +----------------------+       +----------------------+
|   Producer           | ----> |     Kafka            | ----> |      Logstash         | 
|   (Log Generator)    |       |     (Message Broker) |       |                      |   
+----------------------+       +----------------------+       +----------+-----------+
                                                                               |
                                                                               |
                                                                               v
                                                                     +----------------------+
                                                                     |   Elasticsearch      |
                                                                     |   (Log Storage)       |
                                                                     +----------------------+
                                                                               |
                                                                               |
                                                                               v
                                                                     +----------------------+
                                                                     |        Kibana          |
                                                                     |   (Visualization Tool)|
                                                                     +----------------------+

注意事项:

  整个 ELK + Kafka 的架构可以帮助实现高效的日志收集、处理和可视化,适用于大规模分布式系统中的日志管理。

场景六、基于CompletableFuture 异步多线程批处理任务

  当使用多线程和 CompletableFuture 来执行批处理任务时,可以通过将任务分成多个子任务,并使用 CompletableFuture 来异步执行这些子任务。主要思想如下:

图片

假设我们有一个批处理任务,需要对一组数据进行处理:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

public class BatchProcessingExample {

    public static void main(String[] args) {
        // 模拟一组数据
        List data = generateData(10);

        // 定义线程池
        ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);

        // 将数据分成多个子任务进行处理
        List> futures = new ArrayList<>();
        int batchSize = 3;

        for (int i = 0; i < data.size(); i += batchSize) {
            List batch = data.subList(i, Math.min(i + batchSize, data.size()));

            CompletableFuture future = CompletableFuture.runAsync(() -> {
                // 在这里执行批处理的具体逻辑
                processBatch(batch);
            }, executor);

            futures.add(future);
        }

        // 等待所有子任务完成
        CompletableFuture allOf = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));

        // 在所有子任务完成后关闭线程池
        allOf.thenRun(executor::shutdown);

        try {
            // 等待所有任务完成
            allOf.get();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }

    private static List generateData(int size) {
        List data = new ArrayList<>();
        for (int i = 1; i <= size; i++) {
            data.add(i);
        }
        return data;
    }

    private static void processBatch(List batch) {
        // 模拟批处理逻辑
        for (Integer value : batch) {
            System.out.println(Thread.currentThread().getName() + " - Processing: " + value);
        }
    }
}

  以上我们模拟了一组数据,然后将数据分成多个批次,每个批次使用 CompletableFuture 异步执行。CompletableFuture.allOf 用于等待所有子任务完成。

在这个示例中,主要体现了以下异步的思想和操作:

  1. CompletableFuture 异步执行:使用CompletableFuture.runAsync方法,将任务异步提交给CompletableFuture,该任务会在一个线程池中异步执行。这允许程序继续执行而不必等待子任务完成。
CompletableFuture.runAsync(() -> {
    // 执行异步任务的逻辑
}, executor);
  1. 等待所有异步任务完成:使用CompletableFuture.allOf方法等待所有的子任务完成。这个方法会返回一个新的CompletableFuture,当所有输入的CompletableFuture都完成时,这个新的CompletableFuture也会完成。
CompletableFuture allOf = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
  1. 在所有异步任务完成后执行操作:使用thenRun方法,当所有子任务完成后,执行指定的操作。在这个示例中,用于关闭线程池。
allOf.thenRun(executor::shutdown);

  这些异步操作帮助提高程序的并发性和响应性,特别在处理批量任务时,可以更有效地利用系统资源。异步编程模型能够允许程序在等待某些操作完成的同时继续执行其他操作,从而提高系统的效率。

总结

  异步设计在处理并发和提高系统性能方面具有优势,但也带来了一些可能的问题。以上提供的场景和方案仅供参考。使用过程中应当根据业务特征合理选择具体方案。

优势:

  1. 并发性和响应性: 异步设计可以提高系统的并发性和响应性,允许系统在等待某些操作完成的同时继续执行其他操作,从而更有效地利用资源。
  2. 性能提升: 异步操作允许系统并发地执行多个任务,减少了等待时间,提高了系统的性能。尤其在 I/O 密集型任务中,异步操作能够更充分地利用 CPU。
  3. 可伸缩性: 异步设计有助于构建可伸缩的系统,能够更好地处理大量并发请求,适应系统负载的变化。
  4. 降低资源占用: 异步操作可以减少线程或进程的创建和销毁开销,从而降低系统资源的占用。

可能产生的问题:

  1. 数据一致性: 异步操作可能导致数据一致性的问题,特别是在涉及到多个异步任务的场景。需要采取额外的手段,如事务或事件溯源,来保障数据的一致性。
  2. 幂等性: 异步操作的重试机制可能引入幂等性问题。如果一个操作不是幂等的,重试可能导致不正确的结果。需要确保异步操作是幂等的,或者采用幂等性保障措施。
  3. 消息丢失: 在消息传递的异步系统中,由于网络故障或系统故障,消息可能会丢失。需要实施消息确认、重试和持久化等机制,以防止消息丢失。
  4. 异步调用链的复杂性: 复杂的异步调用链可能使代码难以理解和维护,需要谨慎设计和文档化。
来源:码易有道内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯