针对Rokcetmq引入的缺点提供相应解决方案

news2024/12/23 5:37:16

1.针对Rokcermq引入可用性降低问题
Rocketmq实现高可用模式,Rocketmq有三种模式:单机模式、主从模式、分片集群模式。
单机模式
单机模式,就是 Demo 级别的,一般就是你本地启动了玩玩儿的,没人生产用单机模式。
docker-compose.yml

version: '3'
services:
    namesrv:
      image: foxiswho/rocketmq:4.8.0
      container_name: rmqnamesrver
      ports:
        - "9876:9876"
      environment:
        JAVA_OPT_EXT: "-Xms512M -Xmx512M -Xmn128m"
      command: sh mqnamesrv
    broker:
      image: foxiswho/rocketmq:4.8.0
      container_name: rmqbroker
      ports:
        - "10911:10911"
      environment:
        NAMESERV_ADDR: "127.0.0.1:9876"
        JAVA_OPT_EXT: "-Xms512M -Xmx512M -Xmn128m"
      volumes:
        - ./logs:/home/rocketmq/logs
        - ./store:/home/rocketmq/store
        - ./conf/broker.conf:/home/rocketmq/rocketmq-4.8.0/conf/broker.conf
      command: sh mqbroker -n namesrv:9876 -c /home/rocketmq/rocketmq-4.8.0/conf/broker.conf
      depends_on:
        - namesrv
    mqconsole:
      image: styletang/rocketmq-console-ng
      container_name: rmqconsole
      ports:
        - "10100:8080"
      environment:
        JAVA_OPTS: -Drocketmq.config.namesrvAddr=namesrv:9876 -Drocketmq.config.isVIPChannel=false
      depends_on:
        - namesrv

优点:本地开发测试,配置简单,同步刷盘消息一条都不会丢
缺点:不可靠,如果宕机,会导致服务不可用
主从模式:(可动态增加主从节点:如多主多从)
docker-compose.yml文件

version: '3'
services:
    namesrv:
      image: foxiswho/rocketmq:4.8.0
      container_name: rmqnamesrver
      ports:
        - "9876:9876"
      environment:
        JAVA_OPT_EXT: "-Xms512M -Xmx512M -Xmn128m"
      command: sh mqnamesrv
    broker-a:
      image: foxiswho/rocketmq:4.8.0
      container_name: rmqbroker-a
      ports:
        - "10911:10911"
        - "10912:10912"
      environment:
        NAMESERV_ADDR: "127.0.0.1:9876"
        JAVA_OPT_EXT: "-Xms128M -Xmx128M -Xmn128m"
      volumes:
        - ./broker-a/logs:/home/rocketmq/logs
        - ./broker-a/store:/home/rocketmq/store
        - ./broker-a/conf/broker.conf:/home/rocketmq/rocketmq-4.8.0/conf/broker.conf
      command: sh mqbroker -n namesrv:9876 -c /home/rocketmq/rocketmq-4.8.0/conf/broker.conf
      depends_on:
        - namesrv
    broker-b:
      container_name: rmqbroker-b
      image: foxiswho/rocketmq:4.8.0
      ports:
        - '10919:10919'
        - '10921:10921'
      volumes:
        - ./broker-b/logs:/home/rocketmq/logs
        - ./broker-b/store:/home/rocketmq/store
        - ./broker-b/conf/broker.conf:/home/rocketmq/rocketmq-4.8.0/conf/broker.conf
      environment:
        JAVA_OPT_EXT: "-Duser.home=/home/rocketmq -Xms128M -Xmx128M -Xmn128m"
      command: [ "sh","mqbroker","-c","/home/rocketmq/rocketmq-4.8.0/conf/broker.conf","-n","namesrv:9876","autoCreateTopicEnable=true" ]
      depends_on:
        - namesrv
    mqconsole:
      image: styletang/rocketmq-console-ng
      container_name: rmqconsole
      ports:
        - "10100:8080"
      environment:
        JAVA_OPTS: -Drocketmq.config.namesrvAddr=namesrv:9876 -Drocketmq.config.isVIPChannel=false
      depends_on:
        - namesrv

相关broker.conf

# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.


#所属集群名字
brokerClusterName=DefaultCluster

#broker名字,注意此处不同的配置文件填写的不一样,如果在broker-a.properties使用:broker-a,
#在broker-b.properties使用:broker-b
brokerName=broker-a

#0 表示Master,>0 表示Slave
brokerId=0

#nameServer地址,分号分割
#namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876

#启动IP,如果 docker 报 com.alibaba.rocketmq.remoting.exception.RemotingConnectException: connect to <192.168.0.120:10909> failed
# 解决方式1 加上一句producer.setVipChannelEnabled(false);,解决方式2 brokerIP1 设置宿主机IP,不要使用docker 内部IP

# 设置broker节点所在服务器的ip地址(**这个非常重要,主从模式下,从节点会根据主节点的brokerIP2来同步数据,如果不配置,主从无法同步,brokerIP1设置为自己外网能访问的ip,服务器双网卡情况下必须配置,比如阿里云这种,主节点需要配置ip1和ip2,从节点只需要配置ip1即可)
brokerIP1=172.16.100.81
brokerIP2 = 172.16.100.81

#在发送消息时,自动创建服务器不存在的topic,默认创建的队列数
defaultTopicQueueNums=4

#是否允许 Broker 自动创建Topic,建议线下开启,线上关闭 !!!这里仔细看是false,false,false
#原因下篇博客见~ 哈哈哈哈
autoCreateTopicEnable=true

#是否允许 Broker 自动创建订阅组,建议线下开启,线上关闭
autoCreateSubscriptionGroup=true

#Broker 对外服务的监听端口
listenPort=10911

#删除文件时间点,默认凌晨4点
deleteWhen=04

#文件保留时间,默认48小时
fileReservedTime=12

#commitLog每个文件的大小默认1G
mapedFileSizeCommitLog=1073741824

#ConsumeQueue每个文件默认存30W条,根据业务情况调整
mapedFileSizeConsumeQueue=300000

#destroyMapedFileIntervalForcibly=120000
#redeleteHangedFileInterval=120000
#检测物理文件磁盘空间
diskMaxUsedSpaceRatio=98
#存储路径
#storePathRootDir=/home/ztztdata/rocketmq-all-4.1.0-incubating/store
#commitLog 存储路径
#storePathCommitLog=/home/ztztdata/rocketmq-all-4.1.0-incubating/store/commitlog
#消费队列存储
#storePathConsumeQueue=/home/ztztdata/rocketmq-all-4.1.0-incubating/store/consumequeue
#消息索引存储路径
#storePathIndex=/home/ztztdata/rocketmq-all-4.1.0-incubating/store/index
#checkpoint 文件存储路径
#storeCheckpoint=/home/ztztdata/rocketmq-all-4.1.0-incubating/store/checkpoint
#abort 文件存储路径
#abortFile=/home/ztztdata/rocketmq-all-4.1.0-incubating/store/abort
#限制的消息大小
maxMessageSize=65536

#flushCommitLogLeastPages=4
#flushConsumeQueueLeastPages=2
#flushCommitLogThoroughInterval=10000
#flushConsumeQueueThoroughInterval=60000

#Broker 的角色
#- ASYNC_MASTER 异步复制Master
#- SYNC_MASTER 同步双写Master
#- SLAVE
brokerRole=ASYNC_MASTER

#刷盘方式
#- ASYNC_FLUSH 异步刷盘
#- SYNC_FLUSH 同步刷盘
flushDiskType=ASYNC_FLUSH

#发消息线程池数量
#sendMessageThreadPoolNums=128
#拉消息线程池数量
#pullMessageThreadPoolNums=128
slaveReadEnable = true

2 针对系统复杂度提高
2.1 保证消息没有重复消费
(1) 使用redis去重
生产者代码发送100条代码

/**
 * 发送普通消息
 */
public class SendMessage {
    public static void main(String[] args) throws MQClientException, MQBrokerException, RemotingException,InterruptedException {
        // 创建消息生产者, 指定生产者所属的组名
        DefaultMQProducer producer = new DefaultMQProducer("myproducer-group");
        // 指定Nameserver地址
        producer.setNamesrvAddr("127.0.0.1:9876");
        // 启动生产者
        producer.start();
        MessageExt msg = new MessageExt();
        msg.setBody(("RocketMQ Message").getBytes());
        msg.setTopic("topicB");
        msg.setTags("myTag");
        msg.setMsgId(UUID.randomUUID().toString());
        // 发送消息
//        SendResult send = producer.send(msg, 10000);//同步的
        for (int i = 0; i <100 ; i++) {
            producer.send(msg, new SendCallback() {//异步的回调函数
                @Override
                public void onSuccess(SendResult sendResult) {
                    System.out.println("发送成功");
                }
                @Override
                public void onException(Throwable throwable) {
                    System.out.println("发送失败");
                }
            }, 10000);
        }

    }

消费者代码

@Slf4j
@Configuration
public class QCCustomer {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Value("${rocketmq.producer.group:groupB}")
    private String resultsGroupName;
    @Value("${rocketmq.name-server:}")
    private String namesrvAddr;
    @Autowired
    private MQConsumeMsgListenerProcessor mqConsumeMsgListenerProcessor;

    @Bean
    public DefaultMQPushConsumer defaultConsumer() {
        log.info("ruleEngineConsumer 正在创建---------------------------------------");
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer();
        consumer.setNamesrvAddr(namesrvAddr);
        consumer.setConsumeThreadMin(1);
        consumer.setConsumeThreadMax(2);
        consumer.setConsumeMessageBatchMaxSize(100);
        consumer.setMessageModel(MessageModel.CLUSTERING);
        // 设置监听
        consumer.registerMessageListener((MessageListenerConcurrently) (list, consumeConcurrentlyContext) -> {
            try {
                MessageExt messageExt = list.get(0);
                String msgId = messageExt.getMsgId();
                Long increment = redisTemplate.opsForValue().increment(msgId);
                redisTemplate.expire(msgId,2,TimeUnit.MINUTES);//
                if(increment==1) {
                    Thread.sleep(100);
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    String format = sdf.format(new Date());
                    log.info("时间{},MQ接收到的消息为:{}", format, new String(messageExt.getBody(), "utf-8"));
                }
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        });
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
        consumer.setInstanceName(System.currentTimeMillis() + "dstMQMsgConsumer");
        consumer.setConsumerGroup(resultsGroupName);
        try {
            consumer.subscribe("topicB", "*");
            consumer.start();
            log.info("ruleEngineConsumer 创建成功 groupName={}", resultsGroupName);

        } catch (MQClientException e) {
            log.error("ruleEngineConsumer 创建失败!");
        }
        return consumer;
    }

}

结果如下:
在这里插入图片描述

(2) 建立数据库唯一索引,保证数据不会出现重复。
2 如何保证消息的可靠性传输
RocketMQ消息丢失可能发生在以下三个阶段:
1、生产者发送消息到Broker时;
2、Broker内部存储消息到磁盘以及主从复制同步时;
3、Broker把消息推送给消费者或者消费者主动拉取消息时;
解决策略
消息发送方:通过不同的重试策略保证了消息的可靠发送;
(1)、同步发送
同步发送是指发送端在发送消息时,阻塞线程进行等待,直到服务器返回发送的结果。发送端如果需要保证消息的可靠性,防止消息发送失败,可以采用同步阻塞式的发送,然后同步检查Brocker返回的状态来判断消息是否持久化成功。如果发送超时或者失败,则会默认重试2次,RocketMQ选择至少传输成功一次的消息模型,但是有可能发生重复投递,所以消费端需要做好幂等。

(2)、异步发送
异步发送是指发送端在发送消息时,传入回调接口实现类,调用该发送接口后不会阻塞,发送方法会立即返回,回调任务会在另一个线程中执行,消息发送结果会回传给相应的回调函数。具体的业务实现可以根据发送的结果信息来判断是否需要重试来保证消息的可靠性。

(3)、单向发送
单向发送是指发送端发送完成之后,调用该发送接口后立刻返回,并不返回发送的结果,业务方无法根据发送的状态来判断消息是否发送成功,单向发送相对前两种发送方式来说是一种不可靠的消息发送方式,因此要保证消息发送的可靠性,不推荐采用这种方式来发送消息。

(4)、发送重试策略
生产者发送消息失败后,会根据相应的策略进行重试。Producer 的 send 方法本身支持内部重试,重试逻辑如下:

1、至多重试 2 次。

2、如果同步模式发送失败,则轮转到下一个 Broker,如果异步模式发送失败,则只会在当前 Broker 进行重试。这个方法的总耗时时间不超过 sendMsgTimeout 设置的值,默认 10s。

3、如果本身向 broker 发送消息产生超时异常,就不会再重试。

以上策略也是在一定程度上保证了消息可以发送成功。如果业务对消息可靠性要求比较高,建议应用增加相应的重试逻辑:比如调用 send 同步方法发送失败时,则尝试将消息存储到 db,然后由后台线程定时重试,确保消息一定到达 Broker。
Broker服务端:通过不同的刷盘机制以及主从复制来保证消息的可靠存储;
(1)刷盘机制
同步刷盘:消息写入内存的 PageCache后,立刻通知刷盘线程刷盘,然后等待刷盘完成,刷盘线程执行完成后唤醒等待的线程,返回消息写成功的状态。这种方式可以保证数据绝对安全,但是吞吐量不大。
异步刷盘(默认):消息写入到内存的 PageCache中,就立刻给客户端返回写操作成功,当 PageCache中的消息积累到一定的量时,触发一次写操作,或者定时等策略将 PageCache中的消息写入到磁盘中。这种方式吞吐量大,性能高,但是 PageCache中的数据可能丢失,不能保证数据绝对的安全。
使用同步刷盘保证数据绝对的安全
消息消费方:通过至少消费成功一次以及消费重试机制来保证消息的可靠消费
(2)复制同步
同步复制:同步复制方式是等Master和Slave均写成功后才反馈给客户端写成功状态。在同步复制方式下,如果Master出故障,Slave上有全部的备份数据,容易恢复,但是同步复制会增大数据写入延迟,降低系统吞吐量。
异步复制:异步复制方式是只要Master写成功,即可反馈给客户端写成功状态。在异步复制方式下,系统拥有较低的延迟和较高的吞吐量,但是如果Master出了故障,有些数据因为没有被写 入Slave,有可能会丢失;
2 如何发送顺序消息
Rockermq只支持局部顺序,要实现全局顺序,要保证生产者和topic队列消费者处于一对一的关系
生产者

public class SortProducter {
    public static void main(String[] args) throws Exception {
        DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
        producer.setNamesrvAddr("127.0.0.1:9876");
        producer.start();
        String[] tags = new String[]{"TagA", "TagC", "TagD"};
        // 订单列表
        List<OrderStep> orderList = new SortProducter().buildOrders();

        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateStr = sdf.format(date);
        for (int i = 0; i < 10; i++) {
            // 加个时间前缀
            String body = dateStr + " Hello RocketMQ " + orderList.get(i);
            Message msg = new Message("TopicTest", tags[i % tags.length], "KEY" + i, body.getBytes());

            SendResult sendResult = producer.send(msg, new MessageQueueSelector() {
                @Override
                public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
                    Long id = (Long) arg;  //根据订单id选择发送queue
                    long index = id % mqs.size();
                    return mqs.get((int) index);
                }
            }, orderList.get(i).getOrderId());//订单id

            System.out.println(String.format("SendResult status:%s, queueId:%d, body:%s",
                    sendResult.getSendStatus(),
                    sendResult.getMessageQueue().getQueueId(),
                    body));
        }

        producer.shutdown();
    }

    /**
     * 订单的步骤
     */
    private static class OrderStep {
        private long orderId;
        private String desc;

        public long getOrderId() {
            return orderId;
        }

        public void setOrderId(long orderId) {
            this.orderId = orderId;
        }

        public String getDesc() {
            return desc;
        }

        public void setDesc(String desc) {
            this.desc = desc;
        }

        @Override
        public String toString() {
            return "OrderStep{" +
                    "orderId=" + orderId +
                    ", desc='" + desc + '\'' +
                    '}';
        }
    }

    /**
     * 生成模拟订单数据
     */
    private List<OrderStep> buildOrders() {
        List<OrderStep> orderList = new ArrayList<OrderStep>();

        OrderStep orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111039L);
        orderDemo.setDesc("创建");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111065L);
        orderDemo.setDesc("创建");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111039L);
        orderDemo.setDesc("付款");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103117235L);
        orderDemo.setDesc("创建");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111065L);
        orderDemo.setDesc("付款");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103117235L);
        orderDemo.setDesc("付款");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111065L);
        orderDemo.setDesc("完成");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111039L);
        orderDemo.setDesc("推送");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103117235L);
        orderDemo.setDesc("完成");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111039L);
        orderDemo.setDesc("完成");
        orderList.add(orderDemo);

        return orderList;
    }
}

消费者实现

public class SortCustomer {
    public static void main(String[] args) throws Exception {
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name_3");
        consumer.setNamesrvAddr("127.0.0.1:9876");
        /**
         * 设置Consumer第一次启动是从队列头部开始消费还是队列尾部开始消费<br>
         * 如果非第一次启动,那么按照上次消费的位置继续消费
         */
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
        consumer.subscribe("TopicTest", "TagA || TagC || TagD");
        consumer.registerMessageListener(new MessageListenerOrderly() {
            Random random = new Random();
            @Override
            public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) {
                context.setAutoCommit(true);
                for (MessageExt msg : msgs) {
                    // 可以看到每个queue有唯一的consume线程来消费, 订单对每个queue(分区)有序
                    System.out.println("consumeThread=" + Thread.currentThread().getName() + "queueId=" + msg.getQueueId() + ", content:" + new String(msg.getBody()));
                }
                try {
                    //模拟业务逻辑处理中...
                    TimeUnit.SECONDS.sleep(random.nextInt(10));
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return ConsumeOrderlyStatus.SUCCESS;
            }
        });
        consumer.start();
        System.out.println("Consumer Started.");
    }
}

3一致性问题
对于一致性问题可以采用事务消息解决

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

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

相关文章

Postman传递@requestbody标注的List集合的传参遇到的问题

Postman传递requestbody标注的List集合的传参遇到的问题 引子如何测试以及遇到的问题参考文献 引子 我们想测试如下接口 RequestMapping(value "saveMessageRecover", method RequestMethod.POST) ResponseBody public AjaxMessage saveMessageRecover(RequestBod…

聚观早报 |必应成为中国第一大桌面搜索引擎;快手上市后首次盈利

今日要闻&#xff1a;必应成为中国第一大桌面搜索引擎&#xff1b;快手上市后集团层面首次盈利&#xff1b;ChatGPT相关诈骗攻击与日俱增&#xff1b;比亚迪回应法国建厂传闻&#xff1b;薇娅夫妇半年收获两家上市公司 必应成为中国第一大桌面搜索引擎 5 月 22 日消息&#xf…

媒体专访|美创胡大海:国内数据安全市场正处于战略机遇期

引言 &#xff1a;我国在《“十四五”数字经济发展规划》中强调深化应用、规范发展、普惠共享&#xff0c;更多强调了数据资源为关键要素的重要性&#xff0c;并呼应了数据要素正式被纳入生产要素的政策&#xff0c;着重提出了数字经济具有“融合应用”和“全要素数字化转型”的…

断言无忧!接口自动化框架封装,Mysql数据库断言

目录 前言&#xff1a; 一、项目背景 二、框架封装 1. Mysql数据库连接 2. 查询功能 3. 断言功能 4. 使用示例 三、总结 前言&#xff1a; 随着互联网行业的迅猛发展&#xff0c;接口自动化测试在软件开发过程中扮演着越来越重要的角色。而在进行接口测试的过程中&…

初学UE5,UE4的教程适用UE5吗?

在UE5出版后&#xff0c;很多人问UE4还要不要学、UE4适不适用于UE5等问题。 UE5是最近推出的一款游戏引擎&#xff0c;相较于UE4而言&#xff0c;它有着更好的性能和灵活的工作流程&#xff0c;同时也引入了一些新的功能。对于一些游戏开发初学者来说&#xff0c;他们可能会想…

Flask restful分页接口实现

1.先定义一个工作信息表: 指定一些相关的字段:工作名称、年限、级别等 class Work(db.Model):__tablename__ = workid = db.Column(db.Integer, primary_key=True)workName = db.Column(db.String(5),nullable=False)year = db.Column(db.String(20), nullable=False)level = …

加密与解密 调试篇 动态调试技术 (二)

我们在 (一)中调试了一个程序 接着我们开始继续学习 常见的断点 这里有 INT 3断点 硬件断点 内存断点 消息断点等 1.INT 3 断点 我们在OllyDbg中 可以使用 命令 bp 或者 F12进行断点 INT3断点 就是在程序中 对该位置的代码 进行替换 替换为INT3 INT3 是一个软中断指令…

ChatGPT:你真的了解网络安全吗?浅谈网络安全攻击防御进行时之网络安全新定义

ChatGPT&#xff1a;你真的了解网络安全吗&#xff1f;浅谈网络安全攻击防御进行时 网络安全新定义 ChatGPT&#xff08;全名&#xff1a;Chat Generative Pre-trained Transformer&#xff09;&#xff0c;美国OpenAI 研发的聊天机器人程序&#xff0c;是人工智能技术驱动的自…

如何利用ChatGPT在工作中提高生产力?

[请微信搜索“云智AI助手”、“云智博瑞”关注我们 │ 谢谢支持 ] Cloud wisdom, AI assistant 每次人工智能成为头条新闻&#xff0c;都会引发对它是否会让人类失业的讨论。尽管某些工作可能会变得多余&#xff0c;我们应该学会与人工智能共同工作&#xff0c;将其作为增强自…

Python统计学13——回归的多重共线性、异方差、自相关的检验

在基础统计学&#xff0c;或者是计量经济学里面&#xff0c;需要对回归问题进行一些违背经典假设的检验&#xff0c;例如多重共线性、异方差、自相关的检验。这些检验用stata&#xff0c;r&#xff0c;Eviews什么都很简单&#xff0c;但是用python很多人都不会。下面就带大家实…

2023.5.14Ubuntu忘记MySQL密码

如果您忘记了MySQL的密码&#xff0c;可以按照以下步骤重置MySQL的密码&#xff1a; 停止MySQL服务&#xff1a; sudo service mysql stop启动MySQL服务&#xff0c;并跳过授权表&#xff1a; sudo mysqld_safe --skip-grant-tables &使用MySQL客户端连接到MySQL&#x…

【搭建轻量级图床】本地搭建LightPicture开源图床管理系统 - 异地远程访问

文章目录 1.前言2. Lightpicture网站搭建2.1. Lightpicture下载和安装2.2. Lightpicture网页测试2.3.cpolar的安装和注册 3.本地网页发布3.1.Cpolar云端设置3.2.Cpolar本地设置 4.公网访问测试5.结语 1.前言 现在的手机越来越先进&#xff0c;功能也越来越多&#xff0c;而手机…

吃鸡史:傻鸡是怎么进化并“称霸”世界的?

鸡&#xff0c;给我们的印象是温顺的&#xff1a;温顺地长大&#xff0c;温顺地下蛋&#xff0c;温顺地进油锅… 若是鸡祖宗们知道&#xff0c;有一天它们的鸡子鸡孙会进化成一群不会飞、只知道吃的傻鸡&#xff0c;几千年前的红原鸡骨怕是都要惊得飞出土了&#xff01; 毕竟…

day17 回话跟踪技术Cookie与Session

会话跟踪技术 问题:一次会话中的多次请求不会共享数据,不能显示.若通过传参数在路径上来解决该问题,不安全. 作用:解决HTTP无状态 http,cookie,session使用的区别 如果使用http中的request.setAttribute(),只能一次共享一个 若使用cookie,cookie存在浏览器中,每一次请求都…

JAVA——类间双向关联关系的实现-Contact与Phone类(电话簿管理系统)

首先&#xff1a;确定代码雏形框架&#xff08;原始代码&#xff09; 先根据以往经验写出一般的电话簿管理系统&#xff0c;先把代码雏形框架确定好。 原始代码运行结果&#xff1a; 原始代码源码&#xff1a; package bidirectionalDome;import java.util.ArrayList;public…

前端基础面试题八股文

html语义化的理解 代码结构: 使页面在没有css的情况下,也能够呈现出好的内容结构 有利于SEO: 爬虫根据标签来分配关键字的权重,因此可以和搜索引擎建立良好的沟通,帮助爬虫抓取更多的有效信息 方便其他设备解析&#xff1a; 如屏幕阅读器、盲人阅读器、移动设备等&#xff0c…

【敬伟ps教程】自由变换

文章目录 自由变换 自由变换 变换可以针对整个图层(组或链接图层)&#xff0c;或者选区内 基本操作 编辑–自由变换&#xff08;CtrilT&#xff09;&#xff1b; 自由变换的控件框来控制变换的效果&#xff1b; 自由变换是独立进行操作的模式&#xff0c;操作结束后需要点击确…

nginx -- 基本操作命令

修改nginx 配置&#xff0c;重新启动nginx流程,先进入到nginx目录 查看nginx状态 ps -ef | grep nginx 修改完/conf/nginx.conf 配置文件后保存 检查配置文件是否正确 ./sbin/nginx -t 检查文件配置正常 关闭nginx ./sbin/nginx -s quit 启动nginx ./sbin/nginx 完成

无线AP中小型、大型两种常见组网方式

无线AP&#xff08;Access Point&#xff09;网络覆盖是现代无线网络中的重要组成部分。它提供了无线信号的传输和接收功能&#xff0c;使用户能够在无线网络中进行通信和访问互联网。针对不同的需求和场景&#xff0c;存在两种常见的无线AP网络覆盖组网方式&#xff1a;中小型…

IMX6ULL平台的I2C

IMX6ULL平台的I2C 文章目录 IMX6ULL平台的I2C概述模式和操作 外部信号时钟功能描述I2C系统配置仲裁程序时钟同步信号交换外围总线访问复位中断字节顺序 初始化初始化序列启动的生成传输后软件响应停止的生成重复启动的生成从模式仲裁失败软件限制 I2C内存映射/寄存器定义I2C地址…