B007-springcloud alibaba 消息驱动 Rocketmq

目录

      • MQ简介
        • 什么是MQ
        • MQ的应用场景
          • 异步解耦
          • 流量削峰
        • 常见的MQ产品
      • RocketMQ入门
        • RocketMQ环境搭建
          • 环境准备
          • 安装RocketMQ
          • 启动RocketMQ
          • 测试RocketMQ
          • 关闭RocketMQ
        • RocketMQ的架构及概念
        • RocketMQ控制台安装
      • 消息发送和接收演示
        • 发送消息
        • 接收消息
      • 案例
        • 订单微服务发送消息
        • 用户微服务订阅消息
      • 发送不同类型的消息
        • 普通消息
          • 可靠同步发送
          • 可靠异步发送
          • 单向发送
        • 顺序消息
        • 事务消息?
          • 事务消息交互流程:
          • 事务消息发送步骤:
          • 事务消息回查步骤:
      • 消息消费要注意的细节

MQ简介

什么是MQ

MQ(Message Queue)是一种跨进程的通信机制,用于传递消息。通俗点说,就是一个先进先出的数据结构。
在这里插入图片描述

MQ的应用场景
异步解耦

最常见的一个场景是用户注册后,需要发送注册邮件和短信通知,以告知用户注册成功。传统的做法如下:
在这里插入图片描述
此架构下注册、邮件、短信三个任务全部完成后,才返回注册结果到客户端,用户才能使用账号登录。但是对于用户来说,注册功能实际只需要注册系统存储用户的账户信息后,该用户便可以登录,而后续的注册短信和邮件不是即时需要关注的步骤。

所以实际当数据写入注册系统后,注册系统就可以把其他的操作放入对应的消息队列 MQ 中然后马上返回用户结果,由消息队列 MQ 异步地进行这些操作。架构图如下:
在这里插入图片描述
异步解耦是消息队列 MQ 的主要特点,主要目的是减少请求响应时间和解耦。主要的使用场景就是将比较耗时而且不需要即时(同步)返回结果的操作作为消息放入消息队列。同时,由于使用了消息队列 MQ,只要保证消息格式不变,消息的发送方和接收方并不需要彼此联系,也不需要受对方的影响,即解耦合。

流量削峰

流量削峰也是消息队列 MQ 的常用场景,一般在秒杀或团队抢购(高并发)活动中使用广泛。

在秒杀或团队抢购活动中,由于用户请求量较大,导致流量暴增,秒杀的应用在处理如此大量的访问流量后,下游的通知系统无法承载海量的调用量,甚至会导致系统崩溃等问题而发生漏通知的情况。为解决这些问题,可在应用和下游通知系统之间加入消息队列 MQ。
在这里插入图片描述
秒杀处理流程如下所述:
1.用户发起海量秒杀请求到秒杀业务处理系统。
2.秒杀处理系统按照秒杀处理逻辑将满足秒杀条件的请求发送至消息队列 MQ。
3.下游的通知系统订阅消息队列 MQ 的秒杀相关消息,再将秒杀成功的消息发送到相应用户。
4.用户收到秒杀成功的通知。

常见的MQ产品

目前业界有很多MQ产品,比较出名的有下面这些:

ZeroMQ
号称最快的消息队列系统,尤其针对大吞吐量的需求场景。扩展性好,开发比较灵活,采用C语言实现,实际上只是一个socket库的重新封装,如果做为消息队列使用,需要开发大量的代码。 ZeroMQ仅提供非持久性的队列,也就是说如果down机,数据将会丢失。

RabbitMQ
使用erlang语言开发,性能较好,适合于企业级的开发。但是不利于做二次开发和维护。

ActiveMQ
历史悠久的Apache开源项目。已经在很多产品中得到应用,实现了JMS1.1规范,可以和spring- jms轻松融合,实现了多种协议,支持持久化到数据库,对队列数较多的情况支持不好。

RocketMQ
阿里巴巴的MQ中间件,由java语言开发,性能非常好,能够撑住双十一的大流量,而且使用起来很简单。

Kafka
Kafka是Apache下的一个子项目,是一个高性能跨语言分布式Publish/Subscribe消息队列系统,相对于ActiveMQ是一个非常轻量级的消息系统,除了性能非常好之外,还是一个工作良好的分布式系统。

RocketMQ入门

RocketMQ是阿里巴巴开源的分布式消息中间件,现在是Apache的一个顶级项目。在阿里内部使用非常广泛,已经经过了"双11"这种万亿级的消息流转。

RocketMQ环境搭建

接下来我们先在linux平台下安装一个RocketMQ的服务

环境准备

下载RocketMQ
http://rocketmq.apache.org/release_notes/release-notes-4.4.0

环境要求
Linux 64位操作系统,64bit JDK 1.8+

安装RocketMQ

上传文件到Linux系统的/usr/local/src/目录,解压,移动

unzip rocketmq-all-4.4.0-bin-release.zip
mv rocketmq-all-4.4.0-bin-release /usr/local/rocketmp
启动RocketMQ

进入rocketmq的bin目录

启动NameServer

[root@heima bin]# nohup ./mqnamesrv &
[1] 1467
# 只要进程不报错,就应该是启动成功了,可以查看一下日志
[root@heima bin]# tail -f ~/logs/rocketmqlogs/namesrv.log
# 或查看端口
[root@heima bin]# netstat -an | grep 9876

启动Broker - 先编辑两个文件 vim i esc :wq

[root@heima bin]# vim runserver.sh
JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -Xmn128m -XX:MetaspaceSize=128m ...

[root@heima bin]# vim runbroker.sh
JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -Xmn128m"

[root@heima bin]# nohup ./mqbroker -n localhost:9876 &
测试RocketMQ

1测试消息发送

[root@heima bin]# export NAMESRV_ADDR=localhost:9876
[root@heima bin]# ./tools.sh org.apache.rocketmq.example.quickstart.Producer

2测试消息接收

[root@heima bin]# export NAMESRV_ADDR=localhost:9876
[root@heima bin]# ./tools.sh org.apache.rocketmq.example.quickstart.Consumer
关闭RocketMQ
[root@heima bin]# ./mqshutdown broker
[root@heima bin]# ./mqshutdown namesrv
RocketMQ的架构及概念

在这里插入图片描述
在这里插入图片描述
如上图所示,整体可以分成4个角色,分别是:NameServer,Broker,Producer,Consumer。

Broker(邮递员)
Broker是RocketMQ的核心,负责消息的接收,存储,投递等功能

NameServer(邮局)
消息队列的协调者,Broker向它注册路由信息,同时Producer和Consumer向其获取路由信息

Producer(寄件人)
消息的生产者,需要从NameServer获取Broker信息,然后与Broker建立连接,向Broker发送消息

Consumer(收件人)
消息的消费者,需要从NameServer获取Broker信息,然后与Broker建立连接,从Broker获取消息

Topic(地区)
用来区分不同类型的消息,发送和接收消息前都需要先创建Topic,针对Topic来发送和接收消息

Message Queue(邮件)
为了提高性能和吞吐量,引入了Message Queue,一个Topic可以设置一个或多个Message Queue,这样消息就可以并行往各个Message Queue发送消息,消费者也可以并行的从多个 Message Queue读取消息

Message(邮件内文字)
Message 是消息的载体。

Producer Group
生产者组,简单来说就是多个发送同一类消息的生产者称之为一个生产者组。

Consumer Group
消费者组,消费同一类消息的多个 consumer 实例组成一个消费者组。

RocketMQ控制台安装

1.下载

# 在git上下载下面的工程 rocketmq-console-1.0.0 
https://github.com/apache/rocketmq-externals/releases

2.修改配置文件

# 修改配置文件 rocketmq-console\src\main\resources\application.properties 
server.port=7777 #项目启动后的端口号 
rocketmq.config.namesrvAddr=192.168.109.131:9876 #nameserv的地址,注意防火墙要开启 9876端口

3.打成jar包,并启动

# 进入控制台项目,将工程打成jar包
mvn clean package -Dmaven.test.skip=true # 启动控制台
java -jar target/rocketmq-console-ng-1.0.0.jar

4.访问控制台
在这里插入图片描述

消息发送和接收演示

接下来我们使用Java代码来演示消息的发送和接收

<dependency>
	<groupId>org.apache.rocketmq</groupId>
	<artifactId>rocketmq-spring-boot-starter</artifactId>
	<version>2.0.2</version>
</dependency>
发送消息

消息发送步骤:
1.创建消息生产者, 指定生产者所属的组名
2.指定Nameserver地址
3.启动生产者
4.创建消息对象,指定主题、标签和消息体
5.发送消息
6.关闭生产者

public class RocketMQSendMessageTest {

    public static void main(String[] args) throws Exception {
        //1. 创建消息生产者, 指定生产者所属的组名
        DefaultMQProducer producer = new DefaultMQProducer("myproducer-group");
        //2. 指定Nameserver地址
        producer.setNamesrvAddr("192.168.149.128:9876");
        //3. 启动生产者
        producer.start();
        //4. 创建消息对象,指定主题、标签和消息体
        Message msg = new Message("myTopic", "myTag", ("The RocketMQ Message").getBytes());
        //5. 发送消息 第二个参数代表超时时间
        SendResult sendResult = producer.send(msg,10000);
        System.out.println(sendResult);
        //6. 关闭生产者
        producer.shutdown();
    }
}
接收消息

消息接收步骤:
1.创建消息消费者, 指定消费者所属的组名
2.指定Nameserver地址
3.指定消费者订阅的主题和标签
4.设置回调函数,编写处理消息的方法
5.启动消息消费者

public class RocketMQReceiveMessageTest {

    public static void main(String[] args) throws MQClientException {
        //1. 创建消息消费者, 指定消费者所属的组名
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("myconsumer-group");
        //2. 指定Nameserver地址
        consumer.setNamesrvAddr("192.168.149.128:9876");
        //3. 指定消费者订阅的主题和标签
        consumer.subscribe("myTopic", "*");
        //4. 设置回调函数,编写处理消息的方法
        consumer.registerMessageListener(new MessageListenerConcurrently() {
            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
                System.out.println("Receive New Messages: " + msgs);
                //返回消费状态
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });
        //5. 启动消息消费者
        consumer.start();
        System.out.println("Consumer Started.");
    }
}

案例

接下来我们模拟一种场景: 下单成功之后,向下单用户发送短信。设计图如下:
在这里插入图片描述

订单微服务发送消息

1在shop-order 中添加rocketmq的依赖

    <!--rocketmq-->
    <dependency>
        <groupId>org.apache.rocketmq</groupId>
        <artifactId>rocketmq-spring-boot-starter</artifactId>
        <version>2.0.2</version>
    </dependency>
    <dependency>
    	<groupId>org.apache.rocketmq</groupId>
        <artifactId>rocketmq-client</artifactId>
        <version>4.4.0</version>
    </dependency>

2添加配置

# rocketMQ
rocketmq:
  name-server: 192.168.149.128:9876	#rocketMQ服务的地址
  producer:
    group: shop-order # 生产者组

3编写测试代码

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

        //下单成功之后,将消息放到mq中   向mq中投递一个下单成功的消息
        // 参数一:指定topic
        // 参数二:指定消息体
        rocketMQTemplate.convertAndSend("order-topic", order);

启动两个项目,浏览器访问进行下单发送消息

用户微服务订阅消息

1shop-user 添加依赖

    <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.rocketmq</groupId>
            <artifactId>rocketmq-spring-boot-starter</artifactId>
            <version>2.0.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.rocketmq</groupId>
            <artifactId>rocketmq-client</artifactId>
            <version>4.4.0</version>
        </dependency>

2启动类加注解

@EnableDiscoveryClient

3添加配置

spring:
    cloud:
        nacos:
          discovery:
            server-addr: 127.0.0.1:8848
rocketmq:
  name-server: 192.168.149.128:9876

4编写消息接收服务

@Slf4j
@Service
@RocketMQMessageListener(consumerGroup = "shop-user", topic = "order-topic")
public class SmsService implements RocketMQListener<Order> {
    @Override
    public void onMessage(Order order) {
        log.info("收到一个订单信息{},接下来发送短信", JSON.toJSONString(order));
    }
}

5启动服务,执行下单操作,观看后台输出

发送不同类型的消息

普通消息

RocketMQ提供三种方式来发送普通消息:可靠同步发送、可靠异步发送和单向发送。

可靠同步发送

同步发送是指消息发送方发出数据后,会在收到接收方发回响应之后才发下一个数据包的通讯方式。
此种方式应用场景非常广泛,例如重要通知邮件、报名短信通知、营销短信系统等。

可靠异步发送

异步发送是指发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式。发送方通过回调接口接收服务器响应,并对响应结果进行处理。
异步发送一般用于链路耗时较长,对 RT 响应时间较为敏感的业务场景,例如用户视频上传后通知启动转码服务,转码完成后通知推送转码结果等。

单向发送

单向发送是指发送方只负责发送消息,不等待服务器回应且没有回调函数触发,即只发送请求不等待应答。
适用于某些耗时非常短,但对可靠性要求并不高的场景,例如日志收集。

<!--依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
</dependency>
@RunWith(SpringRunner.class)
@SpringBootTest(classes = OrderApp.class)
public class MessageTypeTest {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    //同步消息
    @Test
    public void testSyncSend() {
        //参数一: topic, 如果想添加tag 可以使用"topic:tag"的写法
        //参数二: 消息内容
        //参数三: 超时时间
        SendResult sendResult =
                rocketMQTemplate.syncSend("test-topic-1", "这是一条同步消息", 10000);
        System.out.println(sendResult);
    }

    //异步消息
    @Test
    public void testAsyncSend() throws InterruptedException {
        //参数一: topic, 如果想添加tag 可以使用"topic:tag"的写法
        //参数二: 消息内容
        //参数三: 回调函数, 处理返回结果
        rocketMQTemplate.asyncSend("test-topic-3", "这是一条异步消息", new SendCallback() {
            //成功响应的回调
            @Override
            public void onSuccess(SendResult sendResult) {
                System.out.println(sendResult);
            }

            //异常响应的回调
            @Override
            public void onException(Throwable throwable) {
                System.out.println(throwable);
            }
        });
        System.out.println("=========================");
        //让线程不要终止
        Thread.sleep(30000);
    }

    //单向消息
    @Test
    public void testOneWay() {
        rocketMQTemplate.sendOneWay("test-topic-2", "这是一条单向消息");
    }
}

三种发送方式的对比
在这里插入图片描述

顺序消息

顺序消息是消息队列提供的一种严格按照顺序来发布和消费的消息类型。
在这里插入图片描述

    //顺序消息
    @Test
    public void testOneWayOrderly() {
        for (int i = 0; i < 10; i++) {
            //第三个参数的作用是用来决定这些消息发送到哪个队列上
            //一个topic默认4个队列,把消息都放到一个队列里保证消费时的顺序
            rocketMQTemplate.sendOneWayOrderly("test-topic-5", "这是一条单向消息","xx");
        }
    }
事务消息?

RocketMQ提供了事务消息,通过事务消息就能达到分布式事务的最终一致。

事务消息交互流程:

在这里插入图片描述
两个概念:

  • 半事务消息:暂不能投递的消息,发送方已经成功地将消息发送到了RocketMQ服务端,但是服务端未收到生产者对该消息的二次确认,此时该消息被标记成“暂不能投递”状态,处于该种状态下的消息即半事务消息。
  • 消息回查:由于网络闪断、生产者应用重启等原因,导致某条事务消息的二次确认丢失, RocketMQ服务端通过扫描发现某条消息长期处于“半事务消息”时,需要主动向消息生产者询问该消息的最终状态(Commit 或是 Rollback),该询问过程即消息回查。
事务消息发送步骤:
  1. 发送方将半事务消息发送至RocketMQ服务端。
  2. RocketMQ服务端将消息持久化之后,向发送方返回Ack确认消息已经发送成功,此时消息为半事务消息。
  3. 发送方开始执行本地事务逻辑。
  4. 发送方根据本地事务执行结果向服务端提交二次确认(Commit 或是 Rollback),服务端收到 Commit 状态则将半事务消息标记为可投递,订阅方最终将收到该消息;服务端收到 Rollback 状态则删除半事务消息,订阅方将不会接受该消息。
事务消息回查步骤:
  1. 在断网或者是应用重启的特殊情况下,上述步骤4提交的二次确认最终未到达服务端,经过固定时间后服务端将对该消息发起消息回查。
  2. 发送方收到消息回查后,需要检查对应消息的本地事务执行的最终结果。
  3. 发送方根据检查得到的本地事务的最终状态再次提交二次确认,服务端仍按照步骤4对半事务消息进行操作。
    OrderController
orderServiceImpl4.createOrderBefore(order);

OrderServiceImpl4

@Service
public class OrderServiceImpl4 {

    @Autowired
    private OrderDao orderDao;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private TxLogDao txLogDao;

    public void createOrderBefore(Order order) {
        String txId = UUID.randomUUID().toString();
        //发送半事务消息
        rocketMQTemplate.sendMessageInTransaction(
                "tx_producer_group",
                "tx_topic",
                MessageBuilder.withPayload(order).setHeader("txId",txId).build(),
                order);
    }

    //本地事务
    @Transactional
    public void createOrder(String txId,Order order){
        //保存订单
        orderDao.save(order);
        //保存事务日志
        TxLog txLog = new TxLog();
        txLog.setTxId(txId);
        txLog.setDate(new Date());
        txLogDao.save(txLog);
    }
}

OrderServiceImpl4Listener

@Service
@RocketMQTransactionListener(txProducerGroup = "tx_producer_group")
public class OrderServiceImpl4Listener implements RocketMQLocalTransactionListener {

    @Autowired
    private OrderServiceImpl4 orderServiceImpl4;
    @Autowired
    private TxLogDao txLogDao;

    //发送半事务消息成功后 执行本地事务
    @Override
    public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
        String txId = (String) msg.getHeaders().get("txId");
        try {
            Order order = (Order) arg;
            orderServiceImpl4.createOrder(txId, order);
            return RocketMQLocalTransactionState.COMMIT;
        } catch (Exception e) {
            return RocketMQLocalTransactionState.ROLLBACK;
        }
    }

    //rocketMQ未收到上面的确认 进行消息回查
    @Override
    public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
        String txId = (String) msg.getHeaders().get("txId");
        TxLog txLog = txLogDao.findById(txId).get();
        if (txLog != null){
            //本地事务(订单)成功了
            return RocketMQLocalTransactionState.COMMIT;
        } else {
            return RocketMQLocalTransactionState.ROLLBACK;
        }
    }
}

消息消费要注意的细节

@RocketMQMessageListener(
	consumerGroup = "shop",//消费者组名 
    topic = "order-topic",//要消费的主题
	consumeMode = ConsumeMode.CONCURRENTLY, //消费模式 指定是否顺序消费 CONCURRENTLY (同步 默认) ORDERLY (顺序)
	messageModel = MessageModel.CLUSTERING, //消息模式 BROADCASTING(广播) CLUSTERING (集群,默认)
)
public class SmsService implements RocketMQListener<Order> {}

RocketMQ支持两种消息模式:
广播消费:每个消费者实例都会收到消息,也就是一条消息可以被每个消费者实例处理;
集群消费:一条消息只能被一个消费者实例消费

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

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

相关文章

盲盒一番赏小程序开发:神秘惊喜,等你来揭晓

在当下潮流文化中&#xff0c;盲盒以其独特的魅力&#xff0c;正逐渐成为一种流行的娱乐方式。为了满足广大盲盒爱好者的需求&#xff0c;我们决定开发一款盲盒一番赏小程序&#xff0c;为用户带来更加便捷、丰富的盲盒体验。 一、小程序简介 盲盒一番赏小程序是一个集盲盒购…

应用测评要求解读-三级

身份鉴别&#xff1a; a)应对登录的用户进行身份标识和鉴别&#xff0c;身份标识具有唯一性&#xff0c;身份鉴别信息具有复杂度要求并定期更换&#xff1b; 1. 在未登录状态下尝试直接访问任意操作页面或功能&#xff0c;查看是否具有登陆界面。 2&#xff0e;询问或者测试…

【算法刷题】Day32

文章目录 1. 单词拆分题干&#xff1a;算法原理&#xff1a;1. 状态表示&#xff1a;2. 状态转移方程3. 初始化4. 填表顺序5. 返回值 代码&#xff1a; 2. 环绕字符串中唯一的子字符串题干&#xff1a;算法原理&#xff1a;1. 状态表示&#xff1a;2. 状态转移方程3. 初始化4. …

关于Ansible的模块 ①

转载说明&#xff1a;如果您喜欢这篇文章并打算转载它&#xff0c;请私信作者取得授权。感谢您喜爱本文&#xff0c;请文明转载&#xff0c;谢谢。 什么是Ansible模块 在Linux中&#xff0c;bash无论是在命令行上执行&#xff0c;还是在bash脚本中&#xff0c;都需要调用cd、l…

MySQL最实用面试题(2024-3-14持续更新中)

MySQL篇面试题 一、介绍 ​ 这是由小龙同学自己总结领悟的mysql面试题的解析&#xff0c;也是面试宝典 二、题目 1.数据库三大范式&#xff1a; –作用&#xff1a; ​ 使表结构清晰&#xff0c;减少数据冗余&#xff08;简单讲就是重复&#xff09;&#xff0c;提高查询…

Stable Diffusion + Segment Anything试用

安装 从continue-revolution/sd-webui-segment-anything安装插件分割模型下载后放到这个位置&#xff1a;${sd-webui}/extension/sd-webui-segment-anything/models/sam下&#xff0c;可以下载3个不同大小的模型&#xff0c;从大到小如下&#xff1a;vit_h is 2.56GB, vit_l i…

test测试类-变量学习

test测试类 作用&#xff1a;标记到类上成为测试类&#xff0c;标记到方法上成为测试方法 变量&#xff1a;测试类的变量&#xff0c;在测试类括号中应用 1、invocationCount变量 意思是这个方法应该被调用的次数。 在测试框架中&#xff0c;特别是当使用参数化测试或数据驱动…

游戏陪玩系统约玩系统交友系统功能介绍

游戏约玩系统是一个集动态社交、语聊交友、线上约玩、线下活动以及购物商城等功能于一体的综合性平台。以下是该系统的功能介绍&#xff1a; 一、首页 热门大神&#xff1a;展示平台上最受欢迎的玩家&#xff0c;方便用户快速找到高水平的游戏伙伴。附近大神&#xff1a;基于…

openGauss学习笔记-246 openGauss性能调优-SQL调优-经验总结:SQL语句改写规则

文章目录 openGauss学习笔记-246 openGauss性能调优-SQL调优-经验总结&#xff1a;SQL语句改写规则246.1 使用union all代替union246.2 join列增加非空过滤条件246.3 not in转not exists246.4 选择hashagg246.5 尝试将函数替换为case语句246.6 避免对索引使用函数或表达式运算2…

Android 系统如何添加开机自启动 Shell 脚本

添加开机自启动 Shell 脚本 很多时候&#xff0c;我们想在系统启动的时候干一些“私活”&#xff0c;这个时候&#xff0c;我们就可以添加开机自启动的脚本来完成。下面我们介绍一个简单的示例&#xff1a; 在 device/Jelly/Rice14 目录下添加如下的文件与文件夹&#xff1a;…

RPC 和 序列化

RPC 1 RPC调用流程 1.1 clerk客户端调用远程服务 Clerk::PutAppend() raftServerRpcUtil::PutAppend() raftServerRpcUtil是client与kvserver通信的入口&#xff0c; 包含kvserver功能的一对一映射&#xff1a;Get/PutAppend&#xff0c;通过stub对象——raftKVRpcProctoc:…

HarmonyOS NEXT应用开发—图片压缩方案

介绍 图片压缩在应用开发中是一个非常常见的需求&#xff0c;特别是在处理用户上传图片时&#xff0c;需要上传指定大小以内的图片。目前图片压缩支持jpeg、webp、png格式。本例中以jpeg图片为例介绍如何通过packing和scale实现图片压缩到目标大小以内。 效果图预览 使用说明…

Catmull-Rom P5 ThreeJs与前端

文章目录 问题Echarts 3D如何让曲线变得平滑&#xff1f;Echarts 2D图中平滑效果是如何实现的&#xff1f;如何在一个Echarts 3D图中画一个圆圈&#xff1f;如何在Echarts 3D图中画一个立方体&#xff1f; Catmull-Rom插值算法先来回答第二个问题回到第一个问题在Echarts 3D图中…

运维安全管理与审计系统(堡垒机)

一、什么是运维安全管理与审计系统 运维安全管理与审计系统&#xff08;俗称 “堡垒机”&#xff09;&#xff1a;是采用新一代智能运维技术框架&#xff0c;基于认证、授权、访问、审计的管理流程设计理念&#xff0c;实现对企事业IT中心的网络设备、数据库、安全设备、主机系…

Zustand极简的状态管理工具

介绍 一个小型、快速且可扩展的 Bearbones 状态管理解决方案。 Zustand 有一个基于 hooks 的舒适 API。它不是样板文件或固执己见&#xff0c;但有足够的惯例来明确和类似通量。 zustand官网 zustand使用方法及调试工具的安装使用 安装包 npm install zustand2.创建store仓…

【Unity投屏总结】投屏方案总结

【背景】 想方便自己在VR中工作&#xff0c;打算做一个能够挂多个屏幕的远程控制VR桌面。研究下来发现细分场景有很多&#xff0c;有点鱼和熊掌不可兼得的意味&#xff0c;细分如下。 【投屏场景与解决方案】 希望多人能够同时观看我的屏幕&#xff0c;也就是一屏投多屏&…

K8s的Pod出现Init:ImagePullBackOff问题的解决,(以calico网络插件为例)

问题描述&#xff1a; 对于这类问题的解决思路应该都差不多&#xff0c;本文以calico插件安装为例&#xff0c;发现有个Pod的镜像没有pull成功 第一步&#xff1a;查看这个pod的描述信息 kubectl describe pod calico-node-t9rql -n kube-system从上图发现是docker拉取"…

实体门店运营方案模板与策划技巧:轻松打造高效运营体系

在当今竞争激烈的商业环境中&#xff0c;实体门店的运营如同一场精密谋划的战役&#xff0c;需要精心策划和高效管理才能在市场中崭露头角。作为经营鲜奶吧5年时间的创业者&#xff0c;我深知成功的实体门店背后离不开一套完善的运营方案和策略。 在这篇文章中&#xff0c;我将…

基于java的宠物信息交流平台设计(含源文件)

随着世界经济信息化、全球化的到来和互联网的飞速发展&#xff0c;推动了各行业的改革。若想达到安全&#xff0c;快捷的目的&#xff0c;就需要拥有信息化的组织和管理模式&#xff0c;建立一套合理、动态的、交互友好的、高效的“多鱼”旧物交易平台。当前的信息管理存在工作…

精酿啤酒:一口啤酒,一份享受

在繁华的都市生活中&#xff0c;我们总是匆匆忙忙&#xff0c;追求着各种目标和成就。然而&#xff0c;在这个过程中&#xff0c;我们往往忽略了生活的本质&#xff0c;那就是享受。而Fendi Club 啤酒&#xff0c;正是为那些追求品质生活的都市精英们量身打造的。 Fendi Club啤…