八,项目性能测试
前言通过前面的章节,我们的 RPC 框架已经搭建完成,虽仍有许多待优化的点,但整体的效率性能应该还是不错的,下面我们来对 XRPC 的性能进行测试
测试环境我所用的测试机器硬件配置为:
操作系统:Windows10
CPU: AMD R5 3500X 6-Core
内存:16 GB 3200 MHz DDR4
序列化测试序列化针对序列化的大小和速度进行测试
序列化后的数据大小12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455public class SerializerCompareTest { private static RpcMessage buildMessage() { RpcResponse<Object> rpcResponse = RpcResponse.builder() .requestId(UUID.randomUUID().toString() ...
七、集成Spring与SpringBoot
从零实现一个轻量级 RPC 框架-系列文章Github: https://github.com/DongZhouGu/XRpc
前言SpringBoot 最强大的功能就是把我们常用的场景抽取成了一个个 starter(场景启动器),我们通过引入 springboot 为我提供的这些场景启动器,我们再进行少量的配置就能使用相应的功能。因此对于实现的 XRPC 同样需要制作 starter,并将相关配置和 bean 加载交由 Spring 来管理,最后通过 Maven 发布
自动配置原理
首先,SpringBoot 在启动时会去依赖的 starter 包中寻找 resources/META-INF/spring.factories 文件,然后根据文件中配置的 Jar 包去扫描项目所依赖的 Jar 包,这类似于 Java 的 SPI 机制。
第二步,根据 spring.factories 配置加载 AutoConfigure 类。
最后,根据 @Conditional 注解的条件,进行自动配置并将 Bean 注入 Spring Context 上下文当中。
POM 依赖123456 ...
XRPC项目(仿Dubbo)-README
XRPC-实现轻量级 RPC 框架
介绍
为了更深入的学习 RPC 的原理与实现过程,从零实现了一个简易的可拓展 RPC 项目。
技术点包括:网络通信框架 Netty、长连接复用、TCP 粘包 / 拆包、心跳保活、服务注册与发现(Zookeeper、Nacos)、Java 基础(注解、反射、多线程、Future、SPI 、动态代理)、自定义传输协议、多种序列化(ProtoBuf / Kyro / Hessian)、Gzip 压缩、多种负载均衡算法(轮询、随机、一致性哈希)、客户端同步 / 异步调用,集成 SpringBoot 开箱即用
在学习过程中,我也将重点整理为了博客,如果觉得有用,请点个 star 吧!感谢!!
本人能力有限,如有错误和改进欢迎提交 PR
** 文章列表:**零、如何实现一个轻量级 RPC 框架?
一、如何用 Netty 实现高性能网络通信?
二、网络传输高效序列化协议与实现
三、服务注册与发现
四、采用动态代理去无感调用远程服务
五、使用 SPI 实现可插拔扩展设计
六、去调用哪个服务器呢?负载均衡策略
七、集成 Spring 与 SpringBoot
� ...
六、去调用哪个服务器呢?负载均衡策略
从零实现一个轻量级 RPC 框架-系列文章Github: https://github.com/DongZhouGu/XRpc
前言负载均衡在各个层级都有相应的应用。由于单机应用的性能局限性,在负载高的情况下,通常都会采用增加服务器的形式来横向扩展,通过集群和负载均衡来提高整个系统处理能力。那么在 RPC 项目中,当服务端由集群组成,注册中心的一个 serviceKey 对应多个服务地址,那么该选择哪个进行远程调用呢?这就需要负载均衡算法。这里我们共实现了随机、轮询和一致性 Hash 三种算法
LoadBalance123456789101112131415@SPI(value = "random")public interface LoadBalance { String doSelect(List<String> serviceAddresses, RpcRequest rpcRequest); default String selectServiceAddress(List<String> serviceAddresses, RpcRe ...
五、使用SPI实现可插拔扩展设计
从零实现一个轻量级 RPC 框架-系列文章Github: https://github.com/DongZhouGu/XRpc
前言SPI 全称为 Service Provider Interface,对应中文为服务发现机制。SPI 类似一种可插拔机制,首先需要定义一个接口或一个约定,然后不同的场景可以对其进行实现,调用方在使用的时候无需过多关注具体的实现细节。在 Java 中,SPI 体现了面向接口编程的思想,满足开闭设计原则。
JDK 自带 SPI 实现以序列化为例,如果想要实现可插拔的序列化实现,使用 JDK 原生 SPI 过程如下。
12345678910111213141516171819public interface Serializer { byte[] serialize(Object object);}public class JSONSerializer implements Serializer { @Override public byte[] serialize(Object object) { return JSON ...
四、采用动态代理去无感调用远程服务
从零实现一个轻量级 RPC 框架-系列文章Github: https://github.com/DongZhouGu/XRpc
前言在客户端需要调用远程服务时,我们希望这个过程对于用户来说是无感的,使用框架的开发人员只需要像调用本地服务一样调用远程服务。因此,我们需要使用动态代理来增强接口方法,当调用接口方法时,框架会使用自动代理,将网络通信、编解码等复杂的过程封装在代理类中,本章就是讲解如何实现这个功能。
调用流程与封装上图是整个调用过程的流程图,动态代理的部分,是 XRPC-Client 模块的核心代码。
动态代理工厂类首先,抽象出一个动态代理工厂类,封装为 ProxyFactory
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596@Setter@Accesso ...
三、服务注册与发现
从零实现一个轻量级 RPC 框架-系列文章Github: https://github.com/DongZhouGu/XRpc
前言客户端在调用远程服务时,怎么知道服务端是否有要调用的服务呢,如果有,服务端的地址是什么呢?因此,在 RPC 框架中,服务注册与发现是非常重要的一个部分。在 Provider 也就是服务端启动时,需要将自己的 IP 地址和 RPC 接口写到配置表中;Consumer 也就是客户端在请求远程服务时,会获取该服务的 IP 地址。这个配置表就叫做注册中心
注册中心的要求1. 存储可以简单地将注册中心理解为一个存储系统,存储着服务与服务提供方的映射表。一般注册中心对存储没有太多特别的要求,甚至夸张一点,你可以基于数据库来实现一个注册中心。2. 高可用注册中心一旦挂掉,Consumer 将无法获取 Provider 的地址,整个微服务将无法运转。因此当然 Consumer 可以添加本地缓存,从某种角度上看,是允许注册中心短暂挂掉的。3. 健康检查Provider 向注册中心注册服务之后,注册中心需要定时向 Provider 发起健康检查,当 Provider ...
二、网络传输高效序列化协议与实现
从零实现一个轻量级 RPC 框架-系列文章Github: https://github.com/DongZhouGu/XRpc
前言RPC 需要将对象序列化成二进制数据,写入本地 Socket 中,然后被网卡发送到网络设备中进行网络传输,序列化的速度以及序列化后的数据大小非常影响网络通信的效率,这里,我们实现了多中序列化的方法,并通过 SPI 实现自定义拓展。
对象是不能直接在网络中传输,我们需要提前把它转成可传输的二进制,并要求转换算法是可逆的,这个过程我们一般叫做“序列化”。服务提供方就可以正确的从二进制数据中分割出不同的请求,同时根据请求类型和序列化类型,把二进制消息逆向还原成请求对象,称之为”反序列化“。
序列化要素
解析效率:序列化协议应该首要考虑的因素,像 xml/json 解析起来比较耗时,需要解析 doom 树,二进制自定义协议解析起来效率要快很多。
压缩率:同样一个对象,xml/json 传输起来有大量的标签冗余信息,信息有效性低,二进制自定义协议占用的空间相对来说会小很多。
扩展性与兼容性:是否能够利于信息的扩展,并且增加字段后旧版客户端是否需要强制升级 ...
一、如何用Netty实现高性能网络通信?
从零实现一个轻量级 RPC 框架-系列文章Github: https://github.com/DongZhouGu/XRpc
前言既然要调用远程方法,必然需要网络通信,通过网络来传递要调用的目标类信息及相关方法参数,和返回的调用结果。网络传输具体实现可以使用 Socket 、NIO、Netty:
Socket:Java 中最原始、最基础的网络通信方式。但是 Socket 是阻塞 IO、性能低并且功能单一
NIO:同步非阻塞的 I/O 模型,Java 原生实现,但是用它来进行网络编程太过繁琐
Netty:基于 NIO 的 client-server(客户端服务器)框架,设计了一套优秀的 Reactor 反应器模式使用它可以快速简单地开发网络应用程序。极大地简化并简化了 TCP 和 UDP 套接字服务器等网络编程, 并且性能以及安全性等很多方面甚至都要更好。支持多种协议如 FTP,SMTP,HTTP 以及各种二进制和基于文本的传统协议。
Reactor 反应器模式Reactor 就是基于 NIO 中实现多路复用的一种模式,
单 Reactor 单线程模型
服务端的 Reac ...
零、如何实现一个轻量级RPC框架?
零实现一个轻量级 RPC 框架-系列文章Github: https://github.com/DongZhouGu/XRpc
什么是 RPC?RPC,即 Remote Procedure Call(远程过程调用), 在计算机科学中已经存在了超过四十年时间,由于微服务风潮带来的热度,RPC 技术如今依旧被开发人员关注。RPC 出现的最初目的,就是为了让计算机能够跟调用本地方法一样去调用远程方法。RPC 可基于 HTTP 或 TCP 协议,Web Service 就是基于 HTTP 协议的 RPC,它具有良好的跨平台性,但其性能却不如基于 TCP 协议的 RPC。
为什么需要 RPC?
单一应用下,逻辑简单,用户较少,流量不大,所有的服务都在单体下,这种情况下并不需要 RPC。
当我们的系统访问量增大、业务增多时,我们会发现一台单机运行此系统已经无法承受。此时,我们可以将业务拆分成几个互不关联的应用,分别部署在各自机器上,以划清逻辑并减小压力。此时,我们也可以不需要 RPC,因为应用之间是互不关联的。
发现一些公共的业务逻辑需要抽离出来,组成独立的 service 应用部署在一些机 ...
Springboot-聊天室Websockt
引入依赖1234<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId></dependency>
WebSocket 配置类注册 WebSocket 扫描类到容器中(注册该对象主要用于扫描带有@ServerEndpoint 的类,如果使用外置的 tomcat 就不需要该对象)
12345678@Configurationpublic class WebSocketStompConfig { //这个bean的注册,用于扫描带有@ServerEndpoint的注解成为websocket ,如果你使用外置的tomcat就不需要该配置文件 @Bean public ServerEndpointExporter serverEndpointExporter(){ return new ServerEndpointExpo ...
Docker部署博客项目
后端打包参考SpringBoot+Maven多环境部署将后端项目打包
编写 Dockerfile 文件12345678# 该镜像需要依赖的基础镜像FROM java:8# 将当前目录下的jar包复制到docker容器的/目录下ADD myblog-0.0.1-SNAPSHOT.jar /blog.jar# 指定docker容器启动时运行jar包ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/blog.jar"]# 指定维护者的名字MAINTAINER dzgu
自动化脚本可以作为通用脚本来使用的模板脚本,只需改变其中的一些参数即可,具体执行流程为:停止旧服务->删除旧容器->删除旧镜像->打包新镜像->运行新镜像。
123456789101112131415161718192021#!/usr/bin/env bash#源jar路径SOURCE_PATH=/mydata/docker#docker 镜像/容器名字或者jar名字 这里都命名为这个SERVER_NAME ...