HTTPS是大势所趋?看腾讯专家通过Epoll+OpenSSL在高并发压测机器人中支持https

WeTest 导读

用epoll编写一个高并发网络程序是很常见的任务,但在epoll中加入ssl层的支持则是一个不常见的场景。腾讯WeTest服务器压力测产品,在用户反馈中收到了不少支持https协议的请求。基于此,本文介绍了在基于epoll的高并发机器人框架中加入openssl,实现对https支持时的基本实现思路。

一、背景

2014年,谷歌在其官方博客中发布公告称,为了打造更安全的互联网环境,谷歌搜索引擎将尝试把“是否使用安全加密”(HTTPS)作为搜索排名算法中的一个参考因素,使用加密技术的网站将得到更多的展示机会,排名相对同类网站也更有优势。面对运营商的http劫持,广告嵌入,将产品页面重定向到其他页面,http站点通常束手无策。所以仅仅是为了加密流量,https的部署也将成为大势所趋。

腾讯WeTest服务器性能测试原本的简单模式,主要针对以http协议为主的轻量级场景(游戏业务一般会采用更复杂的协议)。而在上线之后,收到了不少需要https测试的用户反馈,由此决定在我们使用的压测框架中加入https支持。

腾讯WeTest服务器性能测试是一个基于epoll的高并发机器人网络行为模拟框架。其中的网络传输模块,是用单线程epoll的多路复用方式,将多个机器人和服务器的交互包进行非阻塞高速转发。配合以Linux系统层面的一些配置优化,就可以达到单进程几千的机器人数量。

后台开发同学,一般在自己的web服务器中加https的配置相对常见,但自己到socket层去写https的代码实现,这个需求还真不太多。动手之前,我们调研了https层可用的库,最常见的就是OpenSSL了。像curl也有https的相应支持,不过考虑到要在tcp socket(epoll)这一层实现,还是选择了OpenSSL。

二、OpenSSL

在介绍OpenSSL之前,首先要介绍下https。https是什么?https就是http+tls/ssl(下文简称ssl)。从网络协议的层面来说,tcp是传输层协议,http是应用层协议,ssl就是为了给应用层的http报文加密,专门加在tcp和http之间的一层安全协议。网络上对https协议进行介绍的好文很多,如:http://www.cnblogs.com/LittleHann/p/3741907.html

,详细阐述了https的原理,这里就不再赘述。

OpenSSL就是在常用的socket层连接建好之后,完成ssl层的连接建立、收发包、连接释放,其实调用的基本思路还是很清晰的。我们以本文中要实现的client侧为例,如下图所示:
这里写图片描述

可以看到,就是在普通的socket建立好tcp连接后,再用SSL_connect建立ssl层的连接。然后用SSL_read/SSL_write替代recv/send进行收发数据,并在close socket的前后释放ssl层的资源即可。

由于已经实现了基于epoll的客户端数据收发和http协议的解析,所以这两者都不是本文的重点——下文主要介绍的是在epoll的框架中使用openssl收发数据时,需要注意的地方。

三、全双工实现

看到这个标题,肯定有同学会纳闷:tcp本来不就是全双工的么,https是在tcp层之上的,怎么还会单独拎出这个来说?没错,tcp是全双工的,但openssl的实现,不代表你能像普通socket一样在收发两个通道上随意操作。

要点1:OpenSSL并发读写,是不安全的

其实OpenSSL官方的文档上还没找到直接的话术指明同一个SSL不能两个线程并发读写,但实际上,外网上、km上都有文章说在多线程并发情况下读写会引起程序崩溃。想来是SSL对象内部实现中,维护了共享的状态变量或者缓存区之类的资源,并发读写时会改坏数据导致崩溃。可以通过初始化时设置加锁回调的方式来避免(http://linux.die.net/man/3/crypto_set_locking_callback),但锁终究对性能有不小的影响。

不过gaps现有的实现是单进程的,即单进程中通过epoll完成了多个机器人连接的收发数据,所以并不存在多线程并发的问题,也无需加锁。由此,小标题的“全双工实现”其实更严格说是”单进程情况下读写互不干扰的双工实现“。

要点2:OpenSSL的建链、收包、发包接口,其是否阻塞都随socket本身属性而变,所以OpenSSL可以非阻塞使用

在我们的场景下,用epoll来维护机器人的并发建连接和收发包,当然希望任何一个动作都是非阻塞的,这样才能将多路复用的功效发挥到极致。那现在加了个ssl2进去,是否还能保持这一点?答案是能。所以,这里的要点是,OpenSSL的建立连接、收包、发包,都可以是非阻塞的。

建立连接不用上图中的SSL_connect,而用SSL_do_handshake。这样,如果socket本身设置为非阻塞的,那这个操作也就不会阻塞,而是有三种返回可能:
这里写图片描述

1)返回0:

意味着ssl层的交互阻塞了。直观地去理解,虽然这时候tcp已经连好了,但总要去收发些握手数据什么的来建立ssl层连接吧,而这个过程收发数据阻塞了。此时,用SSL_get_error()可以获取具体的错误码:若是SSL_ERROR_WANT_READ或SSL_ERROR_WANT_WRITE,就在epoll中关注该连接的可读或可写事件,并在事件被触发时接着调用SSL_do_handshake,直到返回下面的1。

2)返回1:

ssl层建链数据交互完成,可以开始收发业务数据了

3)<0:

协议或连接层各种异常出错,不再详述。

非阻塞建立SSL连接的过程如图所示:
这里写图片描述

建链之后,就是收发数据了。由于socket为非阻塞,所以收发数据的函数SSL_read、SSL_write一样会非阻塞。他们的参数和普通的recv/send等读写类函数很像,就是传入buff和length这些。需要注意的在于,和SSL_do_handshake一样,如果返回值大于0,表示成功收发了业务层数据;如果返回值等于0,则需要判断下错误码是不是SSL_ERROR_WANT_READ或SSL_ERROR_WANT_WRITE,即读写阻塞了。

发包,即发送一个请求到http服务器的逻辑如下图:
这里写图片描述

可以看出,发包的逻辑和普通的使用epoll发包的逻辑大概相同,区别在于以下几点:

1)SSL_write替代了普通的send

2)SSL_write也会阻塞。只是,我们这里只关注写阻塞(即图中的错误码为SSL_ERROR_WANT_WRITE),然后加入epoll,关注socket的可写事件。

上面的第2点就是openSSL比较奇葩的一个地方了:调用SSL_write发包,可能返回的是一个SSL_ERROR_WANT_READ,即发包可能阻塞在读操作!无法理解吧。其实这个是因为在http的底层,会有一个重协商的过程,这个过程,相当于在业务数据正在单向地收或发的时候,突然在ssl链路层要去交互协议数据,重建链接了——那这个时候,重协商协议数据交互是双方的,client可能刚好在recv协议数据时被阻塞了,那就只能乖乖地等socket可读了——SSL_write在这种情况下,会返回一个SSL_ERROR_WANT_READ,等待可读。而下次可读事件发生时,还需要重复调用SSL_write,直到SSL_write成功……是不是有点奇怪,epoll告知我们socket可读了,我们居然要对socket调用写操作……

重协商的原理网上也有很多,这里不详述。只是,我们在全双工的模式下,对于SSL_write操作,只认为写阻塞是正常的!一旦因为重协商发生而产生读阻塞,我们就认为链路出现问题了——否则,无法真正实现收发互不考虑的全双工,这个会在半双工的时候具体介绍。

收包,即接收服务器侧返回的http响应的逻辑如下图:
这里写图片描述

可以看到,收包的逻辑和发包类似,也是有可能会因为重协商产生写阻塞,我们在全双工实现的做法,一样是认为出错。

四、加入半双工开关——重协商考虑

要点3:当SSL_read或SSL_write阻塞时,需要在SSL对象上重复调用该操作直到收发完成

要点3正是我们上面提到的奇葩之处。这也是在OpenSSL的官方文档中说明了的:
这里写图片描述

所以,我们如果需要真正支持重协商,就必须有一种半双工的实现——这种实现会在收发包阻塞在对应的操作后,记录一个中间状态,不处理当前不期望的收或发,直到之前被阻塞的操作完成。这种情况下,相当于对这个自定义的状态维护了一个状态机。由于实际实现非常复杂,所以代码细节就不在这里贴了。概括一下,大概是下面的这个状态机转移图和一些要点:
这里写图片描述

如上图:

1)“正常状态”可以认为连接当前是空闲的,不需要收发数据;

2)正常态下有客户端数据要发送,则调用SSL_write接口,如果阻塞,则会进入图左的两个状态;

3)正常态下epoll提示有服务端返回的数据可读,则调用SSL_read接口,如果阻塞,则会进入图右的两个状态;

4)在外侧的四种状态下,不是当前期望的操作,都不会处理:如阻塞在等待读/写时,epoll的可写/可读事件都不理会,又如,阻塞在任何一种状态时,客户的发包请求都会入队列;

5)红字标出的两个状态和平时普通socket+epoll的操作刚好相反,值得留意。

如此,一个半双工的https客户端实现就有了。但它的缺陷很明显:每次读、写操作都可能阻塞另一个方向上的数据传输,性能会有急剧的下降。由于通常服务器端并不推荐重协商的过程,所以这种情况也是很少见的。因而,全双工的实现加了开关,当普通https服务器进行压测时,关闭开关,保证性能;当面对真有重协商这种特殊需求的服务器时,才打开开关。

五、HTTPS测试功能的使用

下面,我们来看一下如何在简单模式中进行https页面的服务器性能测试。

1) 点击服务器性能测试产品首页(http://wetest.qq.com/gaps/ )中的快捷入口:HTTP直压。模式选择简单模式,名称和描述可以自己填写。(图中示例起始人数50人,每隔60秒增加50人,加到200人为上限)
这里写图片描述
点击左侧“HTTP直压“进入压测

这里写图片描述

2)新建一个客户端请求,接口压测包括读写接口,读接口基本是GET请求,写接口基本是POST请求。GET请求使用url请求参数,填写测试用例的基础数值,选择正确的URL
这里写图片描述

3) 随后进行Header的配置,Header的名称在选定URL的内,打开URL的链接(推荐使用chrome浏览器),敲击F12并刷新页面,选定Network-Name-Headers-Request Headers(Header的名称与值均在内查看,如下图所示)
这里写图片描述

到这里,基本就完成了对https的配置过程了,是不是很简单?下面动图可以再回顾一下操作的流程:
这里写图片描述

腾讯WeTest服务器性能测试运用了沉淀十多年的内部实践经验总结,通过基于真实业务场景和用户行为进行压力测试,帮助游戏开发者发现服务器端的性能瓶颈,进行针对性的性能调优,降低服务器采购和维护成本,提高用户留存和转化率。

功能目前免费对外开放中,欢迎大家的体验!

体验地址:http://WeTest.qq.com/gaps

如果对使用当中有任何疑问,欢迎联系腾讯WeTest企业qq:800024531

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在socket epoll高并发项目,我们可以使用以下方法来测试高并发性: 1. 压力测试:可以使用工具如Apache JMeter或wrk等进行压力测试,模拟多个并发请求发送到服务器。可以设置并发连接数和请求频率,观察服务器的响应时间和处理能力。 2. 性能测试:可以使用工具如Apache Bench或siege等进行性能测试,发送多个并发请求并记录服务器的响应时间、吞吐量等指标。可以通过调整并发连接数和请求的大小来测试服务器的性能极限。 3. 负载均衡测试:如果项目使用了负载均衡器来分流请求,可以模拟多个并发请求发送到负载均衡器,观察负载均衡器的转发能力和服务器的响应时间。 4. 异常情况测试:可以模拟网络延迟、断连、异常数据等异常情况,观察服务器的容错能力和恢复能力。 5. 数据库测试:如果项目有涉及数据库的操作,可以模拟并发读写请求,观察数据库的性能和并发处理能力。 6. 监控和分析:在测试过程,可以使用监控工具来实时监测服务器的CPU、内存、网络等指标,以及检查是否有内存泄漏或资源泄漏等问题。 通过以上的测试方法和手段,我们可以评估高并发项目的性能和稳定性,找出性能瓶颈和优化空间,提高系统的并发处理能力。 ### 回答2: 在进行socket epoll高并发项目的测试时,可以采取以下几个步骤来测试高并发性: 1. 设计并发测试场景:根据项目的需求和设计,确定需要模拟的并发用户数、每个用户的请求频率和请求类型。可以使用工具如Apache JMeter或自行编写脚本来模拟并发请求。 2. 配置并发环境:在测试机器上进行并发测试,需要增加网络带宽、增加计算资源,比如使用高性能的服务器和网络设备,确保能够支持大量并发连接。 3. 编写测试程序:根据项目的需求,在测试程序实现模拟并发请求的逻辑,通过socket epoll模型建立大量并发连接,并发送模拟请求进行测试。 4. 监控并发连接数和响应时间:使用系统工具如netstat、top等来监控服务器端的并发连接数和系统资源使用情况。同时,使用性能监控工具如zabbix、grafana等来监控服务器的吞吐量、响应时间等指标。 5. 数据验证和压力测试:在并发测试,确保数据的一致性,对接收到的响应进行验证。并逐步增加并发连接数,直至达到系统的极限,观察系统响应时间的变化情况和可能出现的性能瓶颈。 6. 多样化的测试场景:在测试过程,可以尝试不同的测试场景,如不同的请求类型、不同大小的数据包等,验证系统在各种情况下的高并发性能。 7. 异常处理:在测试,需要注意处理一些异常情况,如客户端异常断开连接、网络异常等,确保系统对异常情况的处理能力。 通过以上步骤,可以对socket epoll高并发项目进行有效的测试,找出系统的性能瓶颈,及时进行优化和调整,提升系统的高并发性能。 ### 回答3: 在socket epoll高并发项目,为了测试高并发性能,可以采取以下几种方式: 1. 压力测试工具:使用一些专业的压力测试工具,如JMeter、Apache Bench或wrk等,来模拟大量的并发请求。可以设置并发数、每秒请求数和总请求量等参数,对系统进行压力测试,观察系统在高并发情况下的性能表现。 2. 自动化测试脚本:编写自动化测试脚本,通过多线程或多进程进行模拟并发请求,向服务器发送大量的请求。可以使用Python的模块,如requests、multiprocessing等,实现并发请求的测试。 3. 网络负载生成工具:使用网络负载生成工具,比如Locust、Gatling等,来模拟真实的网络负载情况。可以设置请求频率、并发数和持续时间等参数,模拟多种场景下的高并发情况。 4. 并发性能监控工具:使用一些并发性能监控工具,如Grafana、Prometheus等,来监控系统的并发性能。通过收集CPU、内存、网络等指标数据,可以分析和评估系统在高并发场景下的性能瓶颈。 5. 随机性测试:在测试过程,引入随机性因素,模拟真实场景下的随机请求。可以设计不同类型的请求和不同请求参数的组合,观察系统在随机请求下的并发性能表现。 需要注意的是,在进行高并发性能测试时,要合理设置测试参数,以真实场景为依据,同时监控系统各项指标,及时发现并解决性能瓶颈。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值