OJ在线评测系统 微服务 用分布式消息队列 RabbitMQ 解耦判题服务和题目服务 手搓交换机和队列 实现项目异步化

消息队列解耦 项目异步化

分布式消息队列

分布式消息队列是一种用于异步通信的系统,它允许不同的应用程序或服务之间传递消息。消息队列的核心理念是将消息存储在一个队列中,发送方可以将消息发送到队列,而接收方则可以在适当的时候从队列中读取消息。这种机制有助于解耦应用程序,提高系统的可扩展性和可靠性。

主要特点:

  1. 异步通信:发送方和接收方可以在不同的时间工作,不必直接交互。

  2. 负载均衡:通过将消息分发到多个消费者,可以有效利用系统资源。

  3. 消息持久化:许多消息队列系统支持将消息存储在磁盘上,以防数据丢失。

  4. 顺序处理:某些队列支持按顺序处理消息,确保消息的处理顺序。

  5. 容错性:分布式架构增强了系统的容错能力,可以在部分组件故障时继续工作。

常见的分布式消息队列系统:

  • Apache Kafka:高吞吐量、可扩展的消息队列,常用于大数据处理。

  • RabbitMQ:支持多种消息协议,易于使用,适合复杂的路由场景。

  • ActiveMQ:功能丰富,支持多种编程语言和消息协议。

分布式消息队列在微服务架构、事件驱动架构等场景中广泛应用,可以有效提高系统的灵活性和可维护性。

我们就用RabbitMQ去改造项目 解耦判题服务 题目服务

题目服务只需要向消息队列中发信息

判题服务从消息队列中取消息去执行判题

然后异步更新数据库即可

我们的题目服务和判题服务需要引入rabbitMQ

先引入消息队列的Java客户端

先引入依赖 amqp的客户端

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>

配置一下

  rabbitmq:
    host: localhost
    port: 5672
    password: guest
    username: guest

我们要创建交换机和队列

先启动生产者 的消息队列

package com.yupi.yuojbackendjudgeservice.rabbitmq;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import lombok.extern.slf4j.Slf4j;

/**
 * 用于创建测试程序用到的交换机和队列(只用在程序启动前执行一次)
 */
@Slf4j
public class InitRabbitMq {

    public static void doInit() {
        try {
            ConnectionFactory factory = new ConnectionFactory();
            factory.setHost("localhost");
            Connection connection = factory.newConnection();
            
            // 创建交换机 用于发 收信息
            Channel channel = connection.createChannel();
            String EXCHANGE_NAME = "code_exchange";
            channel.exchangeDeclare(EXCHANGE_NAME, "direct");

            // 创建队列 随机分配一个队列名称
            String queueName = "code_queue";
            channel.queueDeclare(queueName, true, false, false, null);
            channel.queueBind(queueName, EXCHANGE_NAME, "my_routingKey");
            log.info("消息队列启动成功");
        } catch (Exception e) {
            log.error("消息队列启动失败");
        }
    }

    public static void main(String[] args) {
        doInit();
    }
}

在启动类里面可以看见

package com.yupi.yuojbackendjudgeservice;

import com.yupi.yuojbackendjudgeservice.rabbitmq.InitRabbitMq;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
@ComponentScan("com.yupi")
@EnableDiscoveryClient
@EnableFeignClients(basePackages = {"com.yupi.yuojbackendserviceclient.service"})
public class YuojBackendJudgeServiceApplication {

    public static void main(String[] args) {
        // 初始化消息队列,先注释掉,改用 Bean 的方式初始化消息队列(InitRabbitMqBean.java)
//        InitRabbitMq.doInit();
        SpringApplication.run(YuojBackendJudgeServiceApplication.class, args);
    }

}

接下来要把生产者的消息扔到交换机里面

package com.yupi.yuojbackendquestionservice.rabbitmq;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component
public class MyMessageProducer {

    @Resource
    private RabbitTemplate rabbitTemplate;

    /**
     * 发送消息
     * @param exchange
     * @param routingKey
     * @param message
     */
    public void sendMessage(String exchange, String routingKey, String message) {
        rabbitTemplate.convertAndSend(exchange, routingKey, message);
    }

}

写一个接收消息的代码

package com.yupi.yuojbackendjudgeservice.rabbitmq;

import com.rabbitmq.client.Channel;
import com.yupi.yuojbackendjudgeservice.judge.JudgeService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component
@Slf4j
public class MyMessageConsumer {

    @Resource
    private JudgeService judgeService;

    // 指定程序监听的消息队列和确认机制
    @SneakyThrows
    @RabbitListener(queues = {"code_queue"}, ackMode = "MANUAL")
    public void receiveMessage(String message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {
        log.info("receiveMessage message = {}", message);
        long questionSubmitId = Long.parseLong(message);
        try {
            judgeService.doJudge(questionSubmitId);
            channel.basicAck(deliveryTag, false);
        } catch (Exception e) {
            channel.basicNack(deliveryTag, false, false);
        }
    }

}

要传递的消息

是什么

传递的数据

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/888103.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

安卓如何实现双击触摸唤醒点亮屏幕功能-Android framework实战开发

背景 经常有学员朋友在群里问到一个目前市场上常见的功能&#xff1a; 手机待机时候双击屏幕可以唤醒点亮手机屏幕功能 如何实现这个功能&#xff0c;经常有同学在群里求助&#xff0c;今天就刚好来讨论一下这个待机时候双击触摸唤醒点亮屏幕的功能的实现方案。 功能核心方案设…

【微服务】服务注册与发现 - Eureka(day3)

CAP理论 P是分区容错性。简单来说&#xff0c;分区容错性表示分布式服务中一个节点挂掉了&#xff0c;并不影响其他节点对外提供服务。也就是一台服务器出错了&#xff0c;仍然可以对外进行响应&#xff0c;不会因为某一台服务器出错而导致所有的请求都无法响应。综上所述&…

dwceqos网络驱动性能优化

文章介绍 本文会分享一些在QNX系统下对io-pkt-v6-hc驱动模块cpu loading过高问题优化的经验&#xff0c;以及一些调优debug的方法。这些优化措施实施之后可以降低io-pkt-v6-hc在高负载的情况下的cpu loading。本文的调优是基于synopsys公司的dwceqos模块&#xff0c;理论上方法…

【Android 源码分析】Activity生命周期之onPause

忽然有一天&#xff0c;我想要做一件事&#xff1a;去代码中去验证那些曾经被“灌输”的理论。                                                                                  – 服装…

【STM32 HAL库】MPU6050 DMP库移植 与 自检失败的处理

【STM32 HAL库】MPU6050 DMP库移植 与 自检失败的处理 本文参考移植步骤文件配置代码修改inv_mpu.cinv_mpu.hinv_mpu_dmp_motion_driver.c 使用 自检失败怎么处理ret -1改正DEBUG过程 ret -9改正DEBUG过程 本文参考 B站 CSDN 移植步骤 文件配置 新建一个 dmp 文件夹 并将…

【Linux】进程地址空间、环境变量:从理论到实践(三)

&#x1f308; 个人主页&#xff1a;Zfox_ &#x1f525; 系列专栏&#xff1a;Linux 目录 &#x1f680; 前言一&#xff1a;&#x1f525; 环境变量 &#x1f95d; 基本概念&#x1f95d; 常见环境变量&#x1f95d; 查看环境变量方法 二&#xff1a;&#x1f525; 测试 &…

Nat. Commun.:飞秒激光书写受蚂蚁启发的可重构微型机器人集体

背景介绍生物在各种环境中的集体行为十分普遍&#xff0c;它们能够自发有序地完成单个个体难以完成的任务。目前&#xff0c;生物集体的形成主要分为两大类。第一类生物个体之间没有直接接触&#xff0c;如蜜蜂、鱼和鸟类&#xff0c;这导致这些集体不稳定&#xff0c;容易受到…

Linux网络编程 -- 网络基础

本文主要介绍网络的一些基础概念&#xff0c;不涉及具体的操作原理&#xff0c;旨在构建对网络的基础认识。 1、网络的早期发展历程 20世纪50年代 在这一时期&#xff0c;计算机主机非常昂贵&#xff0c;而通信线路和设备相对便宜。为了共享计算机主机资源和进行信息的综合处…

基于图像的3D动物重建与生成

一、背景与目标 3D-Fauna 是一款用于基于图像和视频进行四足动物3D重建与生成的开源方案。自然界展示了复杂的相似性与多样性,该方法通过学习来自网上图片的四足动物的3D形态,能够从单张图片生成可动画化的带有纹理的3D网格模型。其最终目标是通过大量扩展现有的解决方案,实…

数据库(MySQL):使用命令从零开始在Navicat创建一个数据库及其数据表(一).创建基础表

一. 使用工具和命令 1.1 使用的工具 Navicat Premium 17 &#xff1a;“Navicat”是一套可创建多个连接的数据库管理工具。 MySQL版本8.0.39 。 1.2 使用的命令 Navicat中使用的命令 命令命令解释SHOW DATABASES&#xff1b;展示所有的数据库CREATE DATABASE 数据库名称; 创…

基于STM32的数字温度传感器设计与实现

引言 STM32 是由意法半导体&#xff08;STMicroelectronics&#xff09;开发的基于 ARM Cortex-M 内核的微控制器系列&#xff0c;以其强大的处理能力、丰富的外设接口和低功耗著称&#xff0c;广泛应用于嵌入式系统设计中。在这篇文章中&#xff0c;我们将介绍如何基于 STM32…

深度学习:基于MindSpore实现ResNet50中药分拣

ResNet基本介绍 ResNet&#xff08;Residual Network&#xff09;是一种深度神经网络架构&#xff0c;由微软研究院的Kaiming He等人在2015年提出&#xff0c;并且在ILSVRC 2015竞赛中取得了很好的成绩。ResNet主要解决了随着网络深度增加而出现的退化问题&#xff0c;即当网络…

数据结构与算法——动态规划算法简析

1.初步了解动态规划 由于本篇博客属于动态规划的初阶学习&#xff0c;所以大多都是简单的表示&#xff0c;更深层次的学术用语会在之后深度学习动态规划之后出现&#xff0c;本文主要是带各位了解一下动态规划的大致框架 1.1状态表示 通常的我们会开辟一个dp数组来存储需要表示…

015 品牌关联分类

文章目录 后端CategoryBrandEntity.javaCategoryBrandController.javaCategoryBrandServiceImpl.javaCategoryServiceImpl.javaBrandServiceImpl.java删除 npm install pubsub-jsnpm install --save pubsub-js这个错误是由于在尝试安装 pubsub-js 时&#xff0c;npm 发现了项目…

数据结构(栈和队列的实现)

1. 栈&#xff08;Stack&#xff09; 1.1 栈的概念与结构 栈是一种特殊的线性表&#xff0c;其只允许固定的一段插入和删除操作&#xff1b;进行数据插入和删除的一段叫做栈顶&#xff0c;另一端叫栈底&#xff1b;栈中的元素符合后进先出LIFO&#xff08;Last In First Out&…

C++——模拟实现vector

1.查看vector的源代码 2.模拟实现迭代器 #pragma oncenamespace jxy {//模板尽量不要分离编译template <class T>class vector{public:typedef T* iterator;//typedef会受到访问限定符的限制typedef const T* const_iterator;//const迭代器是指向的对象不能修改&#xf…

透明物体的投射和接收阴影

1、让透明度测试Shader投射阴影 &#xff08;1&#xff09;同样我们使用FallBack的形式投射阴影&#xff0c;但是需要注意的是&#xff0c;FallBack的内容为&#xff1a;Transparent / Cutout / VertexLit&#xff0c;该默认Shader中会把裁剪后的物体深度信息写入到 阴影映射纹…

毕业设计_基于springboot+ssm+bootstrap的旅游管理系统【源码+SQL+教程+可运行】【41001】.zip

毕业设计_基于springbootssmbootstrap的旅游管理系统【源码SQL教程可运行】【41001】.zip 下载地址&#xff1a; https://download.csdn.net/download/qq_24428851/89828190 管理系统 url: http://localhost:8080/managerLoginPageuser: admin password: 123 用户门户网站…

【设计模式-解释模式】

定义 解释器模式是一种行为设计模式&#xff0c;用于定义一种语言的文法&#xff0c;并提供一个解释器来处理该语言的句子。它通过为每个语法规则定义一个类&#xff0c;使得可以将复杂的表达式逐步解析和求值。这种模式适用于需要解析和执行语法规则的场景。 UML图 组成角色…

SPDK从安装到运行hello_world示例程序

SPDK从安装到运行示例程序 #mermaid-svg-dwdwvhrJiTcgTkVf {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-dwdwvhrJiTcgTkVf .error-icon{fill:#552222;}#mermaid-svg-dwdwvhrJiTcgTkVf .error-text{fill:#552222;s…