简易RPC框架 - 4
简易RPC框架 - 网络传输模块1、前言我们在前面的文章中说到了客户端通过代理对象进行远程调用,其中通过Channel与服务端进行网络通信,其实就是通过网络请求来传递类信息、方法信息以及方法参数等数据到服务端。其中网络传输的具体实现在本项目中我们使用的是基于NIO的网络编程框架Netty。
2、网络传输1)网络传输实体类在此我们先定义了一些在网络传输中的数据格式:
RpcRequest请求类,当你要调用远程方法时,需要将你要调用的方法的详细信息传输到服务器端,然后服务端就能根据这些信息去获取方法对象。
123456789101112131415161718192021@AllArgsConstructor@NoArgsConstructor@Data@Builder@ToStringpublic class RpcRequest implements Serializable { private static final long serialVersionUID = 6672133783386466359L; private String requestId; ...
简易RPC框架 - 3
简易RPC框架 - 服务订阅、发现模块1、结构设计首先先看Rpc客户端的设计思路:
2、实现这里也是直接上代码:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657@Slf4jpublic class RpcClientAutoConfiguration implements BeanPostProcessor, ApplicationListener<ApplicationReadyEvent> { private static NettyRpcClient client; private volatile boolean needInitClient = false; private volatile boolean hasInitClientConfig = false; @Override public Object postProcessAfterInitializ ...
简易RPC框架 - 2
简易RPC框架 - 服务注册模块1、结构设计紧接上文,结合框架结构图进行讲解:
本节主要讲解服务注册的细节,首先定义了三个注解:@RpcService、@RpcReference、@RpcScan
@RpcService用于标注服务提供者,@RpcReference用于标注服务消费者,@RpcScan用于扫描特定的Bean
123456789101112131415@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Inheritedpublic @interface RpcService { /** * Service version, default value is empty string */ String version() default ""; /** * Service group, default value is empty string */ String group() defaul ...
简易RPC框架 - 1
简易RPC框架 - 前言1、前言Rpc框架想必大家都不陌生,常见的开源RPC框架如Dubbo、gRpc、Thrift等,为啥想到要手动实现一个Rpc框架,主要是本人对网络编程很感兴趣,想通过这个来加强自己对Java以及网络编程的理解,也能体验一下钻研的快乐。
2、基础设计这个Rpc框架的最初设计大概如下图:
最初是尝试通过NIO去实现的,每个服务对应一个Client,即每个服务绑定一个Channel,然后通过Selector轮巡监听服务端的消息。服务端再这里扮演的是一个消息中转站的角色。显而易见的,这个设计存在着一个致命的问题,服务端怎么去分辨Selector上的每个通道对应的是哪个服务,查了很多资料都没有较好的办法,这个方案就不了了之了(最初测试的时候,我试过直接把服务端发布的服务对象序列化到Redis,但存在一些问题,比如当发布的服务中有不可序列化的属性时,就会出现问题)。
这个方案行不通,之后研究了一下Dubbo服务注册的大概思路,结合掘金里DannyIdea(小林)的Java开发者的RPC实战课 里对服务注册、订阅的讲解,对原本的设计进行了改进。
以下是Dubbo的基本架构图 ...
Spring本地事务失效问题
在SpringBoot框架中,当我们需要用到事务时,一般直接在方法上标注@Transactional,这样当方法内发生异常时,整个方法都会回滚。但Spring的事务存在一个问题,假设存在这么一个场景:
123456789101112131415161718public class Service{ @Transactional(timeout = 30) public void a(){ b(); c(); } @Transactional(propagation = Propagation.REQUIRED, timeout = 10) public void b(){ } @Transactional(propagation = Propagation.REQUIRES_NEW, timeout = 10) public void c(){ }}
在spring中,事务的默认传播模式是pro ...
Feign远程调用遇到的坑
1、Feign远程调用丢失请求头问题 在订单服务向购物车服务发起远程调用时,在购物车服务中获取不到用户信息,原因是用户的信息是基于SpringSession保存在redis中,key存在于浏览器的cookie中,当在浏览器中发起请求时,由于请求会默认带上cookie,所以可以正常获取到数据信息,但在这个业务中是由Feign发起的远程调用走到购物车服务,Feign远程调用时会创建一个新的request,里面没有cookie数据,所以在购物车服务中获取不到用户数据。
解决办法,由于Feign在远程调用之前都会调用很多拦截器(默认没有拦截器),可以写一个Feign的请求拦截器扩展Feign的功能,在新的request中加入cookie
12345678910111213141516171819@Configurationpublic class FeignConfig { @Bean public RequestInterceptor requestInterceptor(){ return new RequestInterce ...
frp内网穿透
一、前言 简单介绍一下,frp主要有两个部分,客户端(frpc)和服务端(frps),服务端需要部署在具有公网ip的机器上(也就是我们自己买的云服务器),客户端就是我们需要进行穿透的电脑(本地机器)。
二、服务端配置 首先需要在服务端下载frp并解压。输入命令arch查看处理器架构,根据此去github下载对应的frp版本,然后下载解压完就行。
这里我们只需要修改frps.ini文件的配置就可以了,其他与frpc相关的文件都可删去。由于只需要进行Web服务的穿透访问,这里只配置Web,其他配置按需百度添加即可,重点是成功搭建并运行。
123456789101112131415[common]#frp监听的端口,即与本地机器建立通信的端口,默认是7000,可以改成其他的(不建议动)bind_port = 7000#该端口就是以后访问web服务需要用到的端口,可自定义vhost_http_port = 3000#授权码,建议不要太简单。这个token之后在客户端会用到#注意:不要再token后面加#注释进行注释,也会被算上token内容,导致认证失败!写注释最好单 ...
搭建redis哨兵集群
搭建哨兵集群1.集群结构Redis提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复。哨兵的结构和作用如下:
1.1哨兵的作用
监控:Sentinel 会不断检查您的master和slave是否按预期工作
自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主
通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端
1.2服务状态监控Sentinel基于心跳机制监测服务状态,每隔1秒向集群的每个实例发送ping命令:
主观下线:如果某sentinel节点发现某实例未在规定时间响应,则认为该实例主观下线。
客观下线:若超过指定数量(quorum)的sentinel都认为该实例主观下线,则该实例客观下线。quorum值最好超过Sentinel实例数量的一半。
1.3选举新的master一旦发现master故障,sentinel需要在salve中选择一个作为新的master,选择依据是这样的:
首先会判断slave节点与maste ...
搭建redis主从集群
Redis主从集群1.集群结构我们搭建的主从集群结构如图:
共包含三个节点,一个主节点,两个从节点。
这里我们会在同一台虚拟机中开启3个redis实例,模拟主从集群,信息如下:
IP
PORT
角色
192.168.237.101
7001
master
192.168.237.101
7002
slave
192.168.237.101
7003
slave
2.准备实例和配置要在同一台虚拟机开启3个实例,必须准备三份不同的配置文件和目录,配置文件所在目录也就是工作目录。
1)创建目录
我们创建三个文件夹,名字分别叫7001、7002、7003:
12# 在usr/local/redis-colony文件夹内创建目录mkdir 7001 7002 7003
如图:
2)恢复原始配置
修改redis-5.0.5/redis.conf文件,将其中的持久化模式改为默认的RDB模式,AOF保持关闭状态。
12345678# 开启RDB# save ""save 3600 1save 300 100save 60 10000# 关闭AOFapp ...
著名的三色标记法
一、前言当前主流编程语言的垃圾收集器基本上都是依靠可达性分析算法来判定对象是否存活的,可达性分析算法理论上要求全过程都基于一个能保障一致性的快照中才能够进行分析,这意味着必须全程冻结用户线程的运行(STW)。
在根节点枚举这个步骤中,由于GC Roots相比起整个Java堆中全部的对象毕竟还算是极少数,且在各种优化技巧(如OopMap)的加持下,它带来的停顿已经是非常短暂且相对固定(不随堆容量而增长)的了。可从GC Roots再继续往下遍历对象图,这一步骤的停顿时间就必定会与Java堆容量直接成正比例关系了:堆越大,存储的对象越多,对象图结构越复杂,要标记更多对象而产生的停顿时间自然就更长。包含“标记”阶段是所有追踪式垃圾收集算法的共同特征,如果这个阶段会随着堆变大而等比例增加停顿时间,其影响就会波及几乎所有的垃圾收集器,同理可知,如果能够削减这部分停顿时间的话,那收益也将会是系统性的。
二、三色标记法顾名思义,用三种颜色进行标记,其用在CMS垃圾回收器工作的并发标记阶段。
白色:表示对象尚未被垃圾收集器访问过。显然在可达性分析刚刚开始的阶段,所有的对象都是白色的,若在分析结束的阶 ...