本文是对个人系统: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 中添加新磁盘后,需要手动将新磁盘的空间分配给现有的分区(注意这一步必须有!),从而让系统可以使用这些新分配的空间,步骤如下:
-
首先看下在VirtualBox界面创建完磁盘后目前的情况
lsblk
可以看到在界面创建完磁盘后,已经成功添加了一个新的 20GB 磁盘 (sdb
)。接下来要做的是:将这个新的磁盘空间添加到现有的 LVM 卷组中,并扩展根分区 (/dev/centos/root
)
- 创建一个新的物理卷:
bash
sudo pvcreate /dev/sdb
- 将新的物理卷添加到现有的卷组:
bash
sudo vgextend centos /dev/sdb
- 扩展逻辑卷:
bash
sudo lvextend -l +100%FREE /dev/centos/root
以上 1、2、3 步截图如下: 从提示上来看 逻辑卷已经扩展成功,接下来扩展文件系统。
-
扩展文件系统:
sudo xfs_growfs /
- 验证,观察是否应用到现有分区:
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...