常见问题汇总(持续更新中)
你项目中用到了哪些设计模式在线程池的创建,Zookeeper客户端的创建使用到的单例模式,避免重复创建
创建序列化器,编解码器用到了工厂模式,根据用户配置创建不同的序列化方式
在实现不同序列化方式的时候用到了策略模式,把不同序列化方式封装成一个策略,实现统一接口
小程序项目中使用注解+AOP实现权限控制,本质是基于代理方法在方法调用前做拦截,用到了代理模式
在RPC框架中注册中心监听节点变化用到了观察者模式
Spring中用到了哪些设计模式Bean的创建是单例的,用到了单例模式
Bean的管理使用的BeanFactory,用到了工厂模式
Bean的注入用到了原型模式,每次注入新实例
通用逻辑的封装,比如JdbcTemplate,用到了模板方法模式
Spring事件监听机制用到了观察者模式
SpringMVC的拦截器、过滤器链用到了责任链模式
Bean的生命周期管理用到了状态模式
AOP用到了代理模式
SpringMVC的HandlerAdapter适配不同Controller用到了适配器模式
ES的基本原理ES中比较关键的概念有索引,相当于MySQL的表,文档,相当于表中的行,字段,相 ...
xxl-Job基础入门
分布式任务调度我们可以思考一下下面业务场景的解决方案:
某电商平台需要每天上午10点,下午3点,晚上8点发放一批优惠券
某银行系统需要在信用卡到期还款日的前三天进行短信提醒
某财务系统需要在每天凌晨0:10分结算前一天的财务数据,统计汇总
以上场景就是任务调度所需要解决的问题
任务调度是为了自动完成特定任务,在约定的特定时刻去执行任务的过程
为什么需要分布式调度使用Spring中提供的注解@Scheduled,也能实现调度的功能,在业务类中方法中贴上这个注解,然后在启动类上贴上@EnableScheduling注解
@Scheduled(cron = "0/20 * * * * ? ") public void doWork(){ //doSomething }
但是这种方式:
只能在一台机器上运行,如果程序或者系统出现异常就会导致功能不可用
在单机模式下,定时任务是没什么问题的。但当我们部署了多台服务,同时又每台服务又有定时任务时,若不进行合理的控制在同一时间,只有一个定时任务启动执行,定时执行的结果就可能存在混乱和错误了
原本 ...
项目常见问题梳理(持续更新中)
RPC项目为什么要做RPC项目目前的应用大部分都是分布式或者微服务架构,通常各个模块之间都是通过rpc来进行调用的,所以我认为自己写一个rpc项目可以更加深入的理解rpc的原理
然后在写rpc项目的过程中,学会了对Zookeeper和netty的使用,也学会了通信协议设计、序列化算法、服务注册与发现、负载均衡策略的设计和使用。
项目有什么难点,如何解决的
关于通信协议的实现和切换模块,我希望客户端和服务端支持http,socket和netty传输协议,并且根据配置自动切换。我的解决方案是首先定义了统一的接口RpcClient 和 RpcServer,然后实现其协议子类比如NettyRpcServer和HttpRpcServer,利用Spring Boot的 @ConditionalOnProperty和@ConditionalOnMissingBean 机制,支持配置项自动装配对应的协议实现
关于负载均衡模块的实现,就是服务调用时如何在多个服务节点直接选择一个合适的目标节点。我的解决方案是定义一个统一的接口LoadBalance,在此基础上扩展成随机、轮询和一致性哈希三种方法,使用SP ...
基于Netty的RPC框架实现
RPC又称远程过程调用(Remote Procedure Call),用于解决分布式系统中服务之间的调用问题。通俗地讲,就是开发者能够像调用本地方法一样调用远程的服务。
RPC框架一般必须包含三个组件,分别是客户端、服务端以及注册中心,一次完整的RPC调用流程一般为:
服务端启动服务后,将他提供的服务列表发布到注册中心(服务注册)
客户端会向注册中心订阅相关的服务地址(服务订阅)
客户端通常会利用本地代理模块 Proxy 向服务端发起远程过程调用,Proxy 负责将调用的方法、参数等数据转化为网络字节流
客户端从服务列表中根据负载均衡策略选择一个服务地址,并将数据通过网络发送给服务端
服务端得到数据后,调用对应的服务,然后将结果通过网络返回给客户端
虽然 RPC 调用流程很容易理解,但是实现一个完整的 RPC 框架设计到很多内容,例如服务注册与发现、通信协议与序列化、负载均衡、动态代理等
项目目标
实现基于Netty/Socket/Http三种方式进行网路通信
自定义消息协议,编解码器
五种序列化算法(JDK、JSON、HESSIAN、KRYO、PROTOS ...
Netty常见问题
什么是NettyNetty是一个基于Java NIO (Non-blocking I/O)的网络通信框架,它提供了高性能、可扩展性和可靠性的网络编程解决方案,是一个广泛应用于分布式系统的网络通信库
Netty有哪些核心组件Netty由三层结构构成:
网络通信层:有三个组件:Bootstrap、ServerBootstrap、Channel
Bootstrap负责客户端启动,连接指定服务器
ServerBootstrap负责服务器启动,监听指定端口
Channel是网络通信的载体
事件调度层:有EventLoopGroup、EventLoop
EventLoopGroup本质上是一个线程池,主要是负责接受IO请求,分配线程处理请求
EventLoop是具体的一个线程
服务编排层:ChannelPipline、ChannelHandler、ChannelHandlerContext
ChannelPipline负责将多个ChannelHandler组成一个链,可以看成一个流水线
ChannelHandler是对数据进行处理,可以看作成一道道工序
ChannelHandl ...
Netty优化
扩展序列化算法序列化,反序列化主要用在消息正文的转换上
序列化时,需要将Java对象变为要传输的数据(可以是byte[],json等,最终都需要变成byte[])
反序列化时,需要将传入的正文数据还原成Java对象,便于处理
Java自带的序列化,反序列化机制,核心代码如下:
// 反序列化byte[] body = new byte[bodyLength];byteByf.readBytes(body);ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(body));Message message = (Message) in.readObject();message.setSequenceId(sequenceId);// 序列化ByteArrayOutputStream out = new ByteArrayOutputStream();new ObjectOutputStream(out).writeObject(message);byte[] bytes = out.toByteAr ...
Netty进阶篇
黏包和半包前置知识滑动窗口
TCP以一个段(segment)为单位,每发送一个段就需要进行一次确认应答(ack)处理,但如果这么做,缺点是包的往返时间越长性能就越差
为了解决此问题,引入了窗口概念,窗口大小即决定了无需等待应答而可以继续发送的数据最大值
窗口实际就起到一个缓冲区的作用,同时也能起到流量控制的作用
图中深色的部分即要发送的数据,高亮的部分即窗口
窗口内的数据才允许被发送,当应答未到达前,窗口必须停止滑动
如果 1001~2000 这个段的数据 ack 回来了,窗口就可以向前滑动
接收方也会维护一个窗口,只有落在窗口内的数据才能允许接收
MSS限制链路层对一次能够发送的最大数据有限制,这个限制称之为 MTU(maximum transmission unit),不同的链路设备的 MTU 值也有所不同,例如
以太网的 MTU 是 1500
FDDI(光纤分布式数据接口)的 MTU 是 4352
本地回环地址的 MTU 是 65535 - 本地测试不走网卡
MSS 是最大段长度(maximum segment size),它是 MTU 刨去 tcp 头和 ...
Netty基础入门
Netty is an asynchronous event-driven network application frameworkfor rapid development of maintainable high performance protocol servers & clients.
Netty是一个异步的、基于事件驱动的网络应用框架,用于快速开发可维护、高性能的网络服务器和客户端
HelloWorld开发一个简单的服务器端和客户端
客户端向服务器端发送HelloWorld
服务器仅接收,不返回
加入依赖
<dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.100.Final</version></dependency>
服务器端new ServerBootstrap() .group(new NioEventLo ...
Java网络IO
java中的IO可以分为BIO(blocking io,阻塞IO)、NIO(non-blocking io,非阻塞IO)、AIO(Asynchronous IO,异步IO)
IO中的三大组件Channel与Bufferchannel有一点类似于stream,它就是读写数据的双向通道,可以从 channel 将数据读入 buffer,也可以将 buffer 的数据写入 channel,而之前的 stream 要么是输入,要么是输出,channel 比 stream 更为底层
graph LRchannel --> bufferbuffer --> channel
常见的Channel有
FileChannel:用于对文件进行读写操作的通道,支持随机访问和映射文件
DatagramChannel:用于基于UDP进行无连接数据发送和接收的通道
SocketChannel:用于基于TCP的客户端网络通信,支持非阻塞连接与数据传输
ServerSocketChannel用于监听TCP连接请求的服务端通道,生成SocketChannel
buffer则用来缓冲读写数据,常见的bu ...
Zookeeper基础入门
Zookeeper是一个分布式的、开源的分布式应用程序的协调服务,基于ZAB协议(ZooKeeper Atomic Broadcast)实现分布式数据一致性
Zookeeper内部的数据模型类似文件系统的树形结构(ZNode),每个节点可存储不超过1MB的数据
Zookeeper提供的主要功能包括:
服务注册与发现
配置管理
分布式锁
集群管理
Zookeeper数据模型ZooKeeper是一个树形目录服务,其数据模型和Unix的文件系统目录树很类似,拥有一个层次化结构
这里面的每一个节点都被称为ZNode,每个节点上都会保存自己的数据和节点信息
节点可以拥有子节点,同时也允许少量(1MB)数据存储在该节点之下(可以通过jute.maxbuffer修改单个节点数据大小限制)
节点可以分为四大类:
PERSISTENT:持久化节点,创建后永久存在(除非显式删除)
EPHEMERAL:临时节点 -e,会话结束后自动删除(用于实现服务注册与心跳检测)
PERSISTENT_SEQUENTIAL:持久化顺序节点 -s,顺序节点的名称后面会自动追加单调递增序号(如 /lock/seq-00 ...