【谷粒商城之订单服务-RabbitMQ延时队列】

news2024/11/25 23:01:27

本笔记内容为尚硅谷谷粒商城订单服务锁库存事务最终一致性部分

目录

一、RabbitMQ延时队列

二、具体实现

1、 创建上述队列和路由组件

2、解锁库存

解锁库存的两种情况

1、当订单业务提交后回滚

2、订单取消解锁库存

三、关闭订单

四、消息丢失、挤压、重复等解决方案


一、RabbitMQ延时队列


场景:比如未付款订单,超过一定时间后,系统自动取消订单并释放占有物品

常用解决方案:spring的schedule定时任务轮询数据库

缺点:消耗系统内存,增加数据库压力,存在较大的时间误差

解决:RabbitMQ的消息TTL的死信Exchange结合

消息的TTL就是消息的存活时间

RabbitMQ可以对队列和消息分别设置TTL:推荐给队列设置过期时间

  • 对队列设置就是队列没有消费者连着的保留时间,也可以对每个单独的消息做单独的设置,超过了这个时间,我们认为这个消息就死了,称之为死信;
  • 如果队列设置了,消息也设置了,那么会取小的。所以一个消息如果被路由到不同的队列,这个消息死亡的时间有可能不一样(不同队列设置的)

二、具体实现


 

主要流程:
1、库存锁定,将信息压入延时队列中,延时队列是50min,也可以是40min,自定义即可,如果时间到了,就成了死信队列,通过路由key为stock.releace就发送给交换机,再由交换机发送给解锁库存的队列stock.release.stock.queue,然后由库存服务监听这个队列,进行库存解锁
2、订单创建成功后携带路由key=order.create.order发送给交换机,再由交换机发送给延时队列,延时时间为30min,如果时间到了,延时队列就变成了死信队列,进而带路由key=order.release.order发送给交换机,由交换机发送给关闭订单的队列order.release.order.queue,订单服务监听此队列进行关单;这样就完成了30min没有支付就关单的功能

1、 创建上述队列和路由组件

MyRabbitMQConfig.java

package com.atguigu.gulimall.order.config;

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.Exchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;




@Configuration
public class MyRabbitMQConfig {

    /* 容器中的Queue、Exchange、Binding 会自动创建(在RabbitMQ)不存在的情况下 */

    /**
     * 死信队列
     *
     * @return
     */
    @Bean
    public Queue orderDelayQueue() {
        /*
            Queue(String name,  队列名字
            boolean durable,  是否持久化
            boolean exclusive,  是否排他
            boolean autoDelete, 是否自动删除
            Map<String, Object> arguments) 属性
         */
        HashMap<String, Object> arguments = new HashMap<>();
        arguments.put("x-dead-letter-exchange", "order-event-exchange");
        arguments.put("x-dead-letter-routing-key", "order.release.order");
        arguments.put("x-message-ttl", 60000); // 消息过期时间 1分钟
        Queue queue = new Queue("order.delay.queue", true, false, false, arguments);

        return queue;
    }

    /**
     * 普通队列处理订单
     *
     * @return
     */
    @Bean
    public Queue orderReleaseQueue() {

        Queue queue = new Queue("order.release.order.queue", true, false, false);

        return queue;
    }

    /**
     * TopicExchange
     *
     * @return
     */
    @Bean
    public Exchange orderEventExchange() {
        /*
         *   String name,
         *   boolean durable,
         *   boolean autoDelete,
         *   Map<String, Object> arguments
         * */
        return new TopicExchange("order-event-exchange", true, false);

    }


    @Bean
    public Binding orderCreateBinding() {
        /*
         * String destination, 目的地(队列名或者交换机名字)
         * DestinationType destinationType, 目的地类型(Queue、Exhcange)
         * String exchange,
         * String routingKey,
         * Map<String, Object> arguments
         * */
        return new Binding("order.delay.queue",
                Binding.DestinationType.QUEUE,
                "order-event-exchange",
                "order.create.order",
                null);
    }

    @Bean
    public Binding orderReleaseBinding() {

        return new Binding("order.release.order.queue",
                Binding.DestinationType.QUEUE,
                "order-event-exchange",
                "order.release.order",
                null);
    }

    /**
     * 订单释放直接和库存释放进行绑定
     * @return
     */
    @Bean
    public Binding orderReleaseOtherBinding() {

        return new Binding("stock.release.stock.queue",
                Binding.DestinationType.QUEUE,
                "order-event-exchange",
                "order.release.other.#",
                null);
    }
}

2、解锁库存

引入依赖

		<!--amqp高级消息队列协议,rabbitmq实现-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>

主启动类添加注解

配置

spring.rabbitmq.host=192.168.88.130
spring.rabbitmq.port=5672
spring.rabbitmq.virtual-host=/

新建mq组件

MyRabbitConfig.java

package com.atguigu.gulimail.ware.config;

import com.atguigu.gulimail.ware.entity.WareInfoEntity;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class MyRabbitConfig {
    /**
     * 使用JSON序列化机制,进行消息转换
     *
     * @return
     */
    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }

    @Bean
    public Exchange stockEventExchange() {
        return new TopicExchange("stock-event-exchange", true, false);
    }

    @Bean
    public Queue stockReleaseStockQueue() {
        return new Queue("stock.release.stock.queue", true, false, false);
    }

    @Bean
    public Queue stockDelayQueue() {
        Map<String, Object> arguments = new HashMap<>();
        arguments.put("x-dead-letter-exchange", "stock-event-exchange");
        arguments.put("x-dead-letter-routing-key", "stock.release");
        arguments.put("x-message-ttl", 120000);
        return new Queue("stock.delay.queue", true, false, false, arguments);
    }

    @Bean
    public Binding stockLockedBinding() {
        return new Binding("stock.release.stock.queue", Binding.DestinationType.QUEUE, "stock-event-exchange", "stock.release.#", null);
    }

    @Bean
    public Binding stockReleaseBinding() {
        return new Binding("stock.delay.queue", Binding.DestinationType.QUEUE, "stock-event-exchange", "stock.locked", null);
    }

    //第一次监听消息时,idea会连接rabbitMQ,此时才会创建rdbbitMQ中没有的队列、交换机和绑定关系
    //如果需要修改rabbitMQ中已存在的队列交换机,需要先删除,然后再次创建
//    @RabbitListener(queues = "stock.release.stock.queue")
//    public void listener(WareInfoEntity entity, Channel channel, Message msg) throws IOException {
//        System.out.println("收到过期的订单信息:准备关闭订单" + entity.getId());
//        channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
//    }
}

解锁库存的两种情况

  1. 业务失败,订单提交了,但是后续业务处理失败,解锁库存
  2. 订单取消了,解锁库存

写个监听器监听锁定库存时存入锁定库存信息的队列

StockReleaseListener.java

package com.atguigu.gulimall.ware.listener;

import com.rabbitmq.client.Channel;
import com.atguigu.common.to.OrderTo;
import com.atguigu.common.to.mq.StockLockedTo;
import com.atguigu.gulimall.ware.service.WareSkuService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;



@Slf4j
@RabbitListener(queues = "stock.release.stock.queue")
@Service
public class StockReleaseListener {

    @Autowired
    private WareSkuService wareSkuService;

    /**
     * 1、库存自动解锁
     *  下订单成功,库存锁定成功,接下来的业务调用失败,导致订单回滚。之前锁定的库存就要自动解锁
     *
     *  2、订单失败
     *      库存锁定失败
     *
     *   只要解锁库存的消息失败,一定要告诉服务解锁失败
     */
    @RabbitHandler
    public void handleStockLockedRelease(StockLockedTo to, Message message, Channel channel) throws IOException {
        log.info("******收到解锁库存的信息******");
        try {

            //当前消息是否被第二次及以后(重新)派发过来了
            // Boolean redelivered = message.getMessageProperties().getRedelivered();

            //解锁库存
            wareSkuService.unlockStock(to);
            // 手动删除消息
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        } catch (Exception e) {
            // 解锁失败 将消息重新放回队列,让别人消费
            channel.basicReject(message.getMessageProperties().getDeliveryTag(),true);
        }
    }

    @RabbitHandler
    public void handleOrderCloseRelease(OrderTo orderTo, Message message, Channel channel) throws IOException {

        log.info("******收到订单关闭,准备解锁库存的信息******");

        try {
            wareSkuService.unlockStock(orderTo);
            // 手动删除消息
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        } catch (Exception e) {
            // 解锁失败 将消息重新放回队列,让别人消费
            channel.basicReject(message.getMessageProperties().getDeliveryTag(),true);
        }
    }


}

1、当订单业务提交后回滚

WareSkuServiceImpl.java

 @Override
    public void unlockStock(StockLockedTo to) {
        StockDetailTo detail = to.getDetail();
        Long detailId = detail.getId();
        //解锁库存
        //1.查询关于这个订单的锁定库存信息
        WareOrderTaskDetailEntity orderTaskDetailEntity = orderDetailService.getById(detailId);
        if (orderTaskDetailEntity != null) {
            //有,库存锁定成功,根据订单情况解锁
            Long id = to.getId();//库存工作单Id
            WareOrderTaskEntity taskEntity = wareOrderTaskService.getById(id);
            String orderSn = taskEntity.getOrderSn();
            R r = orderFeignService.getOrderStatus(orderSn);
            if (r.getCode() == 0) {
                OrderVo data = r.getData(new TypeReference<OrderVo>() {
                });
                if (data == null || data.getStatus() == 4) {
                    //没有这个订单 或者 有订单但订单状态是已取消,解锁库存
                    //只有状态是1,才能解锁
                    if (orderTaskDetailEntity.getLockStatus() == 1) {
                        unLockStock(detail.getSkuId(), detail.getWareId(), detail.getSkuNum(), detailId);
                    }
                }
            } else {
                //其它状态(包含订单成功)不解锁
                throw new RuntimeException("远程服务失败");
            }
        } else {
            //没有,库存锁定失败,库存回滚,这种情况无需解锁
        }
    }

需要远程查询订单状态再调用解锁方法

远程接口

package com.atguigu.gulimall.ware.feign;

import com.atguigu.common.utils.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;



@FeignClient("gulimall-order")
public interface OrderFeignService {

    @GetMapping(value = "/order/order/status/{orderSn}")
    R getOrderStatus(@PathVariable("orderSn") String orderSn);

}

订单服务下

OrderController.java

    /**
     * 根据订单编号查询订单状态
     * @param orderSn
     * @return
     */
    @GetMapping(value = "/status/{orderSn}")
    public R getOrderStatus(@PathVariable("orderSn") String orderSn) {
        OrderEntity orderEntity = orderService.getOrderByOrderSn(orderSn);
        return R.ok().setData(orderEntity);
    }

OrderServiceImpl.java


    /**
     * 按照订单号获取订单信息
     * @param orderSn
     * @return
     */
    @Override
    public OrderEntity getOrderByOrderSn(String orderSn) {

        OrderEntity orderEntity = this.baseMapper.selectOne(new QueryWrapper<OrderEntity>().eq("order_sn", orderSn));

        return orderEntity;
    }

2、订单取消解锁库存

WareSkuServiceImpl.java

/*
     *防止因为订单服务故障,导致订单状态未改变,从而无法解锁库存
     */
    @Transactional
    @Override
    public void unlockStock(OrderTo orderTo) {
        String orderSn = orderTo.getOrderSn();
        //查询最新库存状态
        WareOrderTaskEntity task = wareOrderTaskService.getOrderTaskByOrderSn(orderSn);
        Long id = task.getId();
        List<WareOrderTaskDetailEntity> list = orderDetailService.list(new QueryWrapper<WareOrderTaskDetailEntity>().eq("task_id", id)
                .eq("lock_status", 1));
        for (WareOrderTaskDetailEntity entity : list) {
            unLockStock(entity.getSkuId(), entity.getWareId(), entity.getSkuNum(), entity.getId());
        }
    }

    public void unLockStock(Long skuId, Long wareId, Integer num, Long taskDetailId) {
        //库存解锁
        wareSkuDao.unlockStock(skuId, wareId, num);
        //更新库存工作单状态
        WareOrderTaskDetailEntity entity = new WareOrderTaskDetailEntity();
        entity.setId(taskDetailId);
        entity.setLockStatus(2);
        orderDetailService.updateById(entity);
    }

wareOrderTaskService.getOrderTaskByOrderSn()

@Override
    public WareOrderTaskEntity getOrderTaskByOrderSn(String orderSn) {
        WareOrderTaskEntity task = this.getOne(new QueryWrapper<WareOrderTaskEntity>().eq("order_sn", orderSn));
        return task;
    }

wareSkuDao.unlockStock(skuId, wareId, num)

 <update id="unlockStock">
        UPDATE `wms_ware_sku` SET stock_locked = IFNULL(stock_locked,0) - #{num}
        WHERE sku_id = #{skuId} AND ware_id = #{wareId}
    </update>

三、关闭订单


回到提交订单的业务,当提交订单时库存锁定成功,给死信队列发消息,开始执行关闭订单的业务,删除购物车数据

OrderServiceImpl.java下的 submitOrder 方法

				if (r.getCode() == 0) {
                    //锁定成功
                    responseVo.setOrder(order.getOrder());
                    // int i = 10/0;

                    //TODO 订单创建成功,发送消息给MQ
                    rabbitTemplate.convertAndSend("order-event-exchange","order.create.order",order.getOrder());

                    //删除购物车里的数据
                    redisTemplate.delete(CART_PREFIX+memberResponseVo.getId());
                    return responseVo;
                } else {
                    //锁定失败
                    String msg = (String) r.get("msg");
                    throw new NoStockException(msg);
                    // responseVo.setCode(3);
                    // return responseVo;
                }

监听普通队列的消息。当普通队列中监听到消息,说明死信队列订单过期,返还给普通队列来处理关闭订单的消息。

OrderCloseListener.java

@Component
@RabbitListener(queues = "order.release.order.queue")
public class OrderCloseListener {
    @Autowired
    OrderService orderService;

    @RabbitHandler
    public void listener(OrderEntity entity, Channel channel, Message msg) throws IOException {
        try {
            System.out.println("收到过期的订单信息:准备关闭订单" + entity.getOrderSn());
            orderService.closeOrder(entity);
            channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            System.out.println("订单关闭异常,库存解锁异常" + e.getMessage());
            channel.basicReject(msg.getMessageProperties().getDeliveryTag(), true);
        }
    }
}

关闭订单、解锁库存
订单关闭时发送消息给库存服务的普通队列,让库存服务解锁库存。

OrderServiceImpl.java

/**
     * 关闭订单
     *
     * @param entity
     */
    @Override
    public void closeOrder(OrderEntity entity) {
        //查询订单最新状态
        OrderEntity orderEntity = this.getById(entity.getId());
        if (orderEntity.getStatus() == OrderStatusEnum.CREATE_NEW.getCode()) {
            //关闭订单
            OrderEntity update = new OrderEntity();
            update.setId(entity.getId());
            update.setStatus(OrderStatusEnum.CANCLED.getCode());
            this.updateById(update);
            OrderTo orderTo = new OrderTo();
            BeanUtils.copyProperties(orderEntity, orderTo);
            try {
                //每一条消息进行日志记录(数据库保存每一条消息的详细信息)
                //定期扫描数据库将失败的消息再发送一遍
                rabbitTemplate.convertAndSend("order-event-exchange", "order.release.other", orderTo);
            } catch (Exception e) {
                //将没法送成功的消息进行重试发送
            }
        }
    }

四、消息丢失、挤压、重复等解决方案


保证消息一定会发送出去,每一个消息都可以做好日志记录 

CREATE TABLE `mq_message` (
`message_id` char(32) NOT NULL,
`content` text,
`to_exchane` varchar(255) DEFAULT NULL,
`routing_key` varchar(255) DEFAULT NULL,
`class_type` varchar(255) DEFAULT NULL,
`message_status` int(1) DEFAULT '0' COMMENT '0-新建 1-已发送 2-错误抵达 3-已抵达',
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`message_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

结束!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

c++ 继承与派生

继承就是在原有类的基础上产生新类&#xff0c;从而减少了代码重复的必要 格式&#xff1a; class A{}; class B:继承方式 A{}; 在c继承中&#xff0c;有以下几点注意 (1)基类的构造函数与析构函数不能被继承 (2)派生类对基类成员的继承没有选择权&#xff0c;不能选择继承…

c++ 常用总结(三)

1.设计模式 GitHub - FengJungle/DesignPattern: Design pattern demo code &#xff08;一&#xff09; ① 简单工厂模式 再不学简单工厂模式&#xff0c;就真的要去工厂搬砖啦~_冯Jungle的博客-CSDN博客 通过以下的例子可见&#xff0c;只需要提供产品名称作为参数&…

基于springboot+mysql+SpringDataJPA +html实现学生选课管理系统

基于springbootmysqlSpringDataJPA html实现学生选课管理系统 一、系统介绍1、系统主要功能&#xff1a;2.涉及技术框架&#xff1a;3.本项目所用环境&#xff1a;4.项目需求 二、功能展示三、其它系统四、获取源码 一、系统介绍 1、系统主要功能&#xff1a; 管理员&#xf…

【C++】| 03——STL | 迭代器

系列文章目录 【C】| 01——泛型编程 | 模板 【C】| 02——STL | 初识 【C】| 03——STL | 迭代器 【C】| 04——STL | 容器_vector 文章目录 1. 什么是迭代器2. 迭代器的分类3. 不同容器对应的迭代器4. 迭代器的好处5. 迭代器的操作 1. 什么是迭代器 迭代器就是指向容器内元素…

基于MATLAB的路面裂缝检测识别算法代码(GUI系统设计+图像预处理+裂缝检测)

资源地址&#xff1a; 基于MATLAB的路面裂缝检测识别算法代码&#xff08;GUI系统设计图像预处理裂缝检测&#xff09;资源-CSDN文库 主要内容&#xff1a; 1、运行Gui_Main.m程序&#xff0c;得到GUI界面 2、首先点击载入图像文件 3、后续便可以点击右侧的其他按钮进行分析…

C++linux高并发服务器项目实践 day10

Clinux高并发服务器项目实践 day10 守护进程进程组会话进程组、会话操作函数守护进程守护进程的创建步骤 线程线程和进程的区别线程之间共享和非共享资源线程操作线程创建线程退出线程参与线程分离线程取消 线程属性 守护进程 在UNIX系统中&#xff0c;用户通过终端登录系统后…

DCMM评估之战略维度沟通

01 数据战略规划过程 过程描述&#xff1a; 过程描述如下:a) 识别利益相关者,明确利益相关者的需求;b) 数据战略需求评估,组织对业务和信息化现状进行评估,了解业务和信息化对数据的需求;c) 数据战略制定,包含但不限于:1) 愿景陈述,其中包含数据管理原则、目的和目标;2) 规划…

SpringCloud 远程调用Feign、网关Gateway、配置中心Nacos、微服务架构小结、Nacos搭建集群

统一检查maven maven依赖出错的解决 注意代码格式化。因代码格式混乱&#xff0c;导致代码出错&#xff0c;pom.xml出现重复的parent标签 学习方法&#xff0c;听得懂为什么要这么做&#xff0c;要远远比 怎么做 重要的多 一、远程调用Feign 能够使用Feign进行远程调用能够…

【C++学习】创建二维动态数组

1.指针 创建二维动态数组_牛客题霸_牛客网 (nowcoder.com) 使用指针的指针 使用指针的指针可以很方便地创建动态的二维数组&#xff0c;其关键在于使用两层指针进行分配。 以下是一个动态创建n行m列的二维数组的示例代码&#xff1a; int **arr new int*[n]; // 创建一个…

深度学习训练营J2:ResNet50v2算法分析与实战

深度学习训练营J2:ResNet50v2算法分析与实战 原文链接环境介绍0.引言论文分析与解读1.ResNet50和ResNet50v2之间的结构对比2.不同结构之间的尝试 3.关于激活的不同尝试4.文章结果 ResNet50v2架构复现5.残差结构6.模块构建7.架构展示以及网络构建 8.网络结构打印ResNet50v2完整结…

Python——1

一、注释 &#xff08;1&#xff09;单行注释&#xff1a;#需要注释的内容&#xff08;#&#xff09; &#xff08;2&#xff09;多行注释&#xff1a;需要注释的内容&#xff08;三引号&#xff09; 二、变量及变量类型 1.变量 语法定义&#xff1a;变量名 变量值&#…

【小程序】微信云托管服务

链接 官方文档 云托管官网 特点 无需自提供服务&#xff0c;有云托管平台自动分配&#xff0c;并自动缩容/扩容支持多种语言及模板实例采用容器化管理方式实现服务部署支持小程序内网访问&#xff0c;仅公网测试&#xff0c;提供足够的安全防护&#xff0c;微信用户就近接入…

Python:BeautifulSoup库介绍

BeautifulSoup库介绍 1、BeautifulSoup是Python中的一个第三方库&#xff0c;其最主要的功能是处理HTML文档 ⑴查找HTML文档中的指定标签 ⑵获取HTML文档中指定标签的标签名、标签值、标签属性等 ⑶修改HTML文档中指定标签 2、BeautifulSoup库将HTML文档解析为一…

服务器如何做端口映射,使服务器之间通信,然后访问目标网站(baidu.com)

文章目录 服务器如何做端口映射&#xff0c;使服务器之间通信&#xff0c;然后访问目标网站&#xff08;baidu.com)问题缘由所需环境操作步骤1. 目的服务器设置2. 中间服务器设置3. 修改客户端 总结 服务器如何做端口映射&#xff0c;使服务器之间通信&#xff0c;然后访问目标…

DataX读取Hive Orc格式表丢失数据处理记录

文章目录 问题问题概述问题详细描述 原因解决方法修改源码验证 问题 问题概述 DataX读取Hive Orc存储格式表数据丢失 问题详细描述 同步Hive表将数据发送到Kafka&#xff0c;Hive表A数据总量如下 SQL&#xff1a;select count(1) from A; 数量&#xff1a;19397281使用Dat…

HTML小游戏25 —— HTML5拉杆子过关小游戏(附完整源码)

本节教程我会带大家使用 HTML 、CSS和 JS 来制作一个HTML5拉杆子过关小游戏 ✨ 前言 &#x1f579;️ 本文已收录于&#x1f396;️100个HTML小游戏专栏&#xff1a;100个H5游戏专栏https://blog.csdn.net/qq_53544522/category_12064846.html&#x1f3ae; 目前已有100小游戏…

交叉编译--build、--host、--target、--prefix

一、编译例子 ./configure --build编译平台 --host运行平台 --target目标平台 [各种编译参数]build&#xff1a;表示目前我们正在运行的平台名称是什么&#xff0c;如&#xff1a;当前我们是在电脑上编译该系统&#xff0c;那么我们的 --build 就可能是 x86&#xff0c;如果…

如何避免因为 Kubernetes 和 Kafka 而被解雇

本文由 Bing AI 生成。Bing AI 真是尽显程序员本色&#xff0c;我等它生成文章的过程中发现出现了 Markdown 语法&#xff0c;结果点复制过来的就是直接 Markdown 文档。 Kubernetes 和 Kafka 是两个非常流行的技术&#xff0c;它们分别用于容器编排和分布式消息传递。它们的优…

XSD2Code++ Crack

XSD2Code Crack XSD2Code是为那些希望在将复杂的XML和JSON模式转换为NetCore时节省时间的开发人员设计的。它使用简单且灵活&#xff0c;可以很容易地集成到任何项目中&#xff0c;并适应开发人员的需求。它通过直观、可定制的用户界面&#xff0c;真正提高了生产力。使用XSD2C…

【SpringCloud】初步认识微服务

文章目录 1.认识微服务1.1微服务由来1.2为什么需要微服务&#xff1f; 2.两种架构2.1.单体架构2.2.分布式架构 3.微服务的特点4.SpringCloud5.总结最后说一句 1.认识微服务 随着互联网行业的发展&#xff0c;对服务的要求也越来越高&#xff0c;服务架构也从单体架构逐渐演变为…