ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

高性能异步批量ping的golang实现

2019-10-03 10:55:14  阅读:212  来源: 互联网

标签:异步 log err ping golang bp icmp com


  一个监控项目有个需求,会对一批域名全国的边缘节点进行探测,这里包括,丢包率,http 响应时间,探测频率大概时间是2min 一个周期。这里的域名大概有几百个甚至上千。由于是golang 写的调度和agent, 所以,这里探测丢包率是一个有意思的问题。由于目前git 上没有一个好用的支持multi-ping 的库包,或者多ping 有bug,我自己实现了一个
  
  1,icmp 协议介绍
  
  icmp 的报文头部一共是2+2+4+4+4 个字节。
  
  type ICMP struct {
  
  Type uint8
  
  Code uint8
  
  CheckSum uint16
  
  Identifier uint16
  
  SequenceNum uint16
  
  这里 type 是icmp 类型,常见有发送报文头 Echo, 回收报文头 Echo Reply 等,更多类型 见 https://tools.ietf.org/html/rfc792 。 Code 进一步划分ICMP的类型,该字段用来查找产生错误的原因;CheckSum 校验码部分,这个字段包含有从ICMP报头和数据部分计算得来的,用于检查错误的数据;而Identifier 通常为进程id,标识具体是哪个进程发送的icmp 包;SequenceNum 标识发送包的顺序id。
  
  icmp 有个特点,listen 能收到其他进程ping 的结果,看下面例子:
  
  package main
  
  import (
  
  "log"
  
  "github.com/caucy/batch_ping"
  
  )
  
  func main(xingtuylgw.com) {
  
  ipSlice := []string{}
  
  // ip list should not more than 65535
  
  ipSlice = append(ipSlice, "3g.qq.com")
  
  bp, err := ping.NewBatchPinger(ipSlice, false) // true will need to be root
  
  if err != nil {
  
  log.Fatalf("new batch ping err %v", err)
  
  }
  
  bp.SetDebug(true) www.sangyuLpt.com// debug == true will fmt debug log
  
  bp.SetCount(100)
  
  bp.Run()
  
  }
  
  启动上面的进程,会连续ping 3g.qq.com,同时,再启动一个进程ping www.baidu.com , 日志会显示,收到了220.181.38.150 的icmp 包。
  
  2, 如何支持同时支持ping 多个addr
  
  第一种是最简单的,也是大多数探针采用的方式:subprocess 。这个方式有个缺点,就是每个任务会fork 一个进程,非常耗费耗费资源。
  
  第二种方式,我是这样想的,golang 有icmp 包,能够支持send and recive, 我直接起协程 去 收发,每个协程和subprocess 一样,先发后等,这样不就行了?然后起一组协程池,这样并发也能控制。然而,上面例子已经提到了,listen 后的conn 能收到其他进程 ping 的结果,这样实现挺麻烦。
  
  第三种方式,一个协程收,一个协程发。最后选择的是这种方式。
  
  一个协程收,一个协程发,有什么比较麻烦地方?因为icmp 层只能标识seq,所以会出现icmp 包头相同的情况,同时,批量收发,非常容易出现丢包的情况。
  
  3,batch-ping 特性
  
  支持原地址控制
  
  支持ipv6 (操作系统本身支持“ip6:ipv6-icmp”,“udp6” dial )
  
  支持时间间隔控制
  
  支持发送方式控制
  
  支持多addr 控制
  
  支持 mac, linux
  
  使用示例:
  
  package main
  
  import (
  
  "log"
  
  "github.com/caucy/batch_ping"
  
  )
  
  func main( www.baichuangyule.cn) {
  
  ipSlice := []string{}
  
  // ip list should not more than 65535
  
  ipSlice = append(ipSlice,www.jintianxuesha.com "2400:da00:2::29") //support ipv6
  
  ipSlice = append(ipSlice, www.qjljdgt.cn "baidu.com")
  
  bp, err := ping.NewBatchPinger(ipSlice, false)www.yacuangyl.com // true will need to be root
  
  if err != nil {
  
  log.Fatalf("new batch ping err %v", err)
  
  }
  
  bp.SetDebug(true) jujinyulee.com // debug == true will fmt debug log
  
  bp.SetSource("www.xinhuihpw.com") // if hava multi source ip, can use one isp
  
  bp.OnFinish = func(stMap map[string]*ping.Statistics) {
  
  for ip, st := range stMap {
  
  log.Printf("\n--- %s ping statistics ---\n", st.Addr)
  
  log.Printf("ip www.rhyl158.com %s, %d packets transmitted, %d packets received, %v%% packet loss\n", ip,
  
  st.PacketsSent, st.PacketsRecv, st.PacketLoss)
  
  log.Printf("round-trip min/avg/max/stddev = %v/%v/%v/%v\n",
  
  st.MinRtt, st.AvgRtt, st.MaxRtt, st.StdDevRtt)
  
  log.Printf("rtts is %v \n", st.Rtts)
  
  }
  
  }
  
  err = bp.Run()
  
  if err != nil {
  
  log.Printf("run err %v \n", err)
  
  }
  
  bp.OnFinish(bp.Statistics())
  
  }
  
  4,可能问题
  
  因为icmp 基于udp,时间间隔非常小,发送机器非常多的时候,会出现非常严重丢包,内核参数需要优化。

标签:异步,log,err,ping,golang,bp,icmp,com
来源: https://www.cnblogs.com/dakunqq/p/11619278.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有