性能调优🔥
# 背景
自建物联网平台最关键的是与设备进行交互。设备采集到的传感器信息是整个物联网核心价值所在。所以就要求在设计物联网平台时,达到高性能与高可用。要能满足海量设备连接与信息交互。
# 高性能
为了实现平台与设备交互的高性能,兼顾消息的稳定性(不能丢失数据)。主要的使用到方法:
✅IO多路复用
✅异步
✅池化思想
# 信息接收
背景
起初,没人在意设备与平台的信息交互。这不过是一条简单的报文。十几个字节的信息。在浩瀚的网络上翻不起什么涟漪。
- 设备与平台交互,主要是自家设计的协议。
- 底层采用TCP方式,16进制进行通信。
- 平台作为暴露端口,设备通过端口连接到平台。连接成功后,通过端口进行信息交互。
基于这种模式的连接方式。首先脑海中就想起了那个框架 -- Netty
。
Netty是 一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。
基于优秀的设计,数据从设备侧通过网络传输到平台这一层,完全不需要我的考虑。只需要使用Netty
开发一个ServerBootStrap
后,通过简单的配置:
✅ 设置两个线程组boosGroup
和workerGroup
✅ 设置服务端通道实现类型
✅ 设置线程队列得到连接个数
✅ 设置保持活动连接状态
✅ 使用匿名内部类的形式初始化通道对象
✅ 绑定端口号,启动服务端
✅ 对关闭通道进行监听
✅ 最后在给一个优雅的关闭。 齐活🤣
public class MyServer {
public static void main(String[] args) throws Exception {
//创建两个线程组 boosGroup、workerGroup
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//创建服务端的启动对象,设置参数
ServerBootstrap bootstrap = new ServerBootstrap();
//设置两个线程组boosGroup和workerGroup
bootstrap.group(bossGroup, workerGroup)
//设置服务端通道实现类型
.channel(NioServerSocketChannel.class)
//设置线程队列得到连接个数
.option(ChannelOption.SO_BACKLOG, 128)
//设置保持活动连接状态
.childOption(ChannelOption.SO_KEEPALIVE, true)
//使用匿名内部类的形式初始化通道对象
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//给pipeline管道设置处理器
socketChannel.pipeline().addLast(new MyServerHandler());
}
});//给workerGroup的EventLoop对应的管道设置处理器
System.out.println("server is on call...");
//绑定端口号,启动服务端
ChannelFuture channelFuture = bootstrap.bind(6666).sync();
//对关闭通道进行监听
channelFuture.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 异步处理
上一步中已经接收到了消息。此时就需要马上处理数据。为了不长时间的业务操作导致Handler
阻塞。此处,我一拿到消息就是用默认的Netty中的taskQueue
异步处理。对消息进行校验、分类等操作。最后将处理好的信息推送的到Kafka
中。
public class MyServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//获取到线程池eventLoop,添加线程,执行
ctx.channel().eventLoop().execute(new Runnable() {
@Override
public void run() {
try {
// 长时间操作,不至于长时间的业务操作导致Handler阻塞
// do something right here......
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 总结
Netty本身作为一款高性能的网络处理框架。其中有太多值得学习的东西。IO多路复用、Reactor模式、线程模型、零拷贝、异步模型等等。学习优秀的框架解决问题的思路,然后运用在自己的业务中。那种通过自己理解给出的解决方案才是成长的积累。
# 高可用
现代化架构一般采用微服务分布式架构。可以通过部署多套设备交互服务,然后用负载均衡软件满足要求。一般而言。可选的负载均衡软件主要是3款。Nginx
、LVS
、Haproxy
。具体三者对比可以参见: LVS、nginx、Haproxy对比 (opens new window), LVS、Nginx和HAProxy区别 (opens new window)。针对物联网场景一般使用Haproxy
。
一款使用 C 语言编写的自由及开放源代码软件,其提供高可用性、负载均衡,以及基于 TCP 和 HTTP 的应用程序代理,它是免费、快速并且可靠的一种解决方案。
# HAProxy简介
HAProxy 是一款提供高可用性、负载均衡以及基于TCP(第四层)和HTTP(第七层)应用的代理软件,支持虚拟主机,它是免费、快速并且可靠的一种解决方案。 HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。HAProxy运行在时下的硬件上,完全可以支持数以万计的 并发连接。并且它的运行模式使得它可以很简单安全的整合进您当前的架构中, 同时可以保护你的web服务器不被暴露到网络上。
HAProxy 实现了一种事件驱动、单一进程模型,此模型支持非常大的并发连接数。多进程或多线程模型受内存限制 、系统调度器限制以及无处不在的锁限制,很少能处理数千并发连接。事件驱动模型因为在有更好的资源和时间管理的用户端(User-Space) 实现所有这些任务,所以没有这些问题。此模型的弊端是,在多核系统上,这些程序通常扩展性较差。这就是为什么他们必须进行优化以 使每个CPU时间片(Cycle)做更多的工作。
HAProxy 支持连接拒绝 : 因为维护一个连接的打开的开销是很低的,有时我们很需要限制攻击蠕虫(attack bots),也就是说限制它们的连接打开从而限制它们的危害。 这个已经为一个陷于小型DDoS攻击的网站开发了而且已经拯救了很多站点,这个优点也是其它负载均衡器没有的。
HAProxy 支持全透明代理(已具备硬件防火墙的典型特点): 可以用客户端IP地址或者任何其他地址来连接后端服务器. 这个特性仅在Linux 2.4/2.6内核打了cttproxy补丁后才可以使用. 这个特性也使得为某特殊服务器处理部分流量同时又不修改服务器的地址成为可能。
# 性能
HAProxy借助于OS上几种常见的技术来实现性能的最大化。
单进程、事件驱动模型显著降低了上下文切换的开销及内存占用。
O(1)事件检查器(event checker)允许其在高并发连接中对任何连接的任何事件实现即时探测。
在任何可用的情况下,单缓冲(single buffering)机制能以不复制任何数据的方式完成读写操作,这会节约大量的CPU时钟周期及内存带宽;
借助于Linux 2.6 (>= 2.6.27.19)上的splice()系统调用,HAProxy可以实现零复制转发(Zero-copy forwarding),在Linux 3.5及以上的OS中还可以实现零复制启动(zero-starting);
内存分配器在固定大小的内存池中可实现即时内存分配,这能够显著减少创建一个会话的时长;
树型存储:侧重于使用作者多年前开发的弹性二叉树,实现了以O(log(N))的低开销来保持计时器命令、保持运行队列命令及管理轮询及最少连接队列;
优化的HTTP首部分析:优化的首部分析功能避免了在HTTP首部分析过程中重读任何内存区域;
精心地降低了昂贵的系统调用,大部分工作都在用户空间完成,如时间读取、缓冲聚合及文件描述符的启用和禁用等;
所有的这些细微之处的优化实现了在中等规模负载之上依然有着相当低的CPU负载,甚至于在非常高的负载场景中,5%的用户空间占用率和95%的系统空间占用率也是非常普遍的现象,这意味着HAProxy进程消耗比系统空间消耗低20倍以上。因此,对OS进行性能调优是非常重要的。即使用户空间的占用率提高一倍,其CPU占用率也仅为10%,这也解释了为何7层处理对性能影响有限这一现象。由此,在高端系统上HAProxy的7层性能可轻易超过硬件负载均衡设备。
在生产环境中,在7层处理上使用HAProxy作为昂贵的高端硬件负载均衡设备故障故障时的紧急解决方案也时长可见。硬件负载均衡设备在“报文”级别处理请求,这在支持跨报文请求(request across multiple packets)有着较高的难度,并且它们不缓冲任何数据,因此有着较长的响应时间。对应地,软件负载均衡设备使用TCP缓冲,可建立极长的请求,且有着较大的响应时间。