1、SpringGateWay采用的是WebFlux,因为和SpringMVC相比,它是非阻塞的,能提高吞吐量
2、过滤器比拦截器先执行,所以可以在网关服务的过滤器里进行登录token校验,在各个业务服务里的拦截器里进行token解析,将用户信息存入线程上下文
3、现有gateway模块和common模块,gateway模块创建了拦截器,参考上边的2,common模块创建了拦截器,进行token解析,将用户信息存入线程上线文,但由于业务模块多,都需要,所以在common模块声明拦截器,然后所有业务模块引入common。创建拦截器需要实现WebMvcConfigurer接口,所以common需要引入spring-mvc依赖,但gateway模块使用的是异步非阻塞的webflux,不需要mvc,且需要common中的其他东西,而业务模块都需要mvc,所以需要将common中引入的spring-mvc依赖的<scope>设为provided,这样gateway模块就不会引入mvc了。同时需要在声明的拦截器上加注入条件@ConditionalOnClass(DispatcherServlet.class),否则gateway服务启动报错,会提示找不到WebMvcConfigurer。同时gateway模块包路径是com.lhy.gateway.xxxx,而自定义拦截器在common模块的com.lhy.common.config包下,引用common的项目的启动类是扫描不到此自定义拦截器的,所以可以通过在common模块下的resource/META-INF下添加spring.factories的方式注册自定义拦截器,其他模块在使用common时,也会扫描到common模块的spring.factories文件,实在是太妙了。为什么引入common的gateway模块没有引入spring-mvc依赖,没有DispatcherServlet这个类时,@ConditionalOnClass(DispatcherServlet.class)这行代码不会爆红导致gateway启动失败呢?这是因为编译器只检查语法是否正确,而不关心运行时条件是否满足,@ConditionalOnClass就是来判断DispatcherServlet是否存来决定是否创建Bean的,所以DispatcherServlet不存在时当然不能报错了,语义如此,在Springboot底层jar的各种自动装配类里经常见到@ConditionalOnClass(DispatcherServlet.class)爆红的,但是不影响运行。
3、Nacos管理配置时,通过本地的bootstrap.yaml文件启动时,都会加载哪些配置文件,他们之间内容的覆盖优先级是什么,
# 配置文件分为3类:shared-configs,extension-configs,${spring.application.name}-{spring.profiles.active}.${spring.cloud.nacos.config.file-extension} # 其中{spring.profiles.active}可为空"-"号为自动消失,优先级从左往右依次降低,bootstrap.yaml和本地的application.yaml(前者比后者低)都比Nacos低要实现nacos配置热更新,创建properties配置类的方式要比@RefreshScope+@Value更好
。详情参考
4、如果您有一个使用了@ConfigurationProperties的配置类,并且您希望其他Bean能够使用这个配置类中的配置值,并且这些值能够动态地响应配置中心的变化,那么您应该在那些依赖这个配置类配置值的Bean上使用@RefreshScope。而配置类本身则应该被Spring管理为一个Bean(通常通过@Component或@Configuration与@Bean方法结合使用),但不需要(也不推荐)被标注为@RefreshScope
5、交换机只转发消息,不存储消息,投递失败则消息丢失。
6、RabbitMQ使用的可靠性要从三个方面来看:生产者的可靠性、MQ的可靠性、消费者的可靠性。
7、在使用Docker创建Redis容器时要用Host,不要用默认的bridge模式
8、redis实例在创建时,都会又自己的master_replid,当建立了主从关系后,master节点的master_replid不会变,salve节点的master_replid的值会变为master节点的master_replid。master以此来判断salve是否是第一次来建立🔗,slave的master_replid和自己的不一致,说明是第一次,则进行全量同步,否则进行增量同步。
9、主从同步原理:
- 全量同步时,master执行bgsave将内存中的数据持久化到rdb文件中,然后将此文件传输给slave节点,slave节点加载此文件。
- 增量同步时,只要最坏的情况能被解决,那其余的情况就不用关注了。最坏的情况就是第一个slave第一次建立的连接时立刻就挂了,所以master在第一个slave建立连接后就开始记录所有写操作(只有master能写),命令被记录到repl_backlog文件,同时记录一个值叫offset,用以标识记录长度,记录的写命令越多,offset就越大。slave在执行maste同步多来的写命令时也会记录offset,slave向maste发起数据同步请求时会携带自己的offset,maste拿slave的offset和自己的offset进行比较,就能知道需要给slave进行增量同步的数据是哪些。
- 各个节点在启动时master_replid的值都是自己的,当通过slave of建立主从关系时,会携带offset和master_replid,master_replid和主节点的master_replid相同,且offset为-1(没写过数据的默认-1)则说明需要全量同步,否则增量同步。全量同步时,master执行bgsave将内存数据写入rdb文件,然后和自己的offset一起传给从节点,从节点清理内存加载rdb文件,再此期间,master会把自己收到的写命令保存到replication_buffer中,当从节点加载完rdb后,主节点将replication_buff里的命令同步给子节点,子节点执行命令并对自己的offset做相应移动。增量同步时,从节点对比子节点传来的offset后从自己的repl_backlog_buffer中取出相差的命令传输给子节点。repl_backlog_buffer是在master启动时就开始记录写命令,是所用子节点共用的,用于增量同步时比较相差的命令,是环形的,满了的话会从头开始覆盖。replication_buffer是子节点第一次连接时创建,由于每个节点连接的时间各不相同,所以主节点会为每个第一次连接的子节点创建replication_buffer,用以记录主节点在bgsave期间、rdb传输到子节点期间、子节点加载rdb文件期间收到的写命令,发给子节点以保证主从offset值一致。子节点故障时,主节点的repl_backlog_buffer持续存入写命令,由于repl_backlog_buffer是环形设计,当写满时会从头开始覆盖继续写,当主节点从子节点的后边超过去时,则超过的这一部门所覆盖的上一圈的数据丢失,这种情况也会触发全量同步。
10、学习Redis要从三方面入手:主从结构(主从同步问题)、哨兵模式(主从自动切换)、集群分片(单独一个主节点进行海量数据存储、高并发写会扛不住)。这个集群分片就是将数据分成分,然后建立多个主节点,分别存一份,ES也采用了分片。
11、Redis的List数据结构,若pop后list没有元素,则会删除此list
12、事务隔离级别必须在开启事务的上下文中才能生效,事务隔离级别是数据库中用于控制并发事务之间数据的可见性、完整性的一个概念。MySQL默认将每一条SQL语句包含在一个事务中,执行完毕自动提交,再执如此执行下一条SQL,要保证多条SQL都执行过或某条SQL失败时整体都不执行,需要自己手动控制事务的范围。
13、如何防止超卖:1、数据库设置Serializeable隔离级别(严重影响数据库性能);2、乐观锁(也影响数据库性能);3、Redis的SETNX+EXPIRE的分布式锁;4、Redission分布式锁框架;5、基于ZooKeeper的分布式锁。
14、乐观锁不一定要专门加一个字段用于版本控制,常见的业务状态字段就可以,比如:update set status = 2 from table where status = 1;
15、通过setNx+expire实现分布锁的问题:1、死锁,设置了expire所以不会死锁,且要把del锁放到finally块中。2、误删别人的所:第一个请求进来由于业务复杂,锁超时了业务还没完成,此时第二个请求能够获取到锁,开始执行业务逻辑,但第一个请求执行完毕后会去删锁,此时就把第二个请求的锁给释放了,这是第三个请求就能获取锁,导致二、三请求执行出现并发问题。此时可以给锁的value设置值,值不是自己的就说明不是自己的锁,就不要删。3、由于if判断锁是不是自己的和后边的删除锁操作不是原子原子性的,如果if判断为true准备执行del且还没执行时锁恰好过期且第二个请求获得了锁,之后请求一继续执行删除错的操作,那么就又出现误删锁的问题了。此时可以使用lua脚本来解决,由于Redis是单线程处理所有命令的,是收到的命令的顺序依次执行的,通过lua脚本将命令打包依次性发送给Redis,实现lua脚本内的命令都执行完时才执行新的命令,保证了原子性。4、解决了误删锁的问题,但是第一个请求由于业务还没完成,所过期了,有一段时间没有锁,这就可能导致第二个请求的并发问题,如果数据库只有一个资源,第一个请求还没操作完,第二个请求就获得了锁,导致资源消耗超额,因此还需要引入看门狗机制,任务未完成锁快要到期时自动续时,这个是Redisson的一个功能。
16、为了保证分布式锁定的可用性,锁需要具有以下4个特点:
- 互斥性,同一时间只能由一个客户端获得锁
- 不会出现死锁
- 只有锁的拥有者才能解锁
- 加锁和解锁必须具有原子性