使用Go实现ping工具

ping是一个网络工具,它被广泛地用于测试网络连接的质量和稳定性。当我们想知道我们的电脑是否能够与其他设备或服务器进行通信时,ping就是我们最好的朋友。当我们想侦测网络之间的连通性和网络质量的时候,也常常使用ping工具测量,因为它是操作系统常带的一个网络诊断工具,小而强大。

ping最初是由Mike Muuss在1983年为Unix系统开发的。它的名字是来自于海军潜艇的声纳系统,声纳系统通过发送一个声波并测量其返回时间来确定目标的位置。Ping的工作原理类似,它发送一个小数据包到目标设备,然后等待该设备返回一个响应,以测量其响应时间和延迟。

阅读全文

高性能批量读写网络包

虽然网络协议栈提供了丰富的功能,让我们可以方便的实现网络的数据交流,但是有时候我们对协议栈的性能还是不是那么满意的,前几篇文章我也介绍了通过XDP等技术高效处理网络数据的方式,但是毕竟XDP还没有那么广泛的应用,使用起来也还不是那么简单,如果我们通过编程语言提供的标准库来实现数据的读写,还怎么能提高性能呢?今天就介绍一种方式,批量的读写数据包。

阅读全文

使用AF_XDP Socket更高效的网络传输

Linux 网络栈并不缺乏功能,它的表现也很好 足以满足大多数用途。但是,在高速网络下,传统网络编程的额外开销占比太大了。在前一篇关于syscall.Socket的文章中,我们介绍了AF_PACKET类型的socket,它的性能着实一般,所有的数据都得在用户态和内核态之间做转换,而且在高并发的情况下还有大量的中断。使用eBPF XDP可以完美解决高性能的问题,我们在更早的文章中介绍了XDP的技术,Björn Töpel在Linux 4.18版本中为Socket增加了一个协议族 AF_XDP,可以利用Socket接口和XDP技术实现高性能的网络读写。

阅读全文

使用底层的syscall.Socket实现网络编程

socket 函数是一个系统调用,用于在操作系统内核中创建一个新的网络套接字。套接字是一种在网络上进行通信的抽象对象,通过套接字,应用程序可以使用不同的网络协议进行通信,如 TCP、UDP 等,甚至我们可以实现自定义的协议。

阅读全文

每秒1百万的包传输,几乎不耗CPU的那种

这两年来我一直在做网络故障监控的工作,经常使用的一个手段就是发送一些探测包进行网络的探测,根据丢包和时延,再结合网络拓扑等手段分析现网网络故障。因为要监控的是度厂全部网络的质量状况,并且需要很高的精度去覆盖网络设备、板卡、端口以及他们之间映射等所有的路径,所以需要尽量发送高频的探测包去快准狠的感知到故障并发现。
同时,和业务网络程序的不一样,业务程序一般是业务层代码,TCP的重传的机制,或者业务换个五元组重连一次,就会绕过网络中的故障,而网络监控也需要把这个链路中这些故障找出来,经常我会使用UDP或者TCP的握手包进行网络的探测,再不济使用ICMP协议进行网络的探测。

经常有人会说,现在都两个服务器间都能实现几十上百万的requests/second了,比如我们访问Redis节点,但是『达到』和『产品化可用』是两回事,也很少有人将redis节点在几十万的qps之下常态运行,我们还得考虑丢包的情况和时延的情况。

但是不管怎样,benchmark的工作我们还是要做的,这是我们评价我们的程序的一个基准,实际运行中我们可能使用这个基本的1/10的能力,以便保证程序的稳定性和CPU、内存、时延要求等。我写本文的目的,也是在测试机上进行这样的benchmark,检查网络方案的能力。

  • 首先使用一个普通的UDP程序进行百万pps (packets per second)的测试
  • 介绍XDP技术,实现一个简单的网络统计程序
  • 使用XDP技术实现echo能力,替换原来的UDP server, 将CPU使用率几乎降为0

阅读全文

像闪电一样快速扫描全网的IP地址

新开一个Go编程系列,主要讲Go语言的高级编程技术,希望能像《Go并发编程指南》一样形成一个系列,不要断更。

这一篇是使用gopacket库编程的一部分,主要是通过手工构造数据链路层、网络层、传输层的包,实现扫描全网(示例中是中国大陆的) ipv4的IP地址,看看对应的网络是否可达。 首先我们需要知道全网的IP地址,其实我们可以使用fping探测这些IP是否连通,然后我们自己基于ICMP快速扫描这些IP,找出全网活跃的IP地址,最后我们使用tcp scan的方式扫描全网的IP,甚至你可以扫描公网上暴露的Redis实例。

阅读全文

机智!生抠 map的哈希函数

前一段时间我尝试为orcaman/concurrent-map实现泛型的支持时,遭遇到为任意类型计算哈希值的问题,现在这个库也自己实现了泛型支持,你也可以看到它的哈希也没有好的办法,只能提供出一个函数对象让用户自己实现。当然你也可以参考[cornelk/hashmap/blob/36b3b9c2b7ec993f1ef12a6957d45826aca726e6/util_hash.go#L49)中的实现,但是它的实现既不全面也不高效?

我们经常会在一些场景,比如特定的数据结构、cache等场景中使用这样一个哈希函数,那么如何为任务类型实现一个优雅高效的hash函数呢?其实Go运行时中map中就实现了。回想一下内建的map是不是支持泛型的?它的key可以是comparable类型(包括接口类型),内部实现中会把此类型的key计算一个哈希值,能不能吧它的hash函数拿出来使用?很遗憾,Go官方并没有想暴露出来这样的hasher的想法,它的代码也是不容易抽取整理成一个hasher函数。

今天看到一篇文章Hacking Go's Runtime with Generics,提供了一种方法,脑洞大开。没看之前确实没想到,看到之后才发觉这么简单有效,接下来我翻译了这么文章,赶快学习吧。

阅读全文