nacos客户端是如何进行服务发现的?

本来自己写了一遍,但从网上找到的一个源码分析图。觉得比自己总结的好且更为细致,就直接放过来了。一图胜千言。 https://xie.infoq.cn/article/d342a914b8754dd52f5709b43 服务心跳、服务剔除 这些都与eureka类似。定时访问对应的接口即可 与eureka不太一样的是,服务同步如果是ephemeral则异步更新,达到最终一致性 AP。如果是持久化的注册,则使用raft协议同步 CP。 nacos1.x版本使用http进行通信、2.x版本做了重构改为使用grpc进行内部节点以及对外通信,目前为beta版。……

阅读全文

nacos注册中心初始化

注册中心启动类就一个springboot应用,看不出什么东西 @EnableScheduling @SpringBootApplication(scanBasePackages = {"com.alibaba.nacos.naming", "com.alibaba.nacos.core"}) public class NamingApp { public static void main(String[] args) { SpringApplication.run(NamingApp.class, args); } } 通过官方文档已经一些分析,得知底层是用了raft协议来做集群同步 //PersistentConsistencyServiceDelegateImpl private BasePersistentServiceProcessor createNewPersistentServiceProcessor(ProtocolManager protocolManager, ClusterVersionJudgement versionJudgement) throws Exception { //根据相关配置,判断到底是standlone还是raft模式 final BasePersistentServiceProcessor processor = EnvUtil.getStandaloneMode() ? new StandalonePersistentServiceProcessor(versionJudgement) : new PersistentServiceProcessor(protocolManager, versionJudgement); //调用基类的方法 processor.afterConstruct(); return processor; } 具体的代码逻辑 //PersistentServiceProcessor @Override public void afterConstruct() { super.afterConstruct(); this.protocol.addRequestProcessors(Collections.singletonList(this)); //监听元数据的状态 this.protocol.protocolMetaData() .subscribe(Constants.NAMING_PERSISTENT_SERVICE_GROUP, MetadataKey.LEADER_META_DATA, (o, arg) -> hasLeader = StringUtils.……

阅读全文

ArrayList和LinkedList集合源码

ArrayList 底层使用数组实现,适合插入较少 适合随机查找O(1),原理:地址连续 扩容O(n) 源码中int newCapacity = oldCapacity + (oldCapacity » 1);即扩容为原来的1.5倍 插入O(n),尾插为O(1),最坏O(n),平均即为 O(n) LinkedList 底层使用(双向)链表,适合插入较多 随机查找O(n) 头尾插入O(1) 使用场景 ArrayList:一般场景,都是用ArrayList来代表一个集合,只要别频繁的往里面插入和灌入大量的元素就可以了,遍历,或者随机查,都可以。 LinkedList:适合,频繁的在list中插入和删除某个元素,然后尤其是LinkedList他其实是可以当做队列来用的,这个东西的话呢,我们后面看源码的时候,可以来看一下,先进先出,在list尾部怼进去一个元素,从头部拿出来一个元素。如果要在内存里实现一个基本的队列的话,可以用LinkedList……

阅读全文

Hashmap源码

Hashmap 对key进行hash,放到数组对应的位置 p = tab[i = (n - 1) & hash] 。i的位置为i = (n - 1) & hash 从JDK8以后结构为:数组 + 链表 + 红黑树,从原来的hash冲突时由纯链表变为,当链表长度大于8以后变为红黑树。 fail-fast机制是什么东西,这个在开发的时候是一个比较常见的异常,ConcurrentModificationException 核心变量 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 //应该是数组的默认的初始大小,是16,这个跟ArrayList是不一样的,初始的默认大小是10 //这个数组的大小,一般会自己手动指定一下,就跟你用ArrayList一样,你需要去预估一下你的这个数据结构里会放多少key-value对,指定的大一些,避免频繁的扩容 static final float DEFAULT_LOAD_FACTOR = 0.75f; //默认的负载因子,如果你在数组里的元素的个数达到了数组大小(16) * 负载因子(0.75f),默认是达到12个元素,就会进行数组的扩容 static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Node<K,V> next; } //这是一个很关键的内部类,他其实是代表了一个key-value对,里面包含了key的hash值,key,value,还有就是可以有一个next的指针,指向下一个Node,也就是指向单向链表中的下一个节点 //通过这个next指针,就可以形成一个链表 transient Node<K,V>[] table; //这个是什么东东?Node<K, V>[],这个数组就是所谓的map里的核心数据结构的数组,数组的元素就可以看到是Node类型的,天然就可以挂成一个链表,单向链表,Node里面只有一个next指针 transient int size; //这个size代表的是就是当前hashmap中有多少个key-value对,如果这个数量达到了指定大小 * 负载因子,那么就会进行数组的扩容 int threshold; //这个值,其实就是说capacity(就是默认的数组的大小),就是说capacity * loadFactory,就是threshold,如果size达到了threshold,那么就会进行数组的扩容,如果面试这么回答,你就是在打自己的脸。扩容的时机是size>threshold //负载因子,默认值,threshold,扩容,扩容,rehash的算法,JDK 1.……

阅读全文

SpringCloud源码| eureka源码

eureka server启动流程 EurekaBootStrap#contextInitialized(ServletContextEvent) 方法进行初始化 @Override public void contextInitialized(ServletContextEvent event) { try { //1、初始化eureka相关环境 initEurekaEnvironment(); //2、初始化eureka的serverContext initEurekaServerContext(); ServletContext sc = event.getServletContext(); sc.setAttribute(EurekaServerContext.class.getName(), serverContext); } catch (Throwable e) { logger.error("Cannot bootstrap eureka server :", e); throw new RuntimeException("Cannot bootstrap eureka server :", e); } } /** * Users can override to initialize the environment themselves. */ protected void initEurekaEnvironment() throws Exception { logger.info("Setting the eureka configuration.."); AbstractConfiguration configInstance = ConfigurationManager.getConfigInstance(); String dataCenter = configInstance.……

阅读全文

SpringCloud源码| feign源码

feign核心组件 Encoder和Decoder:编解码组件。SpringEncoder和ResponseEntityDecoder Contract:解析spring mvc相关组件。SpringMvcContract Feign.Builder:FeignClient的一个实例构造器,builder模式 FeignClient:LoadBalancerFeignClient ,底层整合ribbon feign的使用和自定义配置 @FeignClient(name = “ServiceA”, configuration = MyConfiguration.class) public interface ServiceAClient { } public class MyConfiguration { @Bean public RequestInterceptor requestInterceptor() { return new MyRequestInterceptor(); } } feign的入口 @EnableFeignClients,使用FeignClientsRegistrar扫描包下面的所有FeignClient。 使用SpringMvcContract解析相关spring mvc注解,生成LoadBalancerFeignClient动态代理 FeignClient底层使用ribbon进行负载均衡,调用对应的远程服务 @Import(FeignClientsRegistrar.class) public @interface EnableFeignClients { //省略 } //FeignClientsRegistrar类的重要方法 @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { //注册bean registerDefaultConfiguration(metadata, registry); //扫描所有@FeignClient,解析注解中的所有属性。注册对应的FeignClient registerFeignClients(metadata, registry); } private void registerDefaultConfiguration(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { Map<String, Object> defaultAttrs = metadata .……

阅读全文

SpringCloud源码| hystrix源码

hystrix在微服务中扮演重要作用,其实现了隔离、熔断、降级等重要组件 但在spring cloud中,常与feign搭配起来使用。故本文仅包含其余feign整合后的相关源码。 hystrix资源隔离 共有两种:线程池的资源隔离,信号量的资源隔离 线程池:适合绝大多数的场景,99%的,线程池,对依赖服务的网络请求的调用和访问,timeout这种问题 信号量:适合对内部的一些比较复杂的业务逻辑的访问,但是像这种访问,系统内部的代码,其实不涉及任何的网络请求,那么只要做信号量的普通限流就可以了,因为不需要去捕获timeout类似的问题。但算法+数据结构的效率不是太高,并发量突然太高,因为这里稍微耗时一些,导致很多线程卡在这里的话,不太好,所以进行一个基本的资源隔离和访问,避免内部复杂的低效率的代码,导致大量的线程被hang住 feign集成hystrix以后,HystrixFeign.Builder则被替换为HystrixFeign.Builder。以支持hystrix相关组件 //ReflectiveFeign 类中 public <T> T newInstance(Target<T> target) { Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target); //对应FeignClient中的方法,及代理类 Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>(); List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>(); for (Method method : target.type().getMethods()) { if (method.getDeclaringClass() == Object.class) { continue; } else if (Util.isDefault(method)) { DefaultMethodHandler handler = new DefaultMethodHandler(method); defaultMethodHandlers.add(handler); methodToHandler.put(method, handler); } else { methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method))); } } //调用HystrixFeign.……

阅读全文

SpringCloud源码| ribbon源码

ribbon的作用:一个服务部署多个实例时,负责负载均衡请求的组件 ribbon重要组件 ILoadBalancer:负载均衡器,其中包含了IRule和IPing IRule:负责负载均衡选择服务的规则 IPing:定时ping服务器,判断其是否存活 public class MyConfiguration { @Bean public IRule getRule() { return new MyRule(); } @Bean public IPing getPing() { return new MyPing(); } } @RibbonClient(name = "ServiceB", configuration = MyConfiguration.class) public class ServiceBConfiguration { } ribbon的入口 @LoadBalanced将将一个RestTemplate标志为底层采用LoadBalancerClient来执行实际的http请求,支持负载均衡。 org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration中有相关的bean注册。LoadBalancerRequestFactory、LoadBalancerInterceptor、RestTemplateCustomizer等等 使用RestTemplateCustomizer对每个restTemplate,使用LoadBalancerInterceptor进行定制。 @Bean @ConditionalOnMissingBean public LoadBalancerRequestFactory loadBalancerRequestFactory( LoadBalancerClient loadBalancerClient) { return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers); } @Configuration(proxyBeanMethods = false) @ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate") static class LoadBalancerInterceptorConfig { //配置拦截器 @Bean public LoadBalancerInterceptor loadBalancerInterceptor( LoadBalancerClient loadBalancerClient, LoadBalancerRequestFactory requestFactory) { return new LoadBalancerInterceptor(loadBalancerClient, requestFactory); } //RestTemplate定制化,使用LoadBalancerInterceptor @Bean @ConditionalOnMissingBean public RestTemplateCustomizer restTemplateCustomizer( final LoadBalancerInterceptor loadBalancerInterceptor) { return restTemplate -> { List<ClientHttpRequestInterceptor> list = new ArrayList<>( restTemplate.……

阅读全文

SpringCloud源码| zuul源码

zuul主要使用责任链设计模式 其中有如下过滤器 pre过滤器 -3:ServletDetectionFilter -2:Servlet30WrapperFilter -1:FromBodyWrapperFilter 1:DebugFilter 5:PreDecorationFilter routing过滤器 10:RibbonRoutingFilter 100:SimpleHostRoutingFilter 500:SendForwardFilter post过滤器 0:SendErrorFilter 900:LocationRewriteFilter 1000:SendResponseFilter @EnableZuulProxy为spring cloud中zuul的入口 @EnableCircuitBreaker @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Import(ZuulProxyMarkerConfiguration.class) public @interface EnableZuulProxy { } 然后在ZuulProxyAutoConfiguration进行相关类的注册 经过断点调试,核心逻辑为此方法ZuulServlet#service @Override public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException { try { init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse); // Marks this request as having passed through the "Zuul engine", as opposed to servlets // explicitly bound in web.……

阅读全文

事务隔离级别,MVCC与国内主流分布式事务方案

ACID与隔离级别 事务具有以下四种特征: 原子性(Atomicity) 事务包含的所有操作要么全部成功,要么全部失败回滚。 一致性(Consistency) 事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。 拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。 隔离性(Isolation) 不同事务并发执行操作相同数据时,每个事务都有各自完整的数据空间,即一个事务内所操作使用的数据与其他并发执行的各事务不互相干扰。 持久性(Durability) 一个事务一旦提交,对数据库中数据状态变更应该是永久保存下来,即使发生系统崩溃或宕机,也一定能恢复到事务成功结束时的状态。 隔离级别 隔离级别 脏读 不可重复读 幻读 读未提交 存在 存在 存在 读已提交 不存在 存在 存在 可重复读 不存在 不存在 存在 串行化 不存在 不存在 不存在 下面用口语化对各个隔离级别进行解释。 假设,数据库中有这样一个数据,id=1 name=张三 读未提交 事务1中,将张三修改为李四,但未提交 事务2中,就读到了id=1 name=李四 此为读未提交,存在脏读 读已提交 事务1中,将张三修改为李四 事务2中,第一次读到了id=1 name=张三……

阅读全文