• 【RocketMQ 系列三】RocketMQ集群搭建(2m-2s-sync)


    您好,我是码农飞哥(wei158556),感谢您阅读本文,欢迎一键三连哦
    💪🏻 1. Python基础专栏,基础知识一网打尽,9.9元买不了吃亏,买不了上当。 Python从入门到精通
    😁 2. 毕业设计专栏,毕业季咱们不慌忙,几百款毕业设计等你选。
    ❤️ 3. Python爬虫专栏,系统性的学习爬虫的知识点。9.9元买不了吃亏,买不了上当 。python爬虫入门进阶
    ❤️ 4. Ceph实战,从原理到实战应有尽有。 Ceph实战
    ❤️ 5. Java高并发编程入门,打卡学习Java高并发。 Java高并发编程入门

    一、集群特点

    image-20230924162430614

    1. NameServer是一个几乎无状态的节点,可集群部署,节点之间不会互相通信。
    2. Broker部署相对比较复杂,Broker分为Master与Slave,一个Master可以对应多个Slave,但是一个Slave只能对应一个Master。Master与Slave可以通过指定相同的BrokerName,不同的BrokerId来区分,BrokerId为0表示Master,BrokerId大于0表示Slave。
    3. Producer与NameServer集群中的其中一个节点(随机选择)建立长链接,定期从NameServer取Topic路由信息,并向Topic服务的Master建立长链接(也就是说根据Topic的路由信息找到向哪个Broker发送消息),且定时向Master发送心跳,Producer完全无状态,可集群部署。
    4. Consumer与NameServer集群中的其中一个节点(随机选择)建立长链接,定期从NameServer取Topic路由信息,并向Topic服务的Master,Slave建立长链接,且定时向Master,Slave发送心跳,Consumer既可以从Master订阅消息,也可以从Slave订阅消息,订阅关系由Broker配置决定。

    二、服务器环境

    1.1.部署架构

    使用的模式是 2m-2s-sync,双主双从,同步复制

    1.2.服务器信息

    IP角色架构模式
    192.31.186.198nameserver,brokermaster1,slave2
    192.31.184.89nameserver,brokermaster2,slave1

    1.3.配置Host (两台服务器都需要)

    1. nameserver机器信息

      #nameserver
      172.31.186.180 rocketmq-nameserver1
      172.31.184.89  rocketmq-nameserver2
      #broker 机器信息
      172.31.186.180  rocketmq-master1
      172.31.186.180  rocketmq-slave2
      172.31.184.89  rocketmq-master2
      172.31.184.89  rocketmq-slave1
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

      配置完成之后,重启网卡。

      systemctl restart network
      
      • 1

    1.4. 安装jdk(两台服务器都需要)

    安装jdk-8u192-linux-x64.rpm,此处省略。

    1.5. 关闭防火墙(两台服务器都需要)

    首先查看防火墙的状态,如果状态是 active 则表示防火墙开启

    $ systemctl status firewalld
    
    • 1

    关闭防火墙

    $ systemctl stop firewalld
    
    • 1

    1.6. 创建数据存储目录(两台服务器都需要)

    1. 创建master节点的存储路径
    mkdir -p /data/server/feige/rocketmq/store
    mkdir -p /data/server/feige/rocketmq/store/commitlog
    mkdir -p /data/server/feige/rocketmq/store/consumequeue
    mkdir -p /data/server/feige/rocketmq/store/index
    
    • 1
    • 2
    • 3
    • 4
    1. 创建slave节点的存储路径

      mkdir -p /data/server/feige/rocketmq/store-s
      mkdir -p /data/server/feige/rocketmq/store-s/commitlog
      mkdir -p /data/server/feige/rocketmq/store-s/consumequeue
      mkdir -p /data/server/feige/rocketmq/store-s/index
      
      • 1
      • 2
      • 3
      • 4

    三、下载与安装配置

    2.1.下载rocketmq并解压(两天服务器都要)

    cd /data/server/feige
    wget https://archive.apache.org/dist/rocketmq/5.1.3/rocketmq-all-5.1.3-bin-release.zip
    unzip rocketmq-all-5.1.3-bin-release.zip -d /data/server/feige/rocketmq
    cd /data/server/feige/rocketmq/rocketmq-all-5.1.3-bin-release
    
    • 1
    • 2
    • 3
    • 4

    2.2. 环境变量配置(两台服务器都需要)

    vim /etc/profile
    
    • 1

    在profile文件的末尾加入如下命令:

    ROCKETMQ_HOME=/data/server/feige/rocketmq/rocketmq-all-5.1.3-bin-release
    PATH=$PATH:$ROCKETMQ_HOME/bin
    export ROCKETMQ_HOME PATH
    
    • 1
    • 2
    • 3

    ​ 执行 source /etc/profile 使文件生效

    2.3. 配置 rocketmq broker-a (在Master1上操作)

    vim conf/2m-2s-sync/broker-a.properties
    
    • 1

    在此配置文件中添加,master默认的端口是10911。

    #所属集群名称
    brokerClusterName=rocketmq-cluster
    #broker名字,注意此处不同的配置文件填写的不一样;主从节点一样,也就是这个值区分broker组的;
    brokerName=broker-a
    #主从标识:0 表示Master, >0 表示Slave;同一个组中区分主从的标识,只能有一个主;
    brokerId=0
    #当前broker监听的IP
    brokerIP1=172.31.186.180
    #用于HA主从同步
    brokerIP2=172.31.186.180
    #nameServer地址,分号分割
    namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
    #在发消息时,自动创建服务器不存在的topic,默认创建的队列数
    defaultTopicQueueNums=4
    #是否允许Broker自动创建Topic,建议线下开启,线上关闭
    autoCreateTopicEnable=true
    #是否允许Broker自动创建订阅组,建议线下开启,线上关闭
    autoCreateSubscriptionGroup=true
    #Broker 对外服务的监听端口
    listenPort=10911
    haListenPort=10912
    #删除长期无用文件时间点,默认凌晨4点
    deleteWhen=04
    #文件保留时间(h),默认48小时
    fileReservedTime=48
    #commitLog每个文件的大小默认1G
    mapedFileSizeCommitLog=1073741824
    #ConsumeQueue每个文件默认存30W条,根据业务情况调整
    mapedFileSizeConsumeQueue=300000
    #检测物理文件磁盘空间使用率
    diskMaxUsedSpaceRatio=88
    #存储路径
    storePathRootDir=/data/server/feige/rocketmq/store
    #commitLog存储路径
    storePathCommitLog=/data/server/feige/rocketmq/store/commitlog
    #消费队列存储路径
    storePathConsumeQueue=/data/server/feige/rocketmq/store/consumequeue
    #消息索引存储路径
    storePathIndex=/data/server/feige/rocketmq/store/index
    #checkpoint 文件存储路径
    storeCheckPoint=/data/server/feige/rocketmq/store/checkpoint
    #abort 文件存储路径
    abortFile=/data/server/feige/rocketmq/store/abort
    #限制的消息大小
    maxMessageSize=65536
    #broker角色
    #- ASYNC_MASTER    异步复制Master
    #- SYNC_MASTER     同步双写Master
    #- SLAVE    从节点
    brokerRole=SYNC_MASTER
    #刷盘策略
    #- ASYNC_FLUSH    异步刷盘
    #- SYNC_FLUSH     同步刷盘
    flushDiskType=ASYNC_FLUSH
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    2.4. 配置 rocketmq broker-b-s (在Slave2上配置)

    这里为了避免与master的端口冲突,将slave的默认端口改成11011,另外还需要将从节点broker的存储路径改下,不能与master节点共用。

    #所属集群名称
    brokerClusterName=rocketmq-cluster
    #broker名字,注意此处不同的配置文件填写的不一样
    brokerName=broker-b
    #主从标识:0 表示Master, >0 表示Slave
    brokerId=1
    #当前broker监听的IP
    brokerIP1=172.31.186.180
    #用于HA主从同步
    brokerIP2=172.31.186.180
    #nameServer地址,分号分割
    namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
    #在发消息时,自动创建服务器不存在的topic,默认创建的队列数
    defaultTopicQueueNums=4
    #是否允许Broker自动创建Topic,建议线下开启,线上关闭
    autoCreateTopicEnable=true
    #是否允许Broker自动创建订阅组,建议线下开启,线上关闭
    autoCreateSubscriptionGroup=true
    #Broker 对外服务的监听端口
    listenPort=11011
    haListenPort=11012
    #删除长期无用文件时间点,默认凌晨4点
    deleteWhen=04
    #文件保留时间(h),默认48小时
    fileReservedTime=48
    #commitLog每个文件的大小默认1G
    mapedFileSizeCommitLog=1073741824
    #ConsumeQueue每个文件默认存30W条,根据业务情况调整
    mapedFileSizeConsumeQueue=300000
    #检测物理文件磁盘空间
    diskMaxUsedSpaceRatio=88
    #存储路径
    storePathRootDir=/data/server/feige/rocketmq/store-s
    #commitLog存储路径
    storePathCommitLog=/data/server/feige/rocketmq/store-s/commitlog
    #消费队列存储路径
    storePathConsumeQueue=/data/server/feige/rocketmq/store-s/consumequeue
    #消息索引存储路径
    storePathIndex=/data/server/feige/rocketmq/store-s/index
    #checkpoint 文件存储路径
    storeCheckPoint=/data/server/feige/rocketmq/store-s/checkpoint
    #abort 文件存储路径
    abortFile=/data/server/feige/rocketmq/store-s/abort
    #限制的消息大小
    maxMessageSize=65536
    #broker角色
    #- ASYNC_MASTER    异步复制Master
    #- SYNC_MASTER     同步双写Master
    #- SLAVE    从节点
    brokerRole=SLAVE
    #刷盘策略
    #- ASYNC_FLUSH    异步刷盘
    #- SYNC_FLUSH     同步刷盘
    flushDiskType=ASYNC_FLUSH
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    2.5. 配置 rocketmq broker-b.properties(在Master2上操作)

    执行

    vim conf/2m-2s-sync/broker-b.properties
    
    • 1

    在此配置文件中添加:master默认的端口是10911。

    #所属集群名称
    brokerClusterName=rocketmq-cluster
    #broker名字,注意此处不同的配置文件填写的不一样
    brokerName=broker-b
    #主从标识:0 表示Master, >0 表示Slave
    brokerId=0
    #当前broker监听的IP
    brokerIP1=172.31.184.89
    #用于HA主从同步
    brokerIP2=172.31.184.89
    #nameServer地址,分号分割
    namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
    #在发消息时,自动创建服务器不存在的topic,默认创建的队列数
    defaultTopicQueueNums=4
    #是否允许Broker自动创建Topic,建议线下开启,线上关闭
    autoCreateTopicEnable=true
    #是否允许Broker自动创建订阅组,建议线下开启,线上关闭
    autoCreateSubscriptionGroup=true
    #Broker 对外服务的监听端口
    listenPort=10911
    haListenPort=10912
    #删除长期无用文件时间点,默认凌晨4点
    deleteWhen=04
    #文件保留时间(h),默认48小时
    fileReservedTime=48
    #commitLog每个文件的大小默认1G
    mapedFileSizeCommitLog=1073741824
    #ConsumeQueue每个文件默认存30W条,根据业务情况调整
    mapedFileSizeConsumeQueue=300000
    #检测物理文件磁盘空间
    diskMaxUsedSpaceRatio=88
    #存储路径
    storePathRootDir=/data/server/feige/rocketmq/store
    #commitLog存储路径
    storePathCommitLog=/data/server/feige/rocketmq/store/commitlog
    #消费队列存储路径
    storePathConsumeQueue=/data/server/feige/rocketmq/store/consumequeue
    #消息索引存储路径
    storePathIndex=/data/server/feige/rocketmq/store/index
    #checkpoint 文件存储路径
    storeCheckPoint=/data/server/feige/rocketmq/store/checkpoint
    #abort 文件存储路径
    abortFile=/data/server/feige/rocketmq/store/abort
    #限制的消息大小
    maxMessageSize=65536
    #broker角色
    #- ASYNC_MASTER    异步复制Master
    #- SYNC_MASTER     同步双写Master
    #- SLAVE    从节点
    brokerRole=SYNC_MASTER
    #刷盘策略
    #- ASYNC_FLUSH    异步刷盘
    #- SYNC_FLUSH     同步刷盘
    flushDiskType=ASYNC_FLUSH
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    2.6. 配置rocketmq broker-a-s.properties(在Slave1上操作)

    vim conf/2m-2s-sync/broker-a-s.properties
    
    • 1

    在此配置文件中添加:将slave的默认端口改成11011。这里从节点的存储路径要与主节点区分,主和从都必须有

    #所属集群名称
    brokerClusterName=rocketmq-cluster
    #broker名字,注意此处不同的配置文件填写的不一样
    brokerName=broker-a
    #主从标识:0 表示Master, >0 表示Slave
    brokerId=1
    #当前broker监听的IP
    brokerIP1=172.31.184.89
    #用于HA主从同步
    brokerIP2=172.31.184.89
    #nameServer地址,分号分割
    namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
    #在发消息时,自动创建服务器不存在的topic,默认创建的队列数
    defaultTopicQueueNums=4
    #是否允许Broker自动创建Topic,建议线下开启,线上关闭
    autoCreateTopicEnable=true
    #是否允许Broker自动创建订阅组,建议线下开启,线上关闭
    autoCreateSubscriptionGroup=true
    #Broker 对外服务的监听端口
    listenPort=11011
    haListenPort=11012
    #删除长期无用文件时间点,默认凌晨4点
    deleteWhen=04
    #文件保留时间(h),默认48小时
    fileReservedTime=48
    #commitLog每个文件的大小默认1G
    mapedFileSizeCommitLog=1073741824
    #ConsumeQueue每个文件默认存30W条,根据业务情况调整
    mapedFileSizeConsumeQueue=300000
    #检测物理文件磁盘空间
    diskMaxUsedSpaceRatio=88
    #存储路径
    storePathRootDir=/data/server/feige/rocketmq/store-s
    #commitLog存储路径
    storePathCommitLog=/data/server/feige/rocketmq/store-s/commitlog
    #消费队列存储路径
    storePathConsumeQueue=/data/server/feige/rocketmq/store-s/consumequeue
    #消息索引存储路径
    storePathIndex=/data/server/feige/rocketmq/store-s/index
    #checkpoint 文件存储路径
    storeCheckPoint=/data/server/feige/rocketmq/store-s/checkpoint
    #abort 文件存储路径
    abortFile=/data/server/feige/rocketmq/store-s/abort
    #限制的消息大小
    maxMessageSize=65536
    #broker角色
    #- ASYNC_MASTER    异步复制Master
    #- SYNC_MASTER     同步双写Master
    #- SLAVE    从节点
    brokerRole=SLAVE
    #刷盘策略
    #- ASYNC_FLUSH    异步刷盘
    #- SYNC_FLUSH     同步刷盘
    flushDiskType=ASYNC_FLUSH
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    2.7. 测试环境JVM配置(两台机器都要执行)

    RocketMQ默认占用的内存是8G,比较大,这里需要修改下占用的堆内存,不然在一个机器是上同时启动两个 broker可能会启动失败。

    vim bin/runbroker.sh
    # 根据机器实际内存调整,这里演示的机器内存比较小,配置的值比较小
    JAVA_OPT="${JAVA_OPT} -server -Xms512m -Xmx512m -Xmn128m"
     vim bin/runserver.sh
    # 根据机器实际内存调整,这里演示的机器内存比较小,配置的值比较小
    JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -Xmn128m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
     vim bin/tools.sh
    # 根据机器实际内存调整,这里演示的机器内存比较小,配置的值比较小
    JAVA_OPT="${JAVA_OPT} -server -Xms128m -Xmx128m -Xmn256m -XX:PermSize=128m -XX:MaxPermSize=128m"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2.8. 生产环境JVM配置

     vim bin/runbroker.sh
    JAVA_OPT="${JAVA_OPT} -server -Xms8g -Xmx8g -Xmn4g"
     vim bin/runserver.sh
    JAVA_OPT="${JAVA_OPT} -server -Xms4g -Xmx4g -Xmn2g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
     vim bin/tools.sh
    JAVA_OPT="${JAVA_OPT} -server -Xms1g -Xmx1g -Xmn256m -XX:PermSize=128m -XX:MaxPermSize=128m"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    四、启动集群

    3.1.启动nameserver((两台机器上都执行)

    nohup sh bin/mqnamesrv > /data/server/feige/rocketmq/logs/mqnamesrv.log 2>&1 &
    
    • 1

    3.2.启动broker

    在192.31.186.180上执行如下命令

    #1.启动Master1,在Master1上操作
    nohup sh bin/mqbroker -c conf/2m-2s-sync/broker-a.properties > /data/server/feige/rocketmq/logs/broker-a.log 2>&1 &
    #2.启动Slave2,在Slave 2上操作
    nohup sh bin/mqbroker -c conf/2m-2s-sync/broker-b-s.properties > /data/server/feige/rocketmq/logs/broker-b-s.log 2>&1 &
    #6、查看 NameServer(9876)和 Broker(10909、10911、10912)启动情况,在2台主机上操作
    netstat -nltup|egrep "9876|10911|10912|11011|11012"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    image-20230921110217969

    在192.31.184.89上执行如下命令:

    #1.启动Master2,在Master2上操作
    nohup sh bin/mqbroker -c conf/2m-2s-sync/broker-b.properties > /data/server/feige/rocketmq/logs/broker-b.log 2>&1 &
    
    #2.启动Slave1,在Slave1上操作
    nohup sh bin/mqbroker -c conf/2m-2s-sync/broker-a-s.properties > /data/server/feige/rocketmq/logs/broker-a-s.log 2>&1 &
    
    #6、查看 NameServer(9876)和 Broker(10909、10911、10912)启动情况,在2台主机上操作
    netstat -nltup|egrep "9876|10911|10912|11011|11012"
    或者
    sh bin/mqadmin clusterList -n "172.31.184.89:9876;172.31.186.180:9876"
    或者
    jps
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3.3.测试集群生产消费情况

    #在2台主机上操作
    vim /etc/profile
    #在文件/etc/profile中追加
    export NAMESRV_ADDR="rocketmq-nameserver1:9876;rocketmq-nameserver2:9876"
    #在控制台在其中1台机器上操作,启动一个生产者,在1个消费者机器就可以看到消费信息
    sh bin/tools.sh org.apache.rocketmq.example.quickstart.Producer
    #在控制台其中2台机器上操作,启动2个消费者
    sh bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这里的NAMESRV_ADDR变量名不能做任何修改,不然就可能报连不上Nameserver的错误。

    i讯飞图片_1695298575007

    正常消费成功的话,则消费者出现如下日志:

    image-20230922124659669

    3.5. 关闭命令

    #关闭broker命令:
    sh bin/mqshutdown broker
    #关闭namesrv命令:
    sh bin/mqshutdown namesrv
    
    • 1
    • 2
    • 3
    • 4

    五、问题总结

    java.lang.RuntimeException: Lock failed,MQ already started
    	at org.apache.rocketmq.store.DefaultMessageStore.start(DefaultMessageStore.java:214)
    	at org.apache.rocketmq.broker.BrokerController.start(BrokerController.java:827)
    	at org.apache.rocketmq.broker.BrokerStartup.start(BrokerStartup.java:64)
    	at org.apache.rocketmq.broker.BrokerStartup.main(BrokerStartup.java:58)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 检查master节点和slave节点的端口是否冲突
    2. 检查master节点和slave节点的broker的存储路径是否冲突

    六、安装管理面板

    官网提供了两种部署方式,docker部署和源码部署,由于前面我们都是使用的直接部署,所以这里也采用官网提供的源码部署的方式。 (PS:docker 部署也尝试了,一直不行)。

    1. 下载源代码,源码地址:https://github.com/apache/rocketmq-dashboard/tags

    2. 在本地解压源码,然后,对源码进行编译打包,打包命令是:

      $ mvn clean package -Dmaven.test.skip=true
      
      • 1

      然后,将生成的 rocketmq-dashboard-1.0.0.jar包上传到服务器,jar的相对路径是 target\rocketmq-dashboard-1.0.0.jar

    3. 运行 rocketmq-dashboard-1.0.0.jar

    nohup java -jar rocketmq-dashboard-1.0.0.jar --server.port=18080 --rocketmq.config.namesrvAddr='172.31.184.89:9876;172.31.186.180:9876'>/data/server/feige/rocketmq/logs/mq-console.log 2>&1 &
    
    • 1

    这里需要指定两个参数:

    1. --server.port=18080 设置端口是18080,因为默认的端口是8080,很可能会冲突
    2. --rocketmq.config.namesrvAddr='192.31.184.89:9876;192.31.186.180:9876' 用于指定nameserver集群的地址,不指定的话会有问题。

    启动成功之后访问控制台:http://192.31.186.180:18080/

    image-20230922193948595

  • 相关阅读:
    度量BGP监测源数量对AS可见性的影响
    ChatGPT角色扮演教程,Prompt词分享
    网络安全(黑客)自学
    【长文】带你搞明白Redis
    科技视界杂志科技视界杂志社科技视界编辑部2022年第21期目录
    应广单片机实现跑马灯
    计算机毕设(附源码)JAVA-SSM绩效考核管理系统
    Android - Context
    第四章:Unix时间
    pytest测试框架使用基础07 fixture—parametrize获取参数的几种常用形式
  • 原文地址:https://blog.csdn.net/u014534808/article/details/133828381