第一次采用分布式框架开发的总结

109 阅读3分钟

第一次采用分布式框架开发的总结

今天第一次完成了一个采用分布式框架的后端项目,对于这次项目中出现的许多问题,在此做个总结。

框架及中间件使用情况

踩过的坑

主要是是在看了基本的一些东西之后,就急匆匆地开始开发了,所以对各个分布式组件并不是很熟悉,导致开发中有着非常多的问题,在这里记录一下

Nacos

  1. 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>
    复制代码
    
  2. Nacos的服务发现与注册配置

    情况:nacos中的服务如果要远程调用另一个服务,要先去寻找服务注册中的地址和端口,而默认情况下服务注册到nacos的地址和端口为本地,外部无法访问,所以要自己配置

    解决:自己手动配置ip和port

    spring:
        cloud:
            nacos:
              server-addr: ${nacos-server}
              discovery:
                ip: xxx.xxx.xxx.xxx
                port: xxxxx
    
  3. nacos的docker部署

    情况:部署时发现过了一段时间nacos关了,发现是内存占用过高,就关了,可以通过设置启动参数来控制

    解决:

    -Xms: 设定程序启动时占用内存大小
    -Xmx: 设定程序运行期间最大可占用的内存大小
    
  4. nacos的部署

    情况:部署启动时发现启动不起来,发现是v2.2.1没有默认密钥

    解决:

    nacos.core.auth.enabled=true  #开启鉴权
    nacos.core.auth.default.token.secret.key=填充上你自定义的秘钥且不低于32位字符即可
    

openfeign

  1. Fein默认情况下无法发表单数据

Rabbitmq

  1. 死信队列

    情况:主要是死信队列一开始设置的时候不情况,也没怎么看文档,以为参数是设置在正常队列那边的,结果搞错了。

    解决:

    @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);
        }
    
  2. 消息疯狂被重复消费

    情况:因为我用到是自动确认,然后消费者端因为openfeign远程服务调用的问题一致报异常,然后导致消息被不断的发给消费者。

    解决:try...catch...就好了

Redis

  1. 主要是序列化

    情况:因为为了处理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

  1. 设置易变辆缓存

    两种方法

    • 单独设置原子自增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类型

测试

感觉要去好好学一下常用的测试组件了,这次感觉代码就挺有问题的。

一些基本的代码习惯