一、Nacos和Eureka的区别
Nacos、Eureka和Zookeeper都是服务发现和注册中心,但它们有一些区别:
(1)Nacos是阿里巴巴开源的服务发现和配置中心,支持服务发现、配置管理、动态DNS服务等功能。Eureka是Netflix开源的服务发现组件,主要用于AWS云平台上的服务注册和发现。Zookeeper是Apache开源的分布式协调服务,可以用于服务发现、配置管理、分布式锁等。
(2)Nacos支持多种协议,如HTTP、DNS、gRPC等,可以适应不同的场景。Eureka只支持HTTP协议。Zookeeper也支持多种协议,如TCP、UDP、HTTP等。
(3)Nacos支持服务配置管理,可以动态修改服务的配置信息。Eureka和Zookeeper也支持配置管理,但需要自己实现。
(4)Nacos支持服务健康检查,可以检测服务的状态。Eureka和Zookeeper也支持健康检查,但需要自己实现。
(5)Nacos支持服务路由和流量控制,可以实现服务的负载均衡和限流。Eureka和Zookeeper不支持路由和流量控制
总的来说,Nacos功能比Eureka和Zookeeper更全面,但也更复杂。选择哪个服务发现和注册中心,需要根据具体的需求和场景来决定。
二、RocketMQ的顺序消费
(1)消息的有序性
消息有序指的是一类消息消费时,能按照发送的顺序来消费。顺序消息分为全局顺序消息与部分顺序消息,全局顺序是指某个Topic下的所有消息都要保证顺序,部分顺序消息只要保证每一组消息被顺序消费即可。
如果想要实现全局顺序消息,那么只能使用一个队列,以及单个生产者,这是会严重影响性能。
因此,我们常说的顺序消息通常是指的是部分顺序消息。顺序消费实际上有两个核心点,一个是生产者有序存储,另一个是消费者有序消费。
(2)生产者有序发送
RocketMQ中生产者生产的消息会放置在某个队列中,基于队列先进先出的特性天然的可以保证存入队列的消息顺序和拉取的消息顺序是一致的,因此,我们只需要保证一组相同的消息按照给定的顺序存入同一个队列中,就能保证生产者有序存储。
普通发送消息的模式下,生产者会采用轮询的方式将消费均匀的分发到不同的队列中,然后被不同的消费者消费,因为一组消息在不同的队列,此时就无法使用RocketMQ带来的队列有序特性来保证消息有序性。
因为RocketMQ支持生产者在投放消息的时候自定义投放策略,我们实现一个MessageQueueSelector接口,使用Hash取模法来保证同一个订单在同一个队列中就行了,即通过订单ID%队列数量得到该ID的订单所投放的队列在队列列表中的索引,然后该订单的所有消息都会被投放到这个队列中。
三、BeanFactory和ApplicationContext的区别
BeanFactory和ApplicationContext都是Spring框架中的容器,用于管理和装配Bean对象。主要区别在于:
(1)BeanFactory是Spring框架最基本的容器,提供了最基本的IOC和DI功能,但是它的功能比较简单,只有在获取Bean时才会进行实例化和依赖注入,因此启动速度比较快,占用资源较少。
(2)ApplicationContext是BeanFactory的扩展,提供了更多的功能,如国际化、事件传递、AOP等,同时也提供了更多的Bean实例化和依赖注入的方式,如自动装配、注解等。ApplicationContext在启动时就会进行Bean的实例化和依赖注入,因此启动速度比较慢,占用资源较多。
综上所述,如果只需要基本的IOC和DI功能,可以使用BeanFactory,如果需要更多的功能,如AOP、自动装配等,可以使用ApplicationContext。
四、介绍一下Spring
Spring最主要的功能就是AOP和IOC,IOC就是将对象的创建权交给Spring去管理,默认是单例的。Bean的生命周期就是在程序启动时,会去扫描Bean的信息,并将Bean的信息封装到BeanDefinition中,然后将所有的BeanDefinition存入到BeanDefinitionMap中,然后会去执行Spring的后处理器,BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor,其中BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子类,会先执行子类方法后执行父类方法,然后会将BeanDefinitionMap进行遍历。将遍历出来的BeanDefinition转换成Object对象,然后进行属性填充,然后执行Aware接口,Spring的后处理器的BeanPostProcessor接口的before方法,InitializingBean接口初始化,Bean的自定义初始化方法init,Spring后处理器的BeanPostProcessor接口的After方法。Spring的后处理是Spring整合其他框架的重要功能,比如Mybatis就是和Spring的后处理器BeanDefinitionRegistryPostProcessor进行完成了整合,比如MapperScannerConfigurer类就是实现了这个接口。MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor接口。在postProcessorBeanDefinitionRegistry方法中定义了一个扫描包的类对象。类对象调用scan方法,该类没有该方法,于是调用它的父类ClassPathBeanDefinitionScanner的scan方法。在父类的scan方法中调用子类的doScan方法,子类的doScan方法再去调用父类的doScan方法返回结果。在父类的doScan方法中使用registerBeanDefinition方法将beanDefinition存入到BeanDefinitionMap中并返回给子类。此时在BeanDefinitionMap中的Mapper是接口,Mapper不能实例化。通过setBeanClass方法修改Mapper的BeanClass,参数为this.mapperFactoryBeanClass。这个参数是一个MapperFactoryBean.class的赋值。而MapperFactoryBean实现了FactoryBean接口 内部实现getObjcet方法是返回的是this.getSqlSession().getMapper(this.mapperInterface)(Mybatis原始代码);这个时候setBeanClass的就是MapperFactoryBean下的getObject返回的类型。此时SqlSessionFactoryBean创建出来的SqlSessionFactory还没有对象引用。setAutowireMode代表自 动注入,2代表类型自动注入。在产生这个Mapper时,它内部在使用到SqlSession时会有一个自动注入 的过程,它回去容器中找有没有sqlSession,有就注进去,帮你去产生最终的Mapper对象 而SqlSessionFactoryBean就是通过实现InitializingBean和FactoryBean完成注册。
五、SpringCloudGateway基本原理
SpringCloudGateway使用了Spring WebFlux非阻塞网络框架,网络层默认使用了高性能非阻塞的Netty Server,解决了Spring Cloud Zuul因为阻塞的线程模型带来的性能下降的问题。
Gateway本身是一个Spring Boot 应用,它处理请求是逻辑根据配置的路由对请求进行预处理和转发。Gateway有几个比较核心的概念:
(1)Route:一个Route由路由ID,转发URI,多个Predicates以及多个Filters构成。Gateway上可以配置多个Routes。处理请求时会按优先级排序,找到第一个满足所有Predicates的Route。
(2)Predicate:表示路由的匹配条件,可以用来匹配请求的各种属性,如请求路径、方法、header等。一个Route可以包含多个子Predicates,多个子Predicates最终会合并成一个。
(3)Filter:过滤器包括了处理请求和响应的逻辑,可以分为pre和post两个阶段。多个Filter在pre阶段会按优先级高到低顺序执行,post阶段则是反向执行。Gateway包括两类Filter:
1)全局Filter:每种全局Filter全局只会有一个实例,会对所有的Route都生效。
2)路由Filter:路由Filter是针对Route进行配置的,不同的Route可以使用不同的参数,因此会创建不同的实例。
六、nacos注册中心挂了,各个服务器还能通信吗
可以,因为nacos是分布式,类似于git,因此当你远程服务器挂掉的时候,本地的nacos其实有缓存一份一模一样的数据。
七、nacos存储的数据
nacos采用了数据的分级存储数据,最外层是namespace,用来隔离环境。然后是group,用来对服务分组。接下来就是服务(service),一个服务包含多个实例,但是可能处于不同机房,因此service下有多个集群(cluster),cluster下是不同的实例(instance)。
对应到Java代码中,nacos采用了一个多层的map来表示。结构为Map<String,Service>,其中最外层Map的key就是namespaceId,值是一个Map。内层Map的key是group拼接serviceName,值是Service对象。Service对象内部又是一个Map,key是集群名称,值是Cluster对象。而Cluster对象内部维护了instance的集合。
八、openfeign实现原理
openfeign会扫描带有@FeignClient注解的接口,然后为其生成一个动态代理。
动态代理里面包含有接口方法的MethodHandler,MethodHandler里面又包含经过MVC Contract解析注解后的元数据。
发起请求时,MethodHandler会生成一个Request。
负载均衡Ribbon会从服务器列表中选择一个Server,拿到对应的IP地址后,拼接成最后的URL,就可以发起远程服务调用了。