第一次采用分布式框架开发的总结
今天第一次完成了一个采用分布式框架的后端项目,对于这次项目中出现的许多问题,在此做个总结。
框架及中间件使用情况
踩过的坑
主要是是在看了基本的一些东西之后,就急匆匆地开始开发了,所以对各个分布式组件并不是很熟悉,导致开发中有着非常多的问题,在这里记录一下
Nacos
-
Nacos和SpringCloud的Ribbon的依赖冲突
情况:主要是Nacos和SpringCloud的依赖都有Ribbon的依赖,导致了依赖之间的冲突
解决:排除掉依赖
<!--nacos--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId> <!-- 排除nacos和springboot中的ribbon冲突 --> <exclusions> <exclusion> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </exclusion> </exclusions> <version>2.2.0.RELEASE</version> </dependency> 复制代码
-
Nacos的服务发现与注册配置
情况:nacos中的服务如果要远程调用另一个服务,要先去寻找服务注册中的地址和端口,而默认情况下服务注册到nacos的地址和端口为本地,外部无法访问,所以要自己配置
解决:自己手动配置ip和port
spring: cloud: nacos: server-addr: ${nacos-server} discovery: ip: xxx.xxx.xxx.xxx port: xxxxx
-
nacos的docker部署
情况:部署时发现过了一段时间nacos关了,发现是内存占用过高,就关了,可以通过设置启动参数来控制
解决:
-Xms: 设定程序启动时占用内存大小 -Xmx: 设定程序运行期间最大可占用的内存大小
-
nacos的部署
情况:部署启动时发现启动不起来,发现是v2.2.1没有默认密钥
解决:
nacos.core.auth.enabled=true #开启鉴权 nacos.core.auth.default.token.secret.key=填充上你自定义的秘钥且不低于32位字符即可
openfeign
- Fein默认情况下无法发表单数据
Rabbitmq
-
死信队列
情况:主要是死信队列一开始设置的时候不情况,也没怎么看文档,以为参数是设置在正常队列那边的,结果搞错了。
解决:
@Bean public Queue deadRequestQueue() { //设置死信队列参数 Map<String, Object> arguments = new HashMap<>(); arguments.put("x-dead-letter-exchange", SUBMIT_DEAD_EXCHANGE_NAME); arguments.put("x-dead-letter-routing-key", SUBMIT_DEAD_ROUTING_KEY); return new Queue(DEAD_QUEUE_NAME, true, false, false, arguments); }
-
消息疯狂被重复消费
情况:因为我用到是自动确认,然后消费者端因为openfeign远程服务调用的问题一致报异常,然后导致消息被不断的发给消费者。
解决:try...catch...就好了
Redis
-
主要是序列化
情况:因为为了处理LocalDateTime类的序列化问题引入了(jackson-datatype-jsr310)依赖(事实上并不需要,spring-boot-start-web里就引入了该依赖),然后需要设置
//通过将WRITE_DATES_AS_TIMESTAMPS设置为false,它将告诉ObjectMapper将日期时间类型序列化为ISO-8601格式的字符串。 objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
但是,objectMapper 在序列化时默认会将单个对象包装在一个包含该对象的数组中,可能会导致序列化json对象为json数组 (ObjectMapper 被配置为启用默认类型,并且该类型是非最终类型,因此它会将序列化的对象的类型信息包含在序列化后的JSON字符串中。 因此,在序列化单个对象时,它可能会将对象包装在一个数组中,以便在反序列化时能够还原对象的类型信息。)
解决:
//配置默认类型 objectMapper.activateDefaultTyping( // LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_OBJECT );
项目合作开发
经验总结
Redis
-
设置易变辆缓存
两种方法
-
单独设置原子自增key-value
@Component public class RedisUtil { public Long incrWatchNum(final String key, Long defaultValue) { //判断有没有num字段 Object o = this.get(key); if (o == null) { return this.incrLong(key, defaultValue); } else { return redisTemplate.opsForValue().increment(key); } } public Long incrLong(final String key, Long delta) { if(delta<0){ throw new RuntimeException("递增因子必须大于0"); } return redisTemplate.opsForValue().increment(key, delta); } } //自增操作 //num原子自增 Long num = redisUtil.incrWatchNum("postId:" + postId + "watch_num", numAnother);
-
设置缓存时使用map类型
-
测试
感觉要去好好学一下常用的测试组件了,这次感觉代码就挺有问题的。