自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(69)
  • 收藏
  • 关注

原创 2024-5-14-从0到1手写配置中心Config之基于数据库的分布式锁

源码:https://github.com/midnight2104/midnight-config/tree/v5。假如9129先启动,观察日志成功获取到锁了,并在定时任务重不断重入。使用注解@PostConstruct初始化,使用数据源创建连接。尝试获取锁,获取成功,locked=true,否则为false。使用@PreDestroy注解销毁bean时,连接回滚,并关闭。开启定时任务,每隔5秒执行一次。锁状态locked表示已经持有。

2024-05-27 20:30:00 326

原创 2024-5-10-从0到1手写配置中心Config之Spring Value热更新

实现postProcessBeforeInitialization()方法。通过工具类找到所有带有@Value的bean,遍历每个字段。通过helper工具类抽取注解上面的表达式,构建SpringValue对象并保存起来。源码:https://github.com/midnight2104/midnight-config/tree/v4。实现ApplicationListener接口,在配置变更时,更新所有的spring value。扫描所有的Spring value,保存起来。

2024-05-26 19:30:00 305

原创 2024-5-9-从0到1手写配置中心Config之@ConfigurationProperties热更新

当EnvironmentChangeEvent事件发布之后,会重新绑定PropertySource,调用getProperty()方法获取最新配置。发现版本发生了变化,重新获取了配置,并发布了EnvironmentChangeEvent事件。发起http请求,从config-server获取所有配置信息。

2024-05-25 19:45:00 366

原创 2024-5-6-从0到1手写配置中心Config之实现配置中心客户端

在demo工程中,使用了@Value的方式和@ConfigurationProperties配置的方式。新建一个web工程,在启动类中使用注解@EnableMidnightConfig启动配置中心客户端。配置中心的客户端只是一个jar包,不是web项目,不能自动扫描注解包,需要手动注册bean。启动工程,查看日志,两种配置方式都是dev500,说明配置中心起作用了。程序启动时,debug可以看到,配置中心的值加载到env的最前面了。工程中默认的配置值midnight.a=a100。

2024-05-24 19:00:00 409 1

原创 2024-5-4-从0到1手写配置中心Config之基于h2的config-server

源码: https://github.com/midnight2104/midnight-config。在web控制台可以看到sql已经初始化完成,crud接口也比较简单。初始化语句创建一个config表,保存服务配置信息。新建的web工程中添加h2的依赖。controller类。

2024-05-23 21:01:50 161

原创 从0到1手写注册中心Registry之主从数据同步

当前节点不是主节点,并且版本信息小于主节点的版本,就认为是从节点,就需要从主节点同步数据,以保证整个集群对外数据的一致性。依次启动8084、8085、8086,主节点是8084,从节点是8085和8086。发起http请求,获取快照数据,然后根据快照数据恢复到当前从节点注册中心数据。在定时任务中,依次执行:服务状态更新,集群选主,主从数据同步。从节点8086也能查询到服务,说明主从数据同步成功。集群选主完成后,从节点需要从主节点同步数据。同步的快照数据是描述注册中心的服务信息。向主节点8084注册服务。

2024-05-01 20:00:00 20

原创 从0到1手写注册中心Registry之集群选主

观察8485的日志:更新服务状态8484是失败的,8485和8486是成功的。观察8486的日志:更新服务状态8484是失败的,8485和8486是成功的。当前实现采用第一种,通过选择出最小的hash为主节点,这种算法可以保证大家选择的都是一样的。观察8484的日志:先更新三个服务信息,都是成功的。观察8485的日志:先更新三个服务信息,都是成功的。观察8486的日志:先更新三个服务信息,都是成功的。从所有服务列表中筛选出状态为true,是主节点的服务。停掉8484,只保留8485和8486两个服务。

2024-04-30 19:15:00 234

原创 从0到1手写注册中心Registry之核心接口设计

注册:将服务和实例注册;取消注册:移除服务实例;获取所有实例;刷新服务版本:服务实例每变动一次,就更新时间戳;版本:获取服务指定版本;多个版本:获取多个服务对应的版本号;

2024-04-29 20:33:08 203

原创 从0到1实现RPC | 接入Apollo配置中心

添加apollo客户端的依赖和spring配置相关依赖通过实现ApplicationContextAware接口,获取Spring上下文。使用@ApolloConfigChangeListener注解监听命名空间rpc-demo-provider.yaml和默认的application.properties。监听逻辑是当配置中心的属性发生变化时,通过事件发布的形式更新bean的赋值。服务提供者provider和服务消费者consumer两端都需要接入配置中心。

2024-04-20 19:15:00 600 1

原创 从0到1实现RPC | 11 丰富测试案例

List参数类型转换,主要实现逻辑都在TypeUtils工具类中。对象数组参数类型转换,主要实现逻辑都在TypeUtils工具类中。对象参数类型转换,主要实现逻辑都在TypeUtils工具类中。数组参数类型转换,主要实现逻辑都在TypeUtils工具类中。数组参数类型转换,主要实现逻辑都在TypeUtils工具类中。参数类型转换,主要实现逻辑都在TypeUtils工具类中。参数类型转换,主要实现逻辑都在TypeUtils工具类中。参数类型转换,主要实现逻辑都在TypeUtils工具类中。

2024-04-14 19:00:00 297

原创 从0到1实现RPC | 12 限流

循环请求指定服务,每秒请求一次,限流配置参数为30s内超过20个请求就会被限流。观察日志,在30s内连续请求20次后第21次的请求就被限流了。限流:指定时间内请求数超过指定阈值时就抛出异常。

2024-04-13 22:29:56 294

原创 从0到1实现RPC | 10 灰度发布

在配置信息中添加实例元信息,其中gray为灰度标识,值为true表示灰度版本,值为false表示正式版本。在实际应用中,小流量严重发现没有问题,就会逐步放大灰度比例,热更新灰度应用表示,直到全部转为正式。当发布新版本时,采用灰度发布的方式,把流量逐步发开到新新版本,可以有效保证发版的顺利。总共三个实例,灰度应用是8081,正常应用是8082,8083,灰度比例是33%。在动态代理类中执行时,会先从一堆实例中选择路由,在这里就有可能选择到灰度实例。在服务注册的时候,将服务原配置添加到注册中心上去。

2024-04-12 18:30:00 748

原创 从0到1实现RPC | 09 故障隔离与恢复

为了能够拿到故障的实例,使用了halfOpenProviders,里面存储的就是故障的实例,使用定时任务,10s后启动,每隔60s执行一次半开逻辑:从故障实例中添加到半开实例中,用于请求探活。当某次调用出现异常时,使用滑动窗口记录该实例的异常调用次数,每发生一次异常就记录一次,当发生的异常次数达到指定阈值后,就隔离该实例。再进行一次请求时,会进行探活,尝试调用8081,传入参数id=1,调用成功,故障实例8081又重新添加到正常实例providers当中,故障实例成功恢复。轮询调用的是8082和8083.

2024-04-11 18:30:00 552 1

原创 从0到1实现RPC | 08 异常码和异常超时

当请求到8081 时,发生网络超时,自动进行了一次重试,第二次重试,在负载均衡时采用的是轮询,所以重试选择了8083,请求成功了。在代理类中,通过传入指定参数retry控制重试次数,使用while()循环进行重试,只对网络超时进行重试,其他异常直接抛出去。从服务消费者发起请求,睡眠时间是2秒,okhttp的连接超时时间设置为1秒,重试次数为1次。在测试方法中通过睡眠模拟网络超时。特别的,只有8081请求端口访问时才超时,其他不会。在发生网络超时的时候,可以进行重试,保证业务请求不因为网络原因而中断。

2024-04-10 18:30:00 325

原创 从0到1实现RPC | 07a 更新pom依赖方式

在consumer和provider两个模块使用依赖管理,导入spring的各个依赖。没有了paren引入的依赖,就需要通过这种方式引入依赖管理。使用命令mvn clean install -Dmaven.test.skip=true 再次编译,先忽略测试案例。默认在根pom文件中引入了spring的parent,导致子模块都是web项目,所以需要更新pom文件。没有了统一的版本号,需要各模块自己指定。

2024-04-09 21:00:00 226

原创 从0到1实现RPC | 07 支持MockFilter和CacheFilter

MockUtils的实现逻辑:对基本类型进行mock,对String类型进行mock,对一般类进行mock,还没有实现数组、集合、Map等复杂数据类型。Mock过滤器应用场景是:当发现微服务间调用异常时,开启MockFilter可以对服务请求进行mock,排查是哪个微服务发生了问题。调用findById()方法,第一次生成对象后,多次调用,返回的时间戳是一样的,证明缓存过滤器起作用了。CacheFilter的应用场景是:对调用过的请求进行缓存,不再发起远程调用,起缓存作用。

2024-04-08 19:30:00 311

原创 从0到1实现RPC | 06 代码重构

这样带来的问题是当整个服务停止时,销毁方法先执行,客户端和zk服务端已经断开连接,而服务取消注册的逻辑再执行时,就不会成功。同理,使用InstanceMeta代替String类型,来表示一个实例的元数据,表达含义更加丰富,支持更多非功能性场景。使用ServiceMeta代替String类型,来表示一个服务的元数据,表达含义更加丰富,支持更多非功能性场景。由于取消注册使用的是quietly()方式,出错了也不会报错,最终就是服务没有取消成功,消费者还可能调用到。重构后,注册中心先启动成功,在进行服务注册。

2024-04-07 20:15:00 358

原创 从0到1实现RPC | 05 基于ZooKeeper的注册中心

在服务消费者consumer启动的过程中,向注册中心获取服务接口实例信息,放到代理类中。同时,完成注册中心的订阅,有节点发生变动,就会清空当前已经获取到的服务节点信息,然后再次获取最新的实例信息。使用@PreDestory注解,当服务停止时,便取消服务注册,使用注册中心RegisterCenter的unregister()方法。Spring 的所有bean加载完成,项目启动成功才进行服务注册,防止启动过程中就注册,然后启动失败了,已经注册的可能会被调用。

2024-04-06 19:30:00 567

原创 从0到1实现RPC | 04 负载均衡和静态注册中心

在消费者启动类ConsumerBootstrap中, 把路由器router和负载均衡器loadBalancer封装到RpcContext中。在创建代理对象时,通过注册中心获取到所有的服务提供者providers,然后联合上下文信息RpcContext一起传递给代理类。同一个接口连续调用三次,可以看到返回结果,依次访问的是8081,8082,8083这三个服务,使用轮询负载均衡的目的已经成功了。在消费者配置类ConsumerConfig中创建Bean,包括注册中心,路由器和负载均衡器(这里使用的是轮询)。

2024-04-05 20:15:00 686

原创 从0到1实现RPC | 03 重载方法和参数类型转换

在Provider端接受到的是一个Double类型,这是因为web应用接收的请求后处理的类型。processArgs()方法负责处理请求每个请求参数,传入的参数和方法参数类型匹配处理。在Provider端创建的时候使用完整的方法签名替换方法全限定名。同理,在Consumer端需要对返回的结果类型进行参数处理。2.处理数组类型:是一个什么样的数组,对每个值进行处理;在Consumer端封装请求参数时,传入方法签名即可。在Provider端进行反射之前,处理请求参数。假设定义的接口如下,参数是float类型。

2024-03-22 20:53:23 691

原创 从0到1实现RPC | 02 RpcConsumer的远程调用

查找bean中的字段是否使用了@RpcConsumer注解,通过循环遍历的方式进行判断。在启动方法中注入业务服务接口UserService和OrderService,使用的注解是@RpcConsumer,本文主要的功能就是如何实现这个注解。主要的依赖是rpc-demo-api,即业务服务定义的api接口,rpc-core是核心依赖包。RpcRequest封装了远程调用消费者端请求的数据结构:接口全限定名称、方法名称、方法参数。六、代理对象RpcInvocationHandler中定义了远程调用方法的逻辑。

2024-03-22 20:51:46 792

原创 从0到1手把手实现RPC|01 RpcProvider本地实现

使用 ApplicationContextAware接口是为了获取Spring的应用上下文ApplicationContext,从里面获取bean。请求调用,根据服务全限定名(就是一个类的全名)去map存找对应的类,找到后,通过反射发起方法调用。启动类在创建的过程,会将带有@RpcProvider注解的类存放到Map中。RpcProvider是自定义的一个注解,用来表示这个类是一个服务提供者。响应类RpcResponse统一封装结果,返回状态,响应结果数据。一个服务提供者,订单服务实现类。

2024-03-10 11:46:14 380

转载 Apache ShenYu 网关正式支持 Dubbo3 服务代理

本文介绍了如何通过Apache ShenYu网关访问Dubbo服务,主要内容包括从简单示例到核心调用流程分析,并对设计原理进行了总结。

2022-06-05 18:25:39 407

原创 Apache ShenYu源码阅读系列-Dubbo插件

Apache ShenYu 是一个异步的,高性能的,跨语言的,响应式的 API 网关。ShenYu 网关使用 dubbo 插件完成对 dubbo服务的调用。你可以查看官方文档 Dubbo快速开始 了解如何使用该插件。本文基于shenyu-2.4.3版本进行源码分析,官网的介绍请参考 Dubbo服务接入 。1. 服务注册以官网提供的例子为例 shenyu-examples-dubbo 。 假如你的dubbo服务定义如下(spring-dubbo.xml):<beans xmlns="h.

2022-05-26 20:30:15 1008

原创 Apache ShenYu源码阅读系列-Divide插件

Apache ShenYu 是一个异步的,高性能的,跨语言的,响应式的 API 网关。ShenYu 网关使用 divide 插件来处理 http 请求。你可以查看官方文档 Http快速开始 了解如何使用该插件。本文基于shenyu-2.4.3版本进行源码分析,官网的介绍请参考 Http服务接入 。1. 服务注册1.1 声明注册接口使用注解@ShenyuSpringMvcClient将服务注册到网关。简单demo如下:@RestController@RequestMapping("/o.

2022-04-11 20:51:05 1540 1

原创 Apache ShenYu源码阅读系列-Agent模块源码分析

Apache ShenYu 是一个异步的,高性能的,跨语言的,响应式的 API 网关。在ShenYu网关中,Apache ShenYu 利用 Java Agent 和 字节码增强 技术实现了无痕埋点,使得用户无需引入依赖即可接入第三方可观测性系统,获取 Traces、Metrics 和 Logging 。本文基于shenyu-2.4.2版本进行源码分析,官网的介绍请参考 可观测性 。具体而言,就是shenyu-agent模块,它基于 Java Agent 机制,通过ByteBuddy字节码增强.

2022-03-14 19:45:48 1561 1

原创 Apache ShenYu源码阅读系列-注册中心实现原理之Http注册

Apache ShenYu 是一个异步的,高性能的,跨语言的,响应式的 API 网关。在ShenYu网关中,注册中心是用于将客户端信息注册到shenyu-admin,admin再通过数据同步将这些信息同步到网关,网关通过这些数据完成流量筛选。客户端信息主要包括接口信息和URI信息。本文基于shenyu-2.4.1版本进行源码分析,官网的介绍请参考 客户端接入原理 。1. 注册中心原理当客户端启动时,读取接口信息和uri信息,通过指定的注册类型,将数据发送到shenyu-admin。图中的.

2021-12-06 12:36:24 1446

原创 Apache ShenYu源码阅读系列-基于Http长轮询的数据同步

Apache ShenYu 是一个异步的,高性能的,跨语言的,响应式的 API 网关。在ShenYu网关中,数据同步是指,当在后台管理系统中,数据发送了更新后,如何将更新的数据同步到网关中。Apache ShenYu 网关当前支持ZooKeeper、WebSocket、Http长轮询、Nacos 、Etcd 和 Consul 进行数据同步。本文的主要内容是基于Http长轮询的数据同步源码分析。本文基于shenyu-2.4.0版本进行源码分析,官网的介绍请参考 数据同步原理 。1. Http长轮.

2021-11-03 13:06:03 716

原创 Apache ShenYu源码阅读系列-基于ZooKeeper的数据同步

Apache ShenYu 是一个异步的,高性能的,跨语言的,响应式的 API 网关。在ShenYu网关中,数据同步是指,当在后台管理系统中,数据发送了更新后,如何将更新的数据同步到网关中。Apache ShenYu 网关当前支持ZooKeeper、WebSocket、Http长轮询、Nacos 、Etcd 和 Consul 进行数据同步。本文的主要内容是基于ZooKeeper的数据同步源码分析。本文基于shenyu-2.4.0版本进行源码分析,官网的介绍请参考 数据同步原理 。1. 关于Zo.

2021-10-07 16:07:36 408

原创 Apache ShenYu源码阅读系列-基于WebSocket的数据同步

Apache ShenYu 是一个异步的,高性能的,跨语言的,响应式的 API 网关。在ShenYu网关中,数据同步是指,当在后台管理系统中,数据发送了更新后,如何将更新的数据同步到网关中。Apache ShenYu 网关当前支持ZooKeeper、WebSocket、Http长轮询、Nacos 、Etcd 和 Consul 进行数据同步。本文的主要内容是基于WebSocket的数据同步源码分析。本文基于shenyu-2.4.0版本进行源码分析,官网的介绍请参考 数据同步原理 。1. 关于We.

2021-09-15 12:38:27 743

原创 MySQL执行计划

MySQL中的 explain命令可以获取一个查询操作的执行计划,描述MySQL如何执行查询操作、执行顺序,使用到的索引,以及成功返回结果集需要执行的行数。可以帮助我们分析SQL语句,知道查询效率低下的原因,改进查询性能。explain的限制:不支持存储过程不会显示MySQL的优化过程不会显示所有执行信息开始之前,所需要的建表语句如下:DROP TABLE IF EXISTS `actor`;CREATE TABLE `actor` ( `id` INT(11) NOT NULL,

2021-08-11 19:45:42 79

原创 Soul源码阅读系列(十三)Resilience4j插件

本篇文章分析的是Resilience4j插件,Resilience4J是Spring Cloud Gateway推荐的容错方案,它是一个轻量级的容错库。它可以提供熔断和限流的功能。操作前准备:启动shenyu-admin,shenyu网关,shenyu-examples-http测试用例。Soul 网关最近换名字了,新的名字叫ShenYu,所以文章中可能出现书写不一致的地方。Resilience4j 功能演示要在shenyu网关使用Resilience4j插件,需要引入依赖: &

2021-06-25 13:08:52 278

原创 2021-6-20-JVM堆内存分配

一张图展示 JVM 内存分配记录下几个主要的参数设置:-Xmx :堆内存最大值,默认为物理内存的 1/4。-Xmx和-XX:MaxHeapSize是等价的。-Xms:堆内存初始值,默认为物理内存的 1/64,这里包括初始化和最小值的设置,如果想分别设置,可以通过参数 -XX:InitialHeapSize设置堆内存的初始值;可以通过参数 -XX:MinHeapSize设置堆内存的最小值。-Xmn:设置年轻代(或者叫Young区)的大小,这里包括初始化和最大值的设置,如果想分别设置,可以通过参数

2021-06-20 13:10:48 202

原创 自定义类加载器

假设,现在有一个Hello.xlass 文件,里面有一个hello()方法,但是此文件内容是一个所有字节(x=255-x)被处理后的文件,那么你应该如何正确读取这个文件呢?这里就需要自定义类加载器,来加载这个文件了。首先,我们还是看一下Java的类加载过程。类的生命周期1.加载:找Class文件2.验证:验证格式和依赖3.准备:为类变量(static修饰的变量)分配内存并设置初始零值。注意,此时实例变量还没有分配内存。4.解析:符号解析为引用5.初始化:构造器,实例变量分配内存并赋值,静态变

2021-06-19 15:56:52 357

原创 使用Java字节码分析四则运算

下面展示了一个简单的 Java类,进行了四则运算。public class Hello{ public static void main(String[] args){ int a = 1; int b = 2 + a; int c = 3 * b; int d = c - a; float e = d / 2f; System.out.println(e); }}通过命令 javac -g Hello.java 进行编译,然后通过命令 java Hello 运

2021-06-19 14:19:22 240

转载 Soul源码阅读系列(十二)基于Http长轮询的数据同步(二)

在上一篇文章中,通过跟踪源码的方式了解了http长轮询的执行流程。但是,自己还有一些疑问,本篇文章是在官网的基础上进行了拓展,加入一些自己的理解。zookeeper、websocket 数据同步的机制比较简单,而 http 同步会相对复杂一些。Soul借鉴了 Apollo、Nacos 的设计思想,取其精华,自己实现了 http 长轮询数据同步功能。注意,这里并非传统的 ajax 长轮询!http 长轮询机制如上所示,请求逻辑是Soul网关主动请求 soul-admin 的配置服务。响应逻辑有两种:

2021-06-06 15:57:32 81

转载 Soul源码阅读系列(十一)基于Http长轮询的数据同步(一)

在上一篇文章中,跟踪了基于Nacos的数据同步原理,本篇文章将要跟踪基于Http长轮询的数据同步原理。如果是 http 同步策略,soul-web 主动发起长轮询请求,默认有 90s 超时时间,如果 soul-admin 没有数据变更,则会阻塞 http 请求,如果有数据发生变更则响应变更的数据信息,如果超过 60s 仍然没有数据变更则响应空数据,网关层接到响应后,继续发起http请求,反复同样的请求。同步的核心逻辑是:在soul-admin后台修改数据,先保存到数据库,然后保存到soul-admi

2021-06-06 15:56:43 110

转载 【Soul源码阅读系列(十)】基于Nacos的数据同步

在上一篇文章中,跟踪了基于ZooKeeper的数据同步原理,本篇文件将要跟踪基于Nacos的数据同步原理。同步的核心逻辑是:在soul-admin后台修改数据,先保存到数据库;然后将修改的信息通过同步策略发送到soul网关;由网关处理后,保存在soul网关内存;使用时,从网关内存获取数据。本文的分析是想通过跟踪源码的方式来理解同步的核心逻辑,数据同步分析步骤如下:1.修改选择器2.更新数据3.接收数据4.使用更新后的数据1. 修改选择器在演示案例之前,将soul-admin的数据同步方式

2021-06-06 15:53:25 327

转载 【Soul源码阅读系列(九)】基于ZooKeeper的数据同步

在上一篇文章中,跟踪了基于WebSocket的数据同步原理,本篇文件将要跟踪基于ZooKeeper的数据同步原理。基于 zookeeper 的同步原理很简单,主要是依赖 zookeeper 的 watch 机制,soul-web 会监听配置的节点,soul-admin 在启动的时候,会将数据全量写入 zookeeper,后续数据发生变更时,会增量更新 zookeeper 的节点,与此同时,soul-web 会监听配置信息的节点,一旦有信息变更时,会更新本地缓存。同步的核心逻辑是:在soul-ad

2021-06-06 15:50:30 147

转载 【Soul源码阅读系列(八)】基于WebSocket的数据同步

在前面几篇文章中我们体验了如何将自己的服务接入到Soul网关中,接下来几篇我们将要了解的是Soul是如何完成数据同步的,在官网中介绍了4种同步方式:基于WebSocket的数据同步,基于ZoomKeeper的数据同步,基于Http长轮询的数据同步和基于Nacos的数据同步。我们将依次进行分析,本篇文章分析的是基于WebSocket的数据同步。数据同步的原理在官网已经有讲述了数据同步原理:Soul 数据同步的流程,Soul 网关在启动时,会从从配置服务同步配置数据,并且支持推拉模式获取配置变更信息,并且

2021-06-06 15:47:57 334

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除