引入 Shiro + JWT ,提供权限认证服务。
设计在现在实现的 API 网关中,当接收 HTTP 请求以后,开始调用对应的 RPC 接口前,其实还应该做一步权限验证。也就是当前调用的 HTTP 接口是否含有网关授予的 Token 信息,这个 Token 是否在有效期范围等控制,这样才能保证一个 HTTP 的调用和返回结果是安全可靠的。
关于网关中权限的校验会使用到 Shiro + JWT, 同时还要提供单独的 Handler 来处理 Netty 中的通信对信息的校验处理。但鉴于这部分属于两块功能,所以本章只先完成关于 Shiro + JWT 部分。
傻傻分不清之 Cookie、Session、Token、JWT - 掘金
什么是 Cookie
HTTP 是无状态的协议(对于事务处理没有记忆能力,每次客户端和服务端会话完成时,服务端不会保存任何会话信息):每个请求都是完全独立的,服务端无法确认当前访问者的身份信息,无法分辨上一次的请求发送者和这一次的发送者是不是同一个人。所以服务器与浏览器为了进行会话跟踪(知道是谁在访问我),就必须主动的去维护一个状态,这个状态用于告知服务端前后两 ...
将 Session 会话中获取连接源,并通过连接源执行泛化调用的整个执行过程作为独立的模块抽离出来。
设计
之前对于 HTTP 请求到网络协议转换后,就是会话流程的处理。但在会话流程中还有些内容过于冗余,这些内容就是对数据源(RPC)的调用时入参和出参的封装,它们应该被提取到一个专门的类来处理,这样才能更加方便的管理。
会话的职责是负责串联上下文,执行器的职责是负责对数据源的调用信息处理。
实现Mapping部分:
GenericReference:invoke返回值变化为 Object ,现在不单单只返回一个 String 了。
DataSource部分:
无变动
Session部分:
DefaultGatewaySession中的执行 RPC 逻辑拆分到执行器
Executor部分:
新增 Executor 接口,声明 execute 方法
新增 BaseExecutor 抽象类,实现 Executor 接口的 execute 方法,将原来会话中的参数封装的逻辑移入这里,并调用定义的抽象方法 doExec 实现不同的执行逻辑
新增 SimpleExecut ...
项目笔记
未读解析 HTTP 请求,包括 GET/POST ,以及应对不同 Content-Type 的参数处理。
设计
从网络请求到会话,需要对 GET/POST 的请求,以及请求的参数类型 Content-Type 做细化的参数解析操作。同时按照 RPC 泛化调用的入参方式,将解析的参数封装处理。
实现Mapping部分:
IGenericReference:invoke 方法参数变化,现在的参数变成了一个 Map,就是一个参数名和参数值的映射
MappedMethod:加入对于 POST 请求类型的处理逻辑
DataSource部分:
无变动
Session部分:
GatewaySession新增 post 方法 ,暂时还是用 get 方法实现
Socket部分:
新增了请求解析器,根据 GET 和 POST 进行参数解析,先解析 Header中的 Content-Type ,然后对应 POST 中不同的 Content-Type 进行不同的解析操作
Type部分:
新增 SimpleTypeRegistry 类型注册器:用于判断 parameterType, 如 ...
拆解Dubbo、HTTP调用,抽象为数据源服务,便于后续功能的扩展和使用
设计
API 网关的实现对于RPC接口的泛化调用,类似于ORM框架中对数据库的调用。所以也可以把 RPC 抽象成一种连接资源,做数据源的管理和池化的实现。这样既可以方便我们扩展新的连接方式,比如各类厂商的 RPC 框架,或者 HTTP 服务等,还可以通过SPI的方式进行自定义连接资源扩展,以适应不同场景的诉求。这也是抽象连接为数据源的设计目的。
实现Mapping部分:
无变动。
DataSource部分:
Connection:连接接口,提供 execute 执行方法
DataSource:数据源接口,提供获取连接方法
DataSourceFactory:数据源工厂,用来新建数据源
DataSourceType:枚举,不同的数据源类型,目前有 Dubbo 和 HTTP
UnpooledDataSource:数据源的实现类,并根据不同的数据源类型获取连接
UnpooledDataSourceFactory:为数据源提供配置,新建数据源;
DubboConnection/HTTPConnectio ...
项目笔记
未读通过分治重构会话流程,细化网络协议、会话、绑定、映射和泛化调用的关系。
设计
因为我们要继续扩展新的功能,而上一章功能实现的逻辑分层结构不易于扩展,所以需要进行重构处理。重构点包括;
拆分session包下会话业务逻辑部分和网络通信部分,做功能实现的隔离。
拆分 bind 包下代理和对RPC接口的泛化调用,这里你可以把RPC当做一种可连接资源,而这种连接资源也不是只有 RPC 一种,同时也因为 RPC 的泛化调用是一种通用方法,井不需要与逻辑绑定,所以它也应该被拆分出来。
实现Mapping 模块:
MapperMethod:switch处理不同的请求,调用GatewaySession中的方法执行具体内容(目前只提供了 get 接口方法实现)
MapperProxy:延续之前的处理方式,这块是一个Interceptor,用来调用执行后续方法,从直接调用 dubbo 变成了调用 MapperedMethod,也就是根据请求类型从 GatewaySession 执行对应的方法
MapperProxyFactory:同之前的 GenericReferenceProxyFactory ...
为网关接口绑定对应的 RPC 服务,建立代理关系封装 RPC 泛化调用。这样调用网关接口就会调用到对应的 RPC 服务接口上并返回对应的数据。
设计对于中间件框架的实现,往往都离不开代理的操作,因为需要使用代理用逻辑封装行为。例如你原本是通过硬编码调用一个接口,那么现在因为所有的行为都被提炼到中间件中控制,那么对于接口的调用就不在一个而是一堆。而对于这样一堆接口的调用,它们是有共性的,比如可以统一使用 Java 反射获取到方法名、入参、出参等等信息,再根据这些信息做代理逻辑包装,让每一个接口的调用都被中间件处理。
那么本章要实现的就是把来自网关的HTTP请求,转换到RPC调用上,这里就涉及到了RPC所提供的泛化调用,按照对应的泛化调用的逻辑,提供对应的接口和方法以及入参信息就可以拿到最终的结果。
文档:dubbo 泛化调用
如何把 HTTP 地址中的接口方法与 RPC 对应的服务建立起一种关联关系,这样才能满足在调用 HTTP 网关接口时,调用到对应的 RPC 服务上。
HTTP 经过网关调用到 RPC 中间的执行逻辑就是把两个模块用绑定的方式建立起连接,生成一个代理对象。代理对象 ...
运用 Netty 对 HTTP 请求信息的协议转换,构建网关会话服务,简单响应 HTTP 请求信息到页面。
设计
HTTP 请求到 API 网关,网关再去调用到对应的RPC服务,那么这样一个流程一次请求,可以把它抽象为是做了一次会话操作。
之所以称之为会话,是因为一次 HTTP 请求,就要完成;建立连接、协议转换、方法映射、泛化调用、返回结果等一系列操作。而在这些操作过程中的各类行为处理。
此外之所以要单独创建出一个 api-gateway-core 的工程,是因为我们要把这个工程独立于各种容器,例如它并不是直接与 SpringBoot 一起开发,那样会让组件失去灵活性。它的存在更应该像是一个 ORM 框架,可以独立使用,谁也都可以结合。
实现
BaseHandler 数据处理器基础类123456789101112131415161718192021222324252627282930package cn.ray.gateway.session;import io.netty.channel.Channel;import io.netty.channel.ChannelHandle ...
扩展序列化算法序列化,反序列化主要用在消息正文的转换上
序列化时,需要将 Java 对象变为要传输的数据(可以是 byte[],或 json 等,最终都需要变成 byte[])
反序列化时,需要将传入的正文数据还原成 Java 对象,便于处理
目前的代码仅支持 Java 自带的序列化,反序列化机制,核心代码如下
1234567891011// 反序列化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(messa ...
启动流程12345678910111213141516171819202122//1 netty 中使用 NioEventLoopGroup (简称 nio boss 线程)来封装线程和 selectorSelector selector = Selector.open(); //2 创建 NioServerSocketChannel,同时会初始化它关联的 handler,以及为原生 ssc 存储 configNioServerSocketChannel attachment = new NioServerSocketChannel();//3 创建 NioServerSocketChannel 时,创建了 java 原生的 ServerSocketChannelServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.configureBlocking(false);//4 启动 nio boss 线程执行接下来的操作//5 注册(仅关联 selector 和 N ...
项目笔记
未读相关资料重点理解MapReduce的机制
MapReduce(2004)翻译
MapReduce 深入浅出
思路首先看一下 Lab 提供的 MapReduce 执行流程图
可以看出 MapReduce 的大致流程:启动一个Master( Coordinator 协调者)分配多个任务给 worker 做 Map 任务。
然后 Worker 完成 Map 任务后返回中间值一组 KV ,接着协调者再将这些 KV 分发给后继的Worker 根据 KV 进行 Reduce 任务,最后对 Reduce 进行一个总的处理进行返回。
实现完成 worker 与 Coordinator 之间的交互,处理 map 任务从实现来看我们可以先完成 worker 与Coordinator之间的交互,首先可以来看看给的 RPC 例子:首先运行 main/mrworker.go 会进入到 mr/Worker 的这个方法中。
可以在这个方法中调用RPC的例子方法:CallExample()。
然后 CallExample() 这个方法中会有一行:
1ok := call("Coordinator. ...