iNeedle系统之国舜项目

1、简介

本周公司接了一个小项目,是给北京国舜科技股份有限公司作一个 HTTP 相关的小功能产品。大概实现功能是将交换机的源数据经过解析,分析出 HTTP 包配对的 request 和 response 头,并把每对的 request 和 response 头相关字段内容,经过TCP方式发送给对方的指定的服务器。java

2、要求

须要一台流量设备来抓取分析交换机中的数据,流量设备经过推送的方式将解析后的数据发送到咱们平台,平台基于数据进行分析,关于流量设备有下边几个需求:linux

一、流量设备ios

a.须要同时支持双向(流出,流入)流量分析 
b.需能支持千兆网峰值流量

二、双方对接方案web

采用 TCP 长链接对接,也就是经过 socket 以 TCP 长链接方式向对方服务器发送指定格式的数据内容,对方以相应的格式进行解析便可。编程

三、发送数据包格式数组

1:  typedefstruct{
2:  unsignedintmagic;// =0x4458434A,即“DXCJ”,用于同步时从新找到一个消息起始点
3:  unsignedintlength;// 负载数据的长度
4:  char*data;// 实际数据内容
5:  }
6:  // 即以前定义的按照需求文档中2张表的顺序\t分隔的请求+响应数据,长度为length,以后即下一条消息的magic字段

注意:对于magic和length字段须要考虑网络字节序问题,咱们设备都是小端字节序,对方要求是大端字节序,网络字节序也是大端字节序,最后转换为网络字节序传输便可。咱们这边是用C语言发送数据,对方接收端程序是java语言写的,不过这都无所谓了,底层协议都是标准的,能够相互通讯。缓存

四、负载均衡服务器

对方接收数据端会有多个主机进行数据的接收,所以存在多主机负载均衡的问题。能够经过设置配置文件,内容大概以这样的形式: host:port,多个主机就存在多个列表。这个配置文件由双方来协商,能够由对方来配置,也存在对方后续会不定时的添加主机或修改主机的状况。在发送数据时,使用轮询调度(Round-Robin Scheduling)将流量分发到各个节点上。例如,如有 3 个节点,发送 4 个消息,按以下顺序: 给节点1发一条消息,再给节点 2 发一条消息,再给节点 3 发一条消息,再从节点1开始继续循环,实现简单的负载均衡。cookie

同时须要支持失败重试,好比 3 个节点有一个节点宕了,那么我这边会尽快启动,启动以前流量由另两个节点处理。待失败节点启动后,再次 3 台机器同时工做;经过长链接端口来断定节点失败。网络

五、数据格式

需求的字段有不少,有一部分字段须要额外从新解析,解析完毕各个字段以后须要以指定的格式进行发送;一个请求各字段间依照上述2个表序号顺序使用\t拼接为一整行做为一条消息发送。若是某个字段为空,不作忽略。例如,假如3个字段:Name\tAge\tAddress  若是Age为空,分隔符保留。则输出:Name\t\tAddress便可,如:liming\t\tchangpingqu。

3、实现方式

本功能实际上并不复杂,彻底能够在 ineedle 系统基础之上作一些简单修改,造成数据消息,而后发送给对方便可。关于 ineedle 后续的额外功能能够摘除,以提升整个 ineedle 系统的效率。

4、方案设计

总共有4部分须要修改或添加

一、HTTP的请求头和相应头字段

由于以前ineedle解析的相关字段是根据后续分析需求而定的,比较少,并不全面;而此次对方需求中的字段有一大部分在ineedle中是没有的,须要再额外再次进行解析。须要在ineedle系统中的相应解码代码中做出相应的解码工做,解码方式还按照原来的实现方式,只是添加些而已,而后挂到相应mbuf上,供后续sess使用。固然首要工做仍是要对这58个字段(后续又增长7个字段)进行查找和分析,找出这些字段的经典取值,以及相关做用,用于后续代码中buf长度的判断,最终暂时定为(1024*8字节)大小。

二、定时刷新主机列表

这一部分能够在ineedle系统中原来flt_main进程中的某个定时线程中作,初次能够设置为10秒钟定时周期。主要定时刷新主机:端口列表是否有修改,或者判断是否有宕机设备从新启动。在刷新主机列表以前要判断一下配置文件host_list的时间戳是否变化,若是没有变化说明这段时间内用户没有更新主机列表,咱们在程序中就不会再更新主机列表。还有一点就是用来从新复活以前宕机的设备,原理是这样的,若是某个设备宕机,就加入黑名单列表,就是在激活主机列表中将该主机alive标志位置1,表示宕机,后续再也不往该设备上发送消息,直到用户重启该设备并定时器刷新复活。所以若是存在一个或多个设备宕机以后,用户将设备启动以后,须要作一个操做就是修改host_list文件的时间戳,简单touch一下就行,若是不touch的话,再没有修改host_list文件内容状况下,咱们程序就不会从新刷新主机列表,也就不会再复活宕机而又重启的设备,这个条件到时候要提醒对方必定要作这个操做,不然单单重启宕机设备多是无效的。这个地方原来是这样设计的,可是对方设备不只可能会存在宕机状况,好比也多是程序挂掉等,也是不能通讯的,这种状况发生的概率仍是比较大的,不能使用上述方式来搞,比较麻烦,每次都须要用户来ssh登录并操做,这样可能自己就是一个缺陷,如今决定暂时放弃这个作法,也就是不去判断配置文件的时间戳,每次直接去读取配置主机列表,这样应该不会有太多性能消耗,不会有太大影响。

三、HTTP报文的request和reponse配置向队列写消息

这部分不用修改太多东西,主要是将分析到的request头和response头的相关字段,组合成指定格式的消息并发送给咱们的缓存队列里边。存在一点问题,就是原来的ineedle每次解析完request和response头相关信息后都是挂在mbuf结构体上,好比上次解析的request头信息挂载mbuf上,下次到response包解析时,会把上次的mbuf清空,来填写此次response报文解析的数据,所以这时得不到完整的req和res的组合信息。所以须要将req和res信息挂到sess上,由于req和res在共同的sess上,所以能够读到上次的信息,并在第二次读到正确的res包时,进行req和res数据的组合,组合完毕将数据拷贝到缓冲数组。须要注意的是一个sess中可能有多个req和res,注意后边的req和res要把前边的数据覆盖掉,保证数据清零,不要让上次数据影响到此次的数据。这里实现的一下细节,须要在mbuf中添加一些须要额外解析的字段,并且在sess表结构中添加http_req_res_buf来存储一对请求响应的数据内容。组合完毕,在发送到数据队列中。

四、启动单独线程发送消息

另外单独启动一个线程来读取缓冲队列的消息,并按照主机列表的顺序经过socket TCP方式依次发送到相应主机上,若是遇到主机宕机状况,将其加入黑名单,并后续不发送数据给它。理论上是这样,要考虑接收主机的负载均衡。经过定时不断刷新,若是以前宕机程序又从新启动,须要从新尝试链接该主机并链接tcp并继续向该主机发送消息。从缓存队列读取消息并发送消息过程,彻底相似一个生产者与消费者的模型,考虑到数据读写的互斥操做,读写线程之间要用线程的条件变量和线程锁来实现互斥的功能。

5、详细设计

这里就详细介绍一下,这几部分的详细设计实现细节。

一、解码http请求和响应字段数据

这一部分没有什么特别须要注意的地方,严格参考以前的解码方式,对比原来方案,实现代码编写,而后将生成解码的值挂到mbuf结构体上。这时就须要在mbuf结构体上添加须要的字段,待后续sess汇总时要用到,其实这时候tcp链接已经彻底创建,sess表已经存在,彻底能够将解析的字段值直接挂到sess表上,可是这样作有点混乱,没有严格按照以前的代码方案,因此最好的方式仍是按照前边的方式比较好。

二、定时刷新主机列表

定时10秒间隔不停刷新主机列表。

三、汇总req和res并向缓冲队列写消息

四、发送线程不断发送消息

6、编码工做

。。。。。。暂时能够参考代码

7、编码中遇到的问题

0一、问题1 ---- MSG_NOSIGNAL

在tcp编程过程当中,测试代码时,发现若是服务器端被关闭,则client端系统会自动向内核发送一个信号,直接把client程序给杀死。这是linux默认的行为,这个地方咱们不须要这样,须要在send函数后边标志位设置一下MSG_NOSIGNAL标记。这样设置完毕就能够了。

8、测试中遇到的问题

0一、问题1

当时设置的若是接收方宕机重启后须要手动修改时间戳,这个问题须要修复一下。这个地方只要在刷新线程中将判断时间戳函数地方注释掉便可。

0二、问题2

socket状态一直关闭不正常状态,出现FIN_WAIT1?????比较多,不知道是什么缘由,后来也没有发现过。后续有时间查找具体缘由。

0三、问题3

双方接收数据对接不成功,对方接收消息时,常常出现错误,好比接收magic和length都会有错误,当时也不肯定是什么问题,或者说是双方谁的程序有问题。后来又通过后续的连续测试,双方检查程序,结果也都没有肯定哪方程序有问题?最后在C程序端发送socket上设置TCP_NODELAY标记后,对方接收数据暂时正确和正常。但这样作只能告诉内核快速发送,不要有延时,这样作的话,对jar端产生的影响就是接收缓存中的msg比较简单,从而减少出现错误的可能性,如今这只是推断,还不能肯定具体缘由是什么?

0四、问题4

ineedle程序在对方接收端所有挂掉的时候会陷入睡眠,致使看门狗没有喂狗,导致ineedle重启。这种状况是很不友好的,须要除去这种状况,就在这个地方设置了一个下标志位,每次判断一下,若是是所有宕机的状况,这时就不要像往常那样进入睡眠,直接跳转到下条数据处理流程代码便可,直接丢弃数据,这种状况是不可避免的。

9、总结

最后在国舜作测试,作 ineedle 开机启动,遇到了一些问题,将启动程序命令写入到/etc/init.d/rc.local文件中,单单写入 /var/dz_resource/ineedle/release/ineedle 这样是运行不了,须要在这个命令以前 source /etc/profile 文件,多是有什么环境变量须要设置,暂时没有找到具体什么缘由,后续再研究。

10、遗留问题

ineedle设备HA特性尚不支持。后续待开发。

11、测试数据

小设备发包极限:50M/S

银灰色小设备测试ineedle性能:

最大速率达到50M/S的速率时开始丢包,算是极限速率吧。

发包数据与生成消息比例:

50M/S   ---->  1.6M/S 
20M/S   ---->  0.65M/S

12、发包设备(交换机)

以前是用一个设备上边跑linux_pcap程序来给待测设备进行发包,这样对于低配置的发包设备来讲,发包速率很低,最高才50M/s左右;对于较高配置(如DELL R430)速率也才到90M/s,这样达不到测试程序速率的效果。为此买了一台千兆交换机,准备用三台设备同时往交换机的三个网口来打流量,这样交换机镜像口就能汇总三个设备流量到一个口上,再经过一根网线将此网口数据打到待测试设备网口上便可。三台设备每台50M/S,三台总共150M/s,此时交换机镜像口接收数据速率有且120M/S,这样的速率基本上达到千兆网速,算是打到了千兆网卡的极限了。此工具之后能够测试后续性能比较好的设备了。可是发包工具当时作了简单的修改,把修改ip、cookie、等信息给去掉了,pcap拿到数据包以后直接从端口发送出去,这样效率应该会高一些,后续有时间能够继续优化一下发包工具。

其中拿到新交换机以后,看说明书进行简单配置,其实说明书并未有卵用,简单的不能再简单,就说明了哪些端口的指示灯表示什么,什么颜色表明网口的工做状态。而后经过交换机的web界面进行了简单配置,设置了几个端口为镜像口,和监测口。在设备与交换机相连的过程当中,出现了协商速率不一致问题,明明都设置的是千兆全双工,设备显示的协商速率确实百兆的,后来仔细琢磨和尝试,换了灰色的网线以后,很轻易的自动识别并协商为1000M的网速,估计是和网线有关,估计那蓝色和红色的网线不支持千兆速率的吧。

十3、设备安装遇到的问题

从国舜拿到的设备回来以后开始安装操做系统,连上显示器,死活都不会显示,并且不会出现bios界面,刚在gs仍是好好的,妹的,把内存条插拔了几回,从新安装上以后,不一会就听到了滴滴2声,显示器唰唰的打印出了bios的启动信息,原来是路上设备颠簸,内存松动,这种状况不止一次出现,以前就出现过一次。这种bios都不显示信息的,必定不是系统问题,确定是基本设备的硬件没有检测到,或者是检测不到位,这样不知足系统启动的条件,就启动不了,并且没有打印信息,连bios都启动不了,太过度了,至少也要嘀嘀嘀报警一阵子啊,变态,这也算是知识的积累,总结经验。

相关文章
相关标签/搜索