IM系统开发、部署等过程中 遇到的问题记录

本文是对个人系统:xzll-im 的一篇记录文章,记录我搭建(搭建估计不会记录了现在已经过了这一阶段)、开发、部署im系统以及周边中间件过程中遇到的问题以及解决方式。遇到的问题太多了,时间充足就尽可能记录上,不充足或者问题比较小就在代码中注释记录一下。这文章只给我自己看。以便多年后 回首曾经走过的路😂。仅此而已😄。

  • 此文将不断更新(只要是此系统相关并且我有时间并且我个人觉得有必要)。
  • 由于之前的一些问题都在代码注释中记录了这里就不补充了。以后遇到的较大的、较费时的问题,尽量在这里记录 以便以后统一管理查看以及实现:不被同一块石头绊倒两次。
  • 本文始于:2024-06-25

1、RocketMq发消息报错:the broker's disk is full [CL: 0.95 CQ: 0.95 INDEX: 0.95] 解决

最近将im依赖的各个组件都迁移到了虚拟机的docker上去了,但是发MQ消息时却报错:

less 复制代码
org.apache.rocketmq.client.exception.MQBrokerException: CODE: 14  DESC: service not available now. It may be caused by one of the following reasons: the broker's disk is full [CL:  0.95 CQ:  0.95 INDEX:  0.95], messages are put to the slave, message store has been shut down, etc.
For more information, please visit the url, http://rocketmq.apache.org/docs/faq/
	at org.apache.rocketmq.client.impl.MQClientAPIImpl.processSendResponse(MQClientAPIImpl.java:556) ~[rocketmq-client-4.5.0.jar:4.5.0]
	at org.apache.rocketmq.client.impl.MQClientAPIImpl.sendMessageSync(MQClientAPIImpl.java:358) ~[rocketmq-client-4.5.0.jar:4.5.0]
	at org.apache.rocketmq.client.impl.MQClientAPIImpl.sendMessage(MQClientAPIImpl.java:340) ~[rocketmq-client-4.5.0.jar:4.5.0]
	at org.apache.rocketmq.client.impl.MQClientAPIImpl.sendMessage(MQClientAPIImpl.java:294) ~[rocketmq-client-4.5.0.jar:4.5.0]
	at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.sendKernelImpl(DefaultMQProducerImpl.java:808) ~[rocketmq-client-4.5.0.jar:4.5.0]
	at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.sendSelectImpl(DefaultMQProducerImpl.java:1072) ~[rocketmq-client-4.5.0.jar:4.5.0]
	at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.send(DefaultMQProducerImpl.java:1044) ~[rocketmq-client-4.5.0.jar:4.5.0]
	at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.send(DefaultMQProducerImpl.java:1039) ~[rocketmq-client-4.5.0.jar:4.5.0]
	at org.apache.rocketmq.client.producer.DefaultMQProducer.send(DefaultMQProducer.java:458) ~[rocketmq-client-4.5.0.jar:4.5.0]
	at com.xzll.connect.cluster.mq.RocketMqProducerWrap.sendClusterEvent(RocketMqProducerWrap.java:80) ~[classes/:?]
	at com.xzll.connect.cluster.provider.C2CMsgProvider.offLineMsg(C2CMsgProvider.java:64) ~[classes/:?]
	at com.xzll.connect.strategy.impl.c2c.C2CMsgSendStrategyImpl.exchange(C2CMsgSendStrategyImpl.java:116) ~[classes/:?]
	at com.xzll.connect.dispatcher.HandlerDispatcher.dispatcher(HandlerDispatcher.java:43) ~[classes/:?]
	at com.xzll.connect.netty.handler.WebSocketServerHandler.lambda$handleWebSocketFrame$2(WebSocketServerHandler.java:211) ~[classes/:?]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]
	at java.lang.Thread.run(Thread.java:829) ~[?:?]

说明个前提:

我的rocketMQ是docker启动的,数据会挂载到宿主机中的目录,具体从启动命令可以看出:

bash 复制代码
# 启动 RocketMQ 的 NameServer
docker run -d \
  --name rmqnamesrv \
  -p 9876:9876 \
  -v /usr/local/soft_hzz/docker/20240624/store:/root/store \
  -v /usr/local/soft_hzz/docker/20240624/logs:/root/logs \
  apache/rocketmq:4.8.0 \
  sh mqnamesrv

# 启动 RocketMQ 的 Broker
docker run -d \
  --name rmqbroker \
  -p 10911:10911 \
  -p 10909:10909 \
  -v /usr/local/soft_hzz/docker/20240624/store:/root/store \
  -v /usr/local/soft_hzz/docker/20240624/logs:/root/logs \
  -v /usr/local/soft_hzz/docker/20240624/conf/broker.conf:/opt/rocketmq-4.8.0/conf/broker.conf \
  apache/rocketmq:4.8.0 \
  sh mqbroker -c /opt/rocketmq-4.8.0/conf/broker.conf

尝试解决:

github上也有类似问题的讨论:github.com/apache/rock... ,其中有人提到权限不够,这确实也是一个可能引发此问题的点,为了打消这个目录读写权限方面的疑点,我接下来将rocketmq挂载的目录权限和容器内的目录的权限都放到最大,以确保docker容器用户可以写入,如下

bash 复制代码
sudo chown -R $(whoami):$(whoami) /你的rocketmq数据存储路径/store
sudo chown -R $(whoami):$(whoami) /你的rocketmq日志文件存储路径/logs
sudo chmod -R 777 /你的rocketmq数据存储路径/store
sudo chmod -R 777 /你的rocketmq日志文件存储路径/logs

之后我们可以看到已经是最大权限了: 赋完权限后,另一个问题就是磁盘不足,情况如下: 可以看到挂载根文件系统的 /dev/mapper/centos-root (是一个逻辑卷管理器(LVM)卷,用于挂载根文件系统(/)。它管理和存储系统的主要数据,包括操作系统、应用程序和配置文件)用了92% ! :

ok那我就老老实实给虚拟机加磁盘吧,再不加的话虚拟机要罢工了。。。 在 VirtualBox 中添加新磁盘后,需要手动将新磁盘的空间分配给现有的分区(注意这一步必须有!),从而让系统可以使用这些新分配的空间,步骤如下:

  1. 首先看下在VirtualBox界面创建完磁盘后目前的情况

    lsblk

可以看到在界面创建完磁盘后,已经成功添加了一个新的 20GB 磁盘 (sdb)。接下来要做的是:将这个新的磁盘空间添加到现有的 LVM 卷组中,并扩展根分区 (/dev/centos/root)

  1. 创建一个新的物理卷
bash 复制代码
sudo pvcreate /dev/sdb
  1. 将新的物理卷添加到现有的卷组
bash 复制代码
sudo vgextend centos /dev/sdb
  1. 扩展逻辑卷
bash 复制代码
sudo lvextend -l +100%FREE /dev/centos/root

以上 1、2、3 步截图如下: 从提示上来看 逻辑卷已经扩展成功,接下来扩展文件系统。

  1. 扩展文件系统

    sudo xfs_growfs /

  1. 验证,观察是否应用到现有分区
bash 复制代码
df -h

从上可以看到 现在dev/mapper/centos/root 已经变为37GB,使用率为 43% 成功扩容磁盘(后期不够再扩吧)。之后的话我将rocketmq重启。

测试一下:可以看到,可以发送消息并正常消费了

2、使用redisTemplate 的execute执行lua脚本后,hash的key或value只要是string类型都被加上了 双引号 的解决记录

最近使用lua 将几个非原子命令搞成原子的,但是却发现 存进redis 的数据不管是key 还是value只要类型是string就会无缘无故多了个 双引号。如下(value没有是因为是int类型 如果是string也会加双引号): 而我获取时 必须得这样获取才能获取到: 而这不是我想要的,我存啥就给我放啥得了呗 别自作主张给我加,于是我一通排查,最开始我以为redisTemplate序列化有问题,但是最后发现其实并不是,如下是我的序列化配置,

java 复制代码
@Bean("redisTemplate")
@Primary
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory, ObjectMapper objectMapper) {
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
    redisTemplate.setConnectionFactory(redisConnectionFactory);

    //设置key 序列化的方式
    StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
    redisTemplate.setKeySerializer(stringRedisSerializer);

    //设置value 序列化的方式
    Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
    serializer.setObjectMapper(objectMapper);

    redisTemplate.setValueSerializer(serializer);

    //设置 hash key value 序列化的方式
    redisTemplate.setHashKeySerializer(new StringRedisSerializer());
    redisTemplate.setHashValueSerializer(new StringRedisSerializer());

    // 禁用默认序列化器
    redisTemplate.setEnableDefaultSerializer(false);
    redisTemplate.setDefaultSerializer(null);

    redisTemplate.afterPropertiesSet();
    return redisTemplate;
}

后来发现:redisTemplate的execute方法重载了好几个,其中有这么个重载方法: 从参数就知道可以指定args和反参的序列化类型,嘿那不正好,来试试吧!

启动项目以及客户端,发现redis中的数据不再带有 双引号了,如下所示: 代码中也可以按期望 获取成功了。

3、宿主机连不上虚拟机中docker部署的服务(如nacos)

在家里,使用docker 桥接网络模式(默认的) 启动nacos 死活连不上,在虚拟机启动了rocketmq和mysql 在宿主机进行 telnet 192.168.1.103 9876 或者 telnet 192.168.1.103 3306 或者相互ping ip ,都没问题,说明宿主机和虚拟机直接网络没问题,那大概率就是docker0 这个网卡问题,在没找到原因之前,只能改成host模式启动docker 容器了,也即:让docker容器 使用虚拟机的端口。不进行虚拟机到docker0网卡的端口转发了。使用host模式的话只需要在启动时指定network即--network host,如下这个就是使用的host模式:

bash 复制代码
sudo docker run -d --name nacos-home-host --network host -e MODE=standalone -p 8848:8848 nacos/nacos-server:2.0.3

后续解决后补充:

我发现问题出在docker0网卡的设置上,即:之前一直宿主机连接不上虚拟机中docker内的服务(比如nacos) 可能是因为虚拟机和docker0的网段冲突,docker0网卡的网段也是192.168.1.xx,虚拟机是192.169.1.103, 我将/etc/docker/daemon.json 文件(就是你配镜像的那个文件)追加 :"bip": "172.17.0.1/24"(这个是docker0网卡默认的ip) 后 执行:

停止所有docker 容器

bash 复制代码
sudo systemctl stop docker

重启后 即自动创建docker0 网卡

bash 复制代码
sudo systemctl restart docker

然后再ifconfig 发现docker0网卡变为172.17.0.1, 之后再重启 docker restart nacos 就可以了,what fuck ! 倒腾很久,哎。。。

贴上启动nacos的命令:

bash 复制代码
sudo docker run -d --name nacos -e MODE=standalone -p 8848:8848 nacos/nacos-server:2.0.3

能被这个问题拌住,说明对docker运行机制还不熟 尤其是他的几种网络模式。关于docker的几种模式这篇文章感觉讲的不错很清晰:www.cnblogs.com/liugp/p/163...

相关推荐
阿伟*rui1 小时前
配置管理,雪崩问题分析,sentinel的使用
java·spring boot·sentinel
XiaoLeisj3 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
paopaokaka_luck3 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
dayouziei3 小时前
java的类加载机制的学习
java·学习
码农小旋风5 小时前
详解K8S--声明式API
后端
Peter_chq5 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
Yaml45 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~5 小时前
Spring Boot详解:从入门到精通
java·spring boot·后端
hong1616885 小时前
Spring Boot中实现多数据源连接和切换的方案
java·spring boot·后端
aloha_7896 小时前
从零记录搭建一个干净的mybatis环境
java·笔记·spring·spring cloud·maven·mybatis·springboot