前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >分布式--RabbitMQ集成SpringBoot、消息可靠性、死信队列、延迟交换机、集群

分布式--RabbitMQ集成SpringBoot、消息可靠性、死信队列、延迟交换机、集群

作者头像
aruba
发布于 2022-09-19 07:39:04
发布于 2022-09-19 07:39:04
61500
代码可运行
举报
文章被收录于专栏:android技术android技术
运行总次数:0
代码可运行

接着上篇分布式--RabbitMQ入门

一、SpringBoot中使用RabbitMQ

1. 导入依赖
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
2. yml配置
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
spring:
  rabbitmq:
    host: 192.168.42.4
    port: 5672
    username: aruba
    password: aruba
    virtual-host: /
    listener:
      direct:
        acknowledge-mode: manual # 手动ack
      simple:
        prefetch: 1 # 流控
        concurrency: 10 # 多线程监控
3. 配置交换机和队列
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Configuration
public class RabbitMQConfig {

    public static final String EXCHANGE_NAME = "MY-MQ-EX";
    public static final String QUEUE_NAME = "MY-MQ-QUEUE";
    public static final String ROUTING_KEY = "key.#";

    /**
     * 注入交换机
     *
     * @return
     */
    @Bean
    public Exchange exchangeProvider() {
        return ExchangeBuilder.topicExchange(EXCHANGE_NAME).build();
    }

    /**
     * 注入队列
     *
     * @return
     */
    @Bean
    public Queue queueProvider() {
        return QueueBuilder.durable(QUEUE_NAME).build();
    }

    /**
     * 注入交换机队列绑定关系
     *
     * @return
     */
    @Bean
    public Binding bootBinding(Exchange exchangeProvider, Queue queueProvider) {
        return BindingBuilder.bind(queueProvider).to(exchangeProvider).with(ROUTING_KEY).noargs();
    }
}
4. 发送消息

SpringBoot中使用RabbitTemplate自动注入,即可发送消息,并对方法都进行了封装

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@SpringBootTest
class SpringbootRabbitmqApplicationTests {
    @Autowired
    public RabbitTemplate rabbitTemplate;

    @Test
    void send() {
        rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME, "key.send", "发送消息");
    }

    /**
     * 携带信息的消息
     */
    @Test
    void sendWithProps() {
        rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME,
                "key.send", "发送消息", new MessagePostProcessor() {
                    @Override
                    public Message postProcessMessage(Message message) throws AmqpException {
                        message.getMessageProperties().setCorrelationId(UUID.randomUUID().toString());
                        return message;
                    }
                });
    }
    
}
5. 订阅消息

在方法上使用@RabbitListener注解,即可指定订阅队列。

入参添加Channel,就可以和之前一样发送ack

将消息封装成了Message,可以获取其携带信息。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Component
public class MQListener {

    @RabbitListener(queues = RabbitMQConfig.QUEUE_NAME)
    public void consume(String msg, Channel channel, Message message) throws IOException {
        System.out.println("队列的消息为:" + msg);
        String correlationId = message.getMessageProperties().getCorrelationId();
        System.out.println("唯一标识为:" + correlationId);
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }

}

运行结果:

二、消息可靠性

由于RabbitMQ在发送消息和订阅消息时,都是通过网络传输,其间必然会出现由网络问题产生的消息丢失情况,要保证消息的可靠性从下面四点出发:

  • 保证消息发送到交换机
  • 保证消息路由到队列
  • 保证队列中消息的持久化
  • 保证消费者正常消费消息
1. Client-API方式
1.1 保证消息发送到交换机

Publisher Confirms就是为了保证消息发送到交换机的机制,一般使用异步的方式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        //4. 开启confirm
        channel.confirmSelect();
        channel.addConfirmListener(new ConfirmListener() {
            @Override
            public void handleAck(long deliveryTag, boolean multiple) throws IOException {
                System.out.println("消息成功发送到交换机");
            }

            @Override
            public void handleNack(long deliveryTag, boolean multiple) throws IOException {
                System.out.println("没有送达交换机");
            }
        });
1.2 保证消息路由到队列

addReturnListener方法可以确认消息是否路由到了队列,如果回调了说明没有路由到队列

发送消息时,指定mandatory参数为true

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        //5. 设置return回调,确认消息是否路由到了队列
        channel.addReturnListener(new ReturnListener() {
            @Override
            public void handleReturn(int replyCode, String replyText, String exchange, String routingKey, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("交换机没有路由到队列");
            }
        });

        //参数: 交换机 routing-Key mandatory 消息其他参数  消息
        channel.basicPublish("", QUEUE_NAME, true, null, message.getBytes());
1.3 保证队列中消息的持久化

首先保证队列的持久化,再保证消息的持久化

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        //3. 构建队列  参数:队列名 是否持久化 是否排外(只允许一个消费者) 长时间未使用是否自动删除 其他参数
        channel.queueDeclare(QUEUE_NAME, true, false, false, null);

        //6. 发送消息
        String message = "hello confirm";
        AMQP.BasicProperties porps = new AMQP.BasicProperties().builder()
                .deliveryMode(2) //2:消息持久化 1: 不持久化
                .build();
        //参数: 交换机 routing-Key mandatory 消息其他参数  消息
        channel.basicPublish("", QUEUE_NAME, true, porps, message.getBytes());
1.4 保证消费者正常消费消息

保证消费者正常消费消息只需要手动ack即可,生产者完整代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Publisher {

    private static final String QUEUE_NAME = "confirm";

    @Test
    public void publisher() throws Exception {
        //1. 获取连接对象
        Connection connection = RBConnectionUtil.getConnection();

        //2. 创建信道
        Channel channel = connection.createChannel();

        //3. 构建队列  参数:队列名 是否持久化 是否排外(只允许一个消费者) 长时间未使用是否自动删除 其他参数
        channel.queueDeclare(QUEUE_NAME, true, false, false, null);

        //4. 开启confirm
        channel.confirmSelect();
        channel.addConfirmListener(new ConfirmListener() {
            @Override
            public void handleAck(long deliveryTag, boolean multiple) throws IOException {
                System.out.println("消息成功发送到交换机");
            }

            @Override
            public void handleNack(long deliveryTag, boolean multiple) throws IOException {
                System.out.println("没有送达交换机");
            }
        });

        //5. 设置return回调,确认消息是否路由到了队列
        channel.addReturnListener(new ReturnListener() {
            @Override
            public void handleReturn(int replyCode, String replyText, String exchange, String routingKey, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("交换机没有路由到队列");
            }
        });

        //6. 发送消息
        String message = "hello confirm";
        AMQP.BasicProperties porps = new AMQP.BasicProperties().builder()
                .deliveryMode(2) //2:消息持久化 1: 不持久化
                .build();
        //参数: 交换机 routing-Key mandatory 消息其他参数  消息
        channel.basicPublish("", QUEUE_NAME, true, porps, message.getBytes());
    }

}
2. SpringBoot方式
2.1 配置Confirm

yml中开启confirm

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
spring:
  rabbitmq:
    publisher-confirm-type: correlated

RabbitTemplate设置回调:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                if (ack) {
                    System.out.println("消息成功送达到交换机");
                } else {
                    System.out.println("消息没有送达到交换机");
                }
            }
        });
2.2 配置Return

yml中开启return

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
spring:
  rabbitmq:
    publisher-returns: true

RabbitTemplate设置回调:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {
            @Override
            public void returnedMessage(ReturnedMessage returned) {
                System.out.println(String.format("交换机:%s 路由消息失败", returned.getExchange()));
            }
        });
2.3 消息持久化

设置Message的携带信息:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME,
                "key.send", "发送消息", new MessagePostProcessor() {
                    @Override
                    public Message postProcessMessage(Message message) throws AmqpException {
                        message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                        return message;
                    }
                });

完整代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    /**
     * 携带信息的消息
     */
    @Test
    void sendWithProps() {
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                if (ack) {
                    System.out.println("消息成功送达到交换机");
                } else {
                    System.out.println("消息没有送达到交换机");
                }
            }
        });
        rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {
            @Override
            public void returnedMessage(ReturnedMessage returned) {
                System.out.println(String.format("交换机:%s 路由消息失败", returned.getExchange()));
            }
        });
        rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME,
                "key.send", "发送消息", new MessagePostProcessor() {
                    @Override
                    public Message postProcessMessage(Message message) throws AmqpException {
                        message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                        message.getMessageProperties().setCorrelationId(UUID.randomUUID().toString());
                        return message;
                    }
                });
    }

三、死信队列

死信队列是存放本来应该死亡的消息的队列,用于对这些消息的特殊处理(如:重新入队、持久化到数据库),具体有以下几种消息会被存放进死信队列:

  • 消费者拒绝的消息,并requeue设置为false(不重新入队列)
  • 消息的生存时间到了,还在队列中的信息
  • 队列设置了整体的消息生存时间,到了生存时间的消息
  • 到达队列中消息最大数,再路由过来的消息
1. 构建交换机

死信队列需要一个死信交换机,并把正常消息的队列绑定死信交换机:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Configuration
public class DeadLetterConfig {

    public static final String NORMAL_EXCHANGE_NAME = "normal-ex";
    public static final String NORMAL_QUEUE_NAME = "normal-queue";
    public static final String NORMAL_ROUTING_KEY = "normal.#";

    public static final String DEAD_EXCHANGE_NAME = "dead-ex";
    public static final String DEAD_QUEUE_NAME = "dead-queue";
    public static final String DEAD_ROUTING_KEY = "dead.#";

    @Bean
    public Exchange normalExchange() {
        return ExchangeBuilder.topicExchange(NORMAL_EXCHANGE_NAME).build();
    }

    @Bean
    public Queue normalQueue() {
        // 绑定死信交换机
        return QueueBuilder.durable(NORMAL_QUEUE_NAME)
                .deadLetterExchange(DEAD_EXCHANGE_NAME)
                .deadLetterRoutingKey("dead.msg") //准备入死信队列的消息重新设置routin-key
                .build();
    }

    @Bean
    public Binding normalBinding(Exchange normalExchange, Queue normalQueue) {
        return BindingBuilder.bind(normalQueue).to(normalExchange).with(NORMAL_ROUTING_KEY).noargs();
    }

    @Bean
    public Exchange deadExchange() {
        return ExchangeBuilder.topicExchange(DEAD_EXCHANGE_NAME).build();
    }

    @Bean
    public Queue deadQueue() {
        return QueueBuilder.durable(DEAD_QUEUE_NAME).build();
    }

    @Bean
    public Binding deadBinding(Exchange deadExchange, Queue deadQueue) {
        return BindingBuilder.bind(deadQueue).to(deadExchange).with(DEAD_ROUTING_KEY).noargs();
    }

}
2. 死信队列的实现方式
2.1 拒绝消息入死信队列

对正常队列消息进行监听,来做相应的处理,首先是拒绝消息,并且要把requeue设为false

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Component
public class DeadListener {

    @RabbitListener(queues = DeadLetterConfig.NORMAL_QUEUE_NAME)
    public void normalListener(Message msg, Channel channel) throws IOException {
        System.out.println("接收到正常队列消息:" + new String(msg.getBody()));
        channel.basicReject(msg.getMessageProperties().getDeliveryTag(), false);
//        channel.basicNack(msg.getMessageProperties().getDeliveryTag(), false, false);
    }

}

尝试发送一个消息:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @Test
    public void sendNormal() {
        rabbitTemplate.convertAndSend(DeadLetterConfig.NORMAL_EXCHANGE_NAME, "normal.msg", "哈喽");
    }

运行结果:

2.2 消息生存时间

发送消息时,通过消息的额外参数MessagePropertiessetExpiration方法设置过期时间:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @Test
    public void sendExpire() {
        rabbitTemplate.convertAndSend(DeadLetterConfig.NORMAL_EXCHANGE_NAME,
                "normal.msg", "哈喽",
                new MessagePostProcessor() {
                    @Override
                    public Message postProcessMessage(Message message) throws AmqpException {
                        // 该消息10s后过期
                        message.getMessageProperties().setExpiration("10000");
                        return message;
                    }
                });
    }

记得把上面消息的监听注释掉,否则会消费消息

运行结果:

2.3 队列消息的整体生存时间

管理页面把之前的正常队列删除,在重新创建时,为正常队列设置ttl

设置ttl

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @Bean
    public Queue normalQueue() {
        // 绑定死信交换机
        return QueueBuilder.durable(NORMAL_QUEUE_NAME)
                .ttl(5000) // 整体消息过期时间为5s
                .deadLetterExchange(DEAD_EXCHANGE_NAME)
                .deadLetterRoutingKey("dead.msg") // 准备入死信队列的消息重新设置routin-key
                .build();
    }

发送正常消息,运行结果:

2.4 达到队列最大数

同样先删除正常队列,后调用maxLength为队列设置最大消息数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @Bean
    public Queue normalQueue() {
        // 绑定死信交换机
        return QueueBuilder.durable(NORMAL_QUEUE_NAME)
//                .ttl(5000) // 整体消息过期时间为5s
                .maxLength(1) // 设置消息最大数
                .deadLetterExchange(DEAD_EXCHANGE_NAME)
                .deadLetterRoutingKey("dead.msg") // 准备入死信队列的消息重新设置routin-key
                .build();
    }

发送两次正常消息,运行结果:

四、延迟交换机

死信队列的问题:由于死信队列只会监听队列头的过期时间,一旦队列头的消息过期时间比后面排队的消息过期时间长,那么后面消息的过期时间并不会生效,而是等待队列头的过期时间到了后,才一并进入死信队列

删除正常队列,恢复配置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @Bean
    public Queue normalQueue() {
        // 绑定死信交换机
        return QueueBuilder.durable(NORMAL_QUEUE_NAME)
//                .ttl(5000) // 整体消息过期时间为5s
//                .maxLength(1) // 设置消息最大数
                .deadLetterExchange(DEAD_EXCHANGE_NAME)
                .deadLetterRoutingKey("dead.msg") // 准备入死信队列的消息重新设置routin-key
                .build();
    }

发送两次消息,第一次过期时间为30s,第二次为2s:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @Test
    public void sendExpire30() {
        rabbitTemplate.convertAndSend(DeadLetterConfig.NORMAL_EXCHANGE_NAME,
                "normal.msg", "哈喽",
                new MessagePostProcessor() {
                    @Override
                    public Message postProcessMessage(Message message) throws AmqpException {
                        message.getMessageProperties().setExpiration("30000");
                        return message;
                    }
                });
    }

    @Test
    public void sendExpire2() {
        rabbitTemplate.convertAndSend(DeadLetterConfig.NORMAL_EXCHANGE_NAME,
                "normal.msg", "哈喽",
                new MessagePostProcessor() {
                    @Override
                    public Message postProcessMessage(Message message) throws AmqpException {
                        message.getMessageProperties().setExpiration("2000");
                        return message;
                    }
                });
    }

结果,过了几秒后,队列中还是两个消息:

解决方法:根据时间创建多个队列或者使用延迟交换机

延迟交换机是一个插件,默认并不带,原理就是将消息暂时放在交换机中,由交换机根据消息过期时间的先后来路由到队列,缺点:由于消息在交换机中,重启会导致消息的丢失

1. 插件下载和使用

根据自己的RabbitMQ版本进行下载:https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases/

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
wget https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases/download/3.8.17/rabbitmq_delayed_message_exchange-3.8.17.8f537ac.ez
mv rabbitmq_delayed_message_exchange-3.8.17.8f537ac.ez /usr/local/rabbitmq/rabbitmq_server-3.8.35/plugins

启动插件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
cd /usr/local/rabbitmq/rabbitmq_server-3.8.35/sbin
./rabbitmq-plugins enable rabbitmq_delayed_message_exchange

重启服务或系统后,多了一个x-delayed-message的交换机类型:

2. 配置延迟交换机

使用CustomExchange构造x-delayed-message类型交换机,并使用其他参数x-delayed-type指定使用哪种原型交换机类型,这边使用的是topic

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Configuration
public class DelayExchangeConfig {

    public static final String EXCHANGE_NAME = "delay-exchange";
    public static final String DELAY_QUEUE = "delay_queue";
    public static final String DELAY_ROUTIN_KEY = "delay.#";

    @Bean
    public Exchange delayExchange() {
        Map<String, Object> args = new HashMap<>();
        // 使用哪种原型交换机类型
        args.put("x-delayed-type", "topic");
        Exchange exchange = new CustomExchange(EXCHANGE_NAME, "x-delayed-message", true, false, args);
        return exchange;
    }

    @Bean
    public Queue delayQueue() {
        return QueueBuilder.durable(DELAY_QUEUE).build();
    }


    @Bean
    public Binding delayBinding(Queue delayQueue, Exchange delayExchange) {
        return BindingBuilder.bind(delayQueue).to(delayExchange).with(DELAY_ROUTIN_KEY).noargs();
    }
    
}
3. 发送消息

MessageProperties使用setDelay方法为消息设置延迟:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @Test
    public void sendDelay30() {
        rabbitTemplate.convertAndSend(DelayExchangeConfig.EXCHANGE_NAME,
                "delay.msg", "哈喽",
                new MessagePostProcessor() {
                    @Override
                    public Message postProcessMessage(Message message) throws AmqpException {
                        message.getMessageProperties().setDelay(30000);
                        return message;
                    }
                });
    }

    @Test
    public void sendDelay5() {
        rabbitTemplate.convertAndSend(DelayExchangeConfig.EXCHANGE_NAME,
                "delay.msg", "哈喽",
                new MessagePostProcessor() {
                    @Override
                    public Message postProcessMessage(Message message) throws AmqpException {
                        message.getMessageProperties().setDelay(5000);
                        return message;
                    }
                });
    }

消息在交换机进行等待后,首先入队列的为5秒延迟的,后面入队列的为30秒延迟的:

五、集群

1. 配置主机名

RabbitMQ集群的搭建要配置主机名:HOSTNAME,先修改network配置文件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
vi /etc/sysconfig/network

追加HOSTNAME:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
HOSTNAME=rabbit1

再修改hosts文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
vi /etc/hosts

追加内容:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
192.168.42.4 rabbit1

重启系统后,RabbitMQ先前配置的管理账号会丢失,需要重新配置

2. 克隆虚拟机
2.1 从机主机名配置

克隆后,对从机进行主机名的配置,network配置文件:

hosts文件,中需要添加集群主节点的ip和hostname:

2.2 建立集群关联

启动RabbitMQ服务后,管理界面的节点会带上主机名:

接下来,配置从机加入到主节点集群中,执行以下命令即可:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
cd /usr/local/rabbitmq/rabbitmq_server-3.8.35/sbin/ 
./rabbitmqctl stop_app
./rabbitmqctl reset 
./rabbitmqctl join_cluster rabbit@rabbit1
./rabbitmqctl start_app

加入成功后,管理界面中就会出现多个节点:

3. 配置镜像模式

目前集群是普通模式,队列中的消息只会存在于一个节点上,而不会同步到其他队列,一旦该节点宕机,其他节点将无法访问消息。

镜像模式是指,集群中所有节点都有一份单独的拷贝,即使单一节点宕机,其他节点中依然存在消息的拷贝,这样才能实现高可用

在管理界面进行配置镜像策略:

新建一个队列,并查看详情:

项目地址:

https://gitee.com/aruba/rabbit-mqstudy.git

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-07-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
谷歌宣布支持使用Rust开发Chromium
谷歌计划在其开源浏览器项目 Chromium 中支持使用第三方 Rust 库,这是对 Rust 编程语言及其安全特性的一次重大认可。
深度学习与Python
2023/03/01
6700
谷歌宣布支持使用Rust开发Chromium
【2023 Week-2】Rust视界周刊 | Google 官宣在 Chromium 项目中支持使用 Rust
Rust 1.66.1 修复了 Cargo 在使用 SSH 克隆依赖项或注册表索引时不验证 SSH 主机密钥的问题。此安全漏洞被跟踪为 CVE-2022-46176[1]。所有包含 1.66.1 之前的 Cargo 的 Rust 版本都容易受到攻击。
张汉东
2023/03/06
1.6K0
【2023 Week-2】Rust视界周刊   | Google 官宣在 Chromium 项目中支持使用 Rust
谷歌“宠爱”升级,Rust 大步跨入 Android 平台
作者|褚杏娟、万佳、王强 “很高兴看到 Rust 在越来越多的项目中发挥作用。” 近日,谷歌宣布 Android 开源项目(AOSP)现已支持使用 Rust 编程语言来开发 OS。这一举动让正火的 Rust 语言热度再次上涨。 要用 Rust 解决什么问题? 目前,Android 项目主要用两种语言构建。Java(以及最近出现的与 jvm 兼容的语言,如 Kotlin) 已被用于操作系统的上层部分,如 UI 部分;在内核、驱动程序等 OS 的基础层面,则通常用 C 编写,有时也会使用 C++。 为了更适合
深度学习与Python
2023/04/01
1.8K0
谷歌“宠爱”升级,Rust 大步跨入 Android 平台
Android 平台基础支持转向 Rust(zdnet)
2021 年 4 月 7 日,zdnet 发布文章:Android 平台基础支持转向 Rust。2021 年 4 月 6 日,谷歌宣布,Rust 可以在 Android 开源项目内部使用。
niqin.com
2022/06/30
4790
Android 平台基础支持转向 Rust(zdnet)
【五万言】Rust 2022 生态版图调研报告(上)
去年我写了 2021 年 Rust 生态版图调研报告 | 星辰大海(上)[1] 和 (下)[2] ,大家能看到 Rust 在各个行业领域中开始暂露头角。2022 年,在政治动荡、经济下行和疫情肆虐的世界大环境下,Rust 却迎来了高质量的发展。2022 年,我愿称之为 Rust 发展元年。
张汉东
2023/03/06
1.2K0
【五万言】Rust 2022 生态版图调研报告(上)
Android 团队宣布 Android 开源项目(AOSP),已支持 Rust 语言来开发 Android 系统本身
Android 平台中,代码的正确性,是每个版本 Android 系统的安全性、稳定性,及其质量的重中之重。C/C++ 语言中的内存安全漏洞,仍然是最难解决的错误来源。我们投入了大量的精力和资源来检测、修复和缓解这类 bug,这些努力有效地防止了大量 bug 进入 Android 系统。然而,尽管做出了这些努力,内存安全漏洞仍然是稳定性问题的主要原因。并且,在 Android 系统高严重性的安全漏洞中,其始终占据大约 70% 的比例。
niqin.com
2022/06/30
1.8K0
Android 团队宣布 Android 开源项目(AOSP),已支持 Rust 语言来开发 Android 系统本身
抛弃 C / C++!微软官宣:请用 Rust 编写 Windows 驱动!
在这众多大厂之中,微软对于 Rust 的重视与支持力度也一直未减。继 5 月效仿 Linux 用 Rust 重写部分 Windows 内核后,近来微软在拥抱 Rust 上又进了一步:微软在 GitHub 中发布了一系列开发工具包,让开发者可以使用 Rust 语言来编写 Windows 驱动程序。
C语言与CPP编程
2023/10/09
7200
抛弃 C / C++!微软官宣:请用 Rust 编写 Windows 驱动!
RUST 编程语言使构建更安全的软件变得更加容易。RUST ALL THE THINGS 需要什么?
给各位分享一篇关于GitHub上的rust风格的开发人员如何可以使开发更加安全的博客,我已经帮大家翻译了
人不走空
2024/05/11
1210
RUST 编程语言使构建更安全的软件变得更加容易。RUST ALL THE THINGS 需要什么?
「快讯」Android 加入了对 Rust 语言的支持
Android 平台中代码的正确性是每一个 Android 版本安全性、稳定性和质量的重中之重。C 和 C++ 中的内存安全漏洞仍然是最难解决的不正确性原因。我们投入了大量的人力和物力来检测、修复和缓解这类 bug,这些努力有效 ¢¢ 地防止了大量的 bug 混入 Android 发行版中。然而,尽管做出了这些努力,内存安全漏洞仍然是造成稳定性问题的首要因素,并且一直占到 Android 高严重性安全漏洞的 70% 左右。
用户1250838
2021/05/31
9590
「快讯」Android 加入了对 Rust 语言的支持
呼吁停用 C/C++,微软 Azure CTO 更青睐 Rust
9 月 20 日,微软 Azure 现任 CTO、Sysinternals 主要开发者 Mark Russinovich 在其个人推特账号发表动态称是时候停止使用 C/C++启动任何新项目,并建议在需要使用 noc-GC 语言的场景下使用 Rust 编程语言。 Rust 由 Graydon Hoare 设计,而后在 Mozilla 成型,Rust 设计时借鉴了许多 C++ 的设计思想如并发特性等,也以高性能著称,还实现了内存安全。2015 年 Rust 作为 C/C++ 的替代品开始引起人们的关注,正因如此
IT大咖说
2022/09/27
7330
呼吁停用 C/C++,微软 Azure CTO 更青睐 Rust
Rust 语言风靡学术界
AWS 将 Rust 编译器团队负责人收入麾下的新闻让开发者们再次聚焦于这门兼具安全性与高性能的编程语言。近日,著名科学期刊 Nature 刊登了一篇文章,表明 Rust 语言也正在成为学术界最受欢迎的编程语言之一。
章鱼猫先生
2021/10/15
6040
Rust 语言风靡学术界
Mozilla将会在Firefox 48版本中引入Rust Component
Mozilla近日宣布,将会在Firefox的正式版中首次引入Rust代码。而该版本(Firefox 48)将于在2016年8月2日发布。 Rust是一种可以更为安全地替代C++的编程语言,因为其独特架构架构,能降低基于Rust的应用中内存泄漏的风险。 内存泄漏问题(例如释放后重利用、缓存溢出等)是最近安全漏洞的根源。不止是Adobe Flash Player,Firefox和Chrome等浏览器也深受其害。 因为自身特性的需要,七年前Mozilla决定赞助这个项目,并最终将其作为自己的编程语言。 Fire
CSDN技术头条
2018/02/12
8540
造就 Rust 的无名英雄
看到社区有朋友对 Brain 这篇文章已经做了翻译,但是出于对 Rust 发展背后付出的无名英雄的敬意,我又认真翻译了一遍。这篇翻译得到了 Brian 本人的授权。
张汉东
2021/05/11
7070
造就 Rust 的无名英雄
什么是Rust语言?探索安全系统编程的未来
在本篇博客中,我们将全面深入探讨Rust语言——一种革命性的系统编程语言,旨在提供内存安全、并发性支持和高性能操作。通过详尽的历史背景、发展史、技术意义及其解决的核心问题分析,本文将带您详细了解Rust语言的优势和应用场景。文章特别适合编程新手和资深开发者阅读,涵盖了丰富的代码示例和操作命令,助您从理论到实践全方位掌握Rust。关键词包括:Rust编程、系统编程、内存安全、并发编程、Rust历史和发展、Rust应用实例。
猫头虎
2024/04/20
6870
【Rust日报】2022-02-12 Amazon:Rust的可持续性
Rust 是一种作为开源项目实现的编程语言。它结合了 C 等系统编程语言的性能和资源效率与 Java 等语言的内存安全性。Rust 于 2010 年作为 Mozilla 的一个研究项目开始,Rust 1.0 于 2015 年推出。2020 年,对 Rust 的支持从 Mozilla 转移到 Rust 基金会,这是一个由 Amazon Web Services, Inc (AWS) 、谷歌、华为、微软和 Mozilla 合作创建的非营利组织。基金会的使命是支持 Rust 的成长和创新,成员公司从创始的 5 家公司发展到第一年的 27 家公司。
MikeLoveRust
2022/03/24
2970
Facebook 是如何引入并使用 Rust 的?
Facebook 正在拥抱当今最受欢迎 、发展最快的一门编程语言——Rust。当前,Facebook 除了为公司内部的 Rust 团队引进人才,还正式加入了 Rust 基金会,与 Mozilla(Rust 的创造者)、AWS、微软和谷歌等其他成员一起,致力于维持和发展 Rust 的开源生态系统。
MikeLoveRust
2021/07/16
8120
Facebook 是如何引入并使用 Rust 的?
C和C++不安全?谷歌宣布Android加入对Rust语言支持
机器之心报道 机器之心编辑部 Rust 越来越流行,开始跨入 Android 领域。谷歌宣布 AOSP (Android Open Source Project) 现已支持使用 Rust 开发 Android 操作系统。 Android 系统涉及很多组件,开发者会根据正在开发的 Android 部分而选择不同的编程语言。对于应用开发者来说,Java 和 Kotlin 是比较流行的选择;而对于从事操作系统以及内部底层的开发人员来说,C 和 C++ 是比较好的选择。 近日,谷歌为操作系统开发者增加了第 3 个
机器之心
2023/03/29
6270
C和C++不安全?谷歌宣布Android加入对Rust语言支持
Docker 之父:Go、Rust 为什么会成为云原生的主导语言?
作者 | Justin Cormack 译者 | 核子可乐 审校 | 褚杏娟 Docker 公司 CTO Justin Cormack 在 InfoQ 的会议上与 Docker 公司创始人、Docker 之父 Solomon Hykes、Vitess 联合创始人 Sougoumarane 、Krustlet 主要作者 Matt Butcher 等人一起探讨了等各大云原生项目在最开始为何选择了 Go 和 Rust 语言,并对云原生项目如何选择编程语言提出了几点建议。我们将本次大咖们的对话进行了编译
深度学习与Python
2023/03/29
7310
Docker 之父:Go、Rust 为什么会成为云原生的主导语言?
Android 支持 Rust 编程语言,以避免内存缺陷(thehackernews)
谷歌周二(2021-04-06)宣布,其开源版本的 Android 操作系统,将增加对 Rust 编程语言的支持,以防止内存安全漏洞。
niqin.com
2022/06/30
1.5K0
Android 支持 Rust 编程语言,以避免内存缺陷(thehackernews)
Linux 基金会要接管 Chromium 了吗?
纵观浏览器的发展历程,有三个重要节点。第一个节点是网景公司成立,发布第一款商用浏览器 Netscape Navigator,拉开互联网走向大众的序幕。第二个节点是微软 IE 击败 Netscape Navigator,成为浏览器的新霸主,然后不思进取,拖慢了 Web 发展的进程。第三个节点是谷歌 Chrome 浏览器崛起,甚至微软也不得不屈服,放弃自家的浏览器引擎,基于 Chromium,开发新一代浏览器 Edge。
云水木石
2025/01/23
460
Linux 基金会要接管 Chromium 了吗?
推荐阅读
相关推荐
谷歌宣布支持使用Rust开发Chromium
更多 >
目录
  • 一、SpringBoot中使用RabbitMQ
    • 1. 导入依赖
    • 2. yml配置
    • 3. 配置交换机和队列
    • 4. 发送消息
    • 5. 订阅消息
  • 二、消息可靠性
    • 1. Client-API方式
      • 1.1 保证消息发送到交换机
      • 1.2 保证消息路由到队列
      • 1.3 保证队列中消息的持久化
      • 1.4 保证消费者正常消费消息
    • 2. SpringBoot方式
      • 2.1 配置Confirm
      • 2.2 配置Return
      • 2.3 消息持久化
  • 三、死信队列
    • 1. 构建交换机
    • 2. 死信队列的实现方式
      • 2.1 拒绝消息入死信队列
      • 2.2 消息生存时间
      • 2.3 队列消息的整体生存时间
      • 2.4 达到队列最大数
  • 四、延迟交换机
    • 1. 插件下载和使用
    • 2. 配置延迟交换机
    • 3. 发送消息
  • 五、集群
    • 1. 配置主机名
    • 2. 克隆虚拟机
      • 2.1 从机主机名配置
      • 2.2 建立集群关联
    • 3. 配置镜像模式
    • 项目地址:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档