<返回更多

如何用Netty写一个高性能的分布式服务框架?

2021-06-23    技术联盟总坛
加入收藏

家纯 阿里技术

如何用Netty写一个高性能的分布式服务框架?

 

一 什么是 Netty? 能做什么?

 

 

 

 

设计一个分布式服务框架

 

1 Architecture

如何用Netty写一个高性能的分布式服务框架?

 

2 远程调用的流程

 

 

 

 

 

 

 

以上流程对方法调用者是透明的,一切看起来就像本地调用一样。

 

3 远程调用客户端图解

如何用Netty写一个高性能的分布式服务框架?

 

重要概念:RPC三元组 <ID,Request,Response>。

 

PS: 若是 netty4.x 的线程模型,IO Thread(worker) —> Map<InvokeId,Future> 代替全局 Map 能更好的避免线程竞争。

 

4 远程调用服务端图解

如何用Netty写一个高性能的分布式服务框架?

 

5 远程调用传输层图解

如何用Netty写一个高性能的分布式服务框架?

 

6 设计传输层协议栈

 

协议头

如何用Netty写一个高性能的分布式服务框架?

 

协议体

 

1)metadata: <group,providerName,version>

 

2)methodName

 

3)parameterTypes[] 真的需要吗?

 

(a)有什么问题?

 

 

(b)能解决吗?

 

 

(c)args[]

 

(d)其他:traceId,AppName…

 

三 一些Features&好的实践&压榨性能

 

1 创建客户端代理对象

 

1)Proxy 做什么?

 

 

2)有哪些创建 Proxy 的方式?

 

 

3)要注意的:

 

 

4)推荐的(bytebuddy):

如何用Netty写一个高性能的分布式服务框架?

 

2 优雅的同步/异步调用

 

 

3 单播/组播

 

 

4 泛化调用

 

 

5 序列化/反序列化

 

协议 header 标记 serializer type,同时支持多种。

 

6 可扩展性

 

Java SPI:

 

 

7 服务级别线程池隔离

 

要挂你先挂,别拉着我。

 

8 责任链模式的拦截器

 

太多扩展需要从这里起步。

 

9 指标度量(Metrics)

 

10 链路追踪

 

OpenTracing

 

11 注册中心

 

12 流控(应用级别/服务级别)

 

要有能方便接入第三方流控中间件的扩展能力。

 

13 Provider线程池满了怎么办?

如何用Netty写一个高性能的分布式服务框架?

 

14 软负载均衡

 

1)加权随机 (二分法,不要遍历)

如何用Netty写一个高性能的分布式服务框架?

 

2)加权轮训(最大公约数)

如何用Netty写一个高性能的分布式服务框架?

 

3)最小负载

 

4)一致性 hash (有状态服务场景)

 

5)其他

 

注意:要有预热逻辑。

 

15 集群容错

 

1)Fail-fast

 

2)Failover

 

异步调用怎么处理?

 

 

如何用Netty写一个高性能的分布式服务框架?

 

 

如何用Netty写一个高性能的分布式服务框架?

 

3)Fail-safe

 

4)Fail-back

 

5)Forking

 

6)其他

 

16 如何压榨性能(Don’t trust it,Test it)

 

1)ASM 写个 FastMethodAccessor 来代替服务端那个反射调用

如何用Netty写一个高性能的分布式服务框架?

 

2)序列化/反序列化

 

在业务线程中序列化/反序列化,避免占用 IO 线程:

 

 

 

选择高效的序列化/反序列化框架:

 

 

选择只是第一步,它(序列化框架)做的不好的,去扩展和优化之:

 

 

 

 

 

 

3)IO 线程绑定 CPU

 

4)同步阻塞调用的客户端和容易成为瓶颈,客户端协程:

 

 

name

description

kilim

编译期间字节码增强

quasar agent

动态字节码增强

ali_wisp

ali_jvm 在底层直接实现

 

5)Netty Native Transport & PooledByteBufAllocator:

 

 

6)尽快释放 IO 线程去做他该做的事情,尽量减少线程上下文切换。

 

四 Why Netty?

 

1 BIO vs NIO

如何用Netty写一个高性能的分布式服务框架?

 

2 Java 原生 NIO API 从入门到放弃

 

复杂度高

 

 

稳定性差,坑多且深

 

 

 

NIO代码实现方面的一些缺点

 

1)Selector.selectedKeys() 产生太多垃圾

 

Netty 修改了 sun.nio.ch.SelectorImpl 的实现,使用双数组代替 HashSet 存储来 selectedKeys:

 

 

Nio 的代码到处是 synchronized (比如 allocate direct buffer 和 Selector.wakeup() ):

 

 

 

 

2)fdToKey 映射

 

 

 

 

3)Selector在linux 平台是 Epoll LT 实现

 

 

4)Direct Buffers 事实上还是由 GC 管理

 

 

 

 

 

五 Netty 的真实面目

 

1 Netty 中几个重要概念及其关系

 

EventLoop

 

 

 

 

 

Boss: mainReactor 角色,Worker: subReactor 角色

 

 

 

 

 

 

2 Netty4 Thread Model

如何用Netty写一个高性能的分布式服务框架?

 

3 ChannelPipeline

如何用Netty写一个高性能的分布式服务框架?

 

4 Pooling&reuse

 

PooledByteBufAllocator

 

 

 

 

Recycler

 

 

 

 

 

 

5 Netty Native Transport

 

相比 Nio 创建更少的对象,更小的 GC 压力。

 

针对 linux 平台优化,一些 specific features:

 

 

 

 

 

6 多路复用简介

 

select/poll

 

 

 

 

epoll

 

 

 

7 稍微深入了解一点 Epoll

 

LT vs ET

 

概念:

 

 

可读:

 

 

可写:

 

 

图解:

如何用Netty写一个高性能的分布式服务框架?

 

epoll 三个方法简介

 

1)主要代码:
linux-2.6.11.12/fs/eventpoll.c

 

2)int epoll_create(int size)

 

创建 rb-tree(红黑树)和 ready-list (就绪链表):

 

 

 

3)int epoll_ctl(int epfd,int op,int fd,struct epoll_event *event)

 

 

4)int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout)

 

 

epoll 的数据结构

如何用Netty写一个高性能的分布式服务框架?

 

epoll_wait 工作流程概述

 

对照代码:
linux-2.6.11.12/fs/eventpoll.c:

 

1)epoll_wait 调用 ep_poll

 

 

2)文件描述符 fd 的 events 状态改变

 

 

3)ep_poll_callback 被触发

 

 

4)执行 ep_events_transfer 函数

 

 

 

5)执行 ep_send_events 函数

 

 

 

8 Netty 的最佳实践

 

1)业务线程池必要性

 

 

2)WriteBufferWaterMark

 

 

3)重写 MessageSizeEstimator 来反应真实的高低水位线

 

 

4)注意EventLoop#ioRatio的设置(默认50)

 

 

5)空闲链路检测用谁调度?

 

 

 

6)使用ctx.writeAndFlush还是channel.writeAndFlush?

 

 

 

7)使用Bytebuf.forEachByte() 来代替循环 ByteBuf.readByte()的遍历操作,避免rangeCheck()

 

8)使用CompositeByteBuf来避免不必要的内存拷贝

 

 

9)如果要读一个int,用Bytebuf.readInt(),不要Bytebuf.readBytes(buf,0,4)

 

 

10)配置


UnpooledUnsafeNoCleanerDirectByteBuf来代替jdk的DirectByteBuf,让netty框架基于引用计数来释放堆外内存

 

io.netty.maxDirectMemory:

 

 

 

0:不使用cleaner,并且这个参数将直接限制netty的最大direct memory size,(jdk的direct memory size是独立的,不受此参数限制)。

 

11)最佳连接数

 

 

12)使用PooledBytebuf时要善于利用
-Dio.netty.leakDetection.level 参数

 

 

 

 

 

 

13)Channel.attr(),将自己的对象attach到channel上

 

 

 

9 从 Netty 源码中学到的代码技巧

 

1)海量对象场景中

AtomicIntegerFieldUpdater --> AtomicInteger

 

 

 

2)FastThreadLocal,相比jdk的实现更快

 

 

3)IntObjectHashMap / LongObjectHashMap …

 

 

4)RecyclableArrayList

 

 

5)JCTools

 

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>