https://blog.myhro.info/2017/01/how-fast-are-unix-domain-sockets

Jan 3, 2017 • Tiago Ilieve

Warning: this is my first post written in English, after over five years writing only in Portuguese. After reading many technical articles written in English by non-native speakers, I’ve wondered: imagine how much information I would be missing if they wrote those posts in French or Russian. Following their examples, this blog can also reach a much wider audience as well.

It probably happened more than once, when you ask your team about how a reverse proxy should talk to the application backend server. “Unix sockets. They are faster.”, they’ll say. But how much faster this communication will be? And why a Unix domain socket is faster than an IP socket when multiple processes are talking to each other in the same machine? Before answering those questions, we should figure what Unix sockets really are.

Unix sockets are a form of inter-process communication (IPC) that allows data exchange between processes in the same machine. They are special files, in the sense that they exist in a file system like a regular file (hence, have an inode and metadata like ownership and permissions associated to it), but will be read and written using recv() and send() syscalls instead of read() and write(). When binding and connecting to a Unix socket, we’ll be using file paths instead of IP addresses and ports.

In order to determine how fast a Unix socket is compared to an IP socket, two proofs of concept (POCs) will be used. They were written in Python, due to being small and easy to understand. Their implementation details will be clarified when needed.

IP POC

ip_server.py

#!/usr/bin/env python

import socket

server_addr = '127.0.0.1'
server_port = 5000 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((server_addr, server_port))
sock.listen(0) print 'Server ready.' while True:
conn, _ = sock.accept()
conn.send('Hello there!')
conn.close()

ip_client.py

#!/usr/bin/env python

import socket
import time server_addr = '127.0.0.1'
server_port = 5000 duration = 1
end = time.time() + duration
msgs = 0 print 'Receiving messages...' while time.time() < end:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((server_addr, server_port))
data = sock.recv(32)
msgs += 1
sock.close() print 'Received {} messages in {} second(s).'.format(msgs, duration)

Unix domain socket POC

uds_server.py

#!/usr/bin/env python

import os
import socket server_addr = '/tmp/uds_server.sock' if os.path.exists(server_addr):
os.unlink(server_addr) sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.bind(server_addr)
sock.listen(0) print 'Server ready.' while True:
conn, _ = sock.accept()
conn.send('Hello there!')
conn.close()

uds_client.py

#!/usr/bin/env python

import socket
import time server_addr = '/tmp/uds_server.sock' duration = 1
end = time.time() + duration
msgs = 0 print 'Receiving messages...' while time.time() < end:
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect(server_addr)
data = sock.recv(32)
msgs += 1
sock.close() print 'Received {} messages in {} second(s).'.format(msgs, duration)

As we can see by those code snippets, both implementations are close to each other as possible. The differences between them are:

  • Their address family: socket.AF_INET (IP) and socket.AF_UNIX (Unix sockets).
  • To bind a process using socket.AF_UNIX, the socket file should be removed and created again if it already exists.
  • When using socket.AF_INET, the socket.SO_REUSEADDR flag have to be set in order to avoid socket.error: [Errno 98] Address already in use errors that may occur even when the socket is properly closed. This option tells the kernel to reuse the same port if there are connections in the TIME_WAIT state.

Both POCs were executed on a Core i3 laptop running Ubuntu 16.04 (Xenial) with stock kernel. There is no output at every loop iteration to avoid the huge performance penalty of writing to a screen. Let’s take a look at their performances.

IP POC

First terminal:

$ python ip_server.py
Server ready.

Second terminal:

$ python ip_client.py
Receiving messages...
Received 10159 messages in 1 second(s).

Unix domain socket POC

First terminal:

$ python uds_server.py
Server ready.

Second terminal:

$ python uds_client.py
Receiving messages...
Received 22067 messages in 1 second(s).

The Unix socket implementation can send and receive more than twice the number of messages, over the course of a second, when compared to the IP one. During multiple runs, this proportion is consistent, varying around 10% for more or less on both of them. Now that we figured their performance differences, let’s find out why Unix sockets are so much faster.

It’s important to notice that both IP and Unix socket implementations are using TCP (socket.SOCK_STREAM), so the answer isn’t related to how TCP performs in comparison to another transport protocol like UDP, for instance (see update 1). What happens is that when Unix sockets are used, the entire IP stack from the operating system will be bypassed. There will be no headers being added, checksums being calculated (see update 2), encapsulation and decapsulation of packets being done nor routing being performed. Although those tasks are performed really fast by the OS, there is still a visible difference when doing benchmarks like this one.

There’s so much room for real-world comparisons besides this synthetic measurement demonstrated here. What will be the throughput differences when a reverse proxy like nginx is communicating to a Gunicorn backend server using IP or Unix sockets? Will it impact on latency as well? What about transfering big chunks of data, like huge binary files, instead of small messages? Can Unix sockets be used to avoid Docker network overhead when forwarding ports from the host to a container?

References:

Updates:

  1. John-Mark Gurney and Justin Cormack pointed out that SOCK_STREAM doesn’t mean TCP under Unix domain sockets. This makes sense, but I couldn’t find any reference affirming nor denying it.
  2. Justin Cormack also mentioned that there’s no checksumming on local interfaces by default. Looking at the source code of the Linux loopback driver, this seems to be present in kernel since version 2.6.12-r2.

[转帖]How fast are Unix domain sockets?的更多相关文章

  1. PHP 调用 Go 服务的正确方式 - Unix Domain Sockets

    * { color: #3e3e3e } body { font-family: "Helvetica Neue", Helvetica, "Hiragino Sans ...

  2. UNIX DOMAIN SOCKETS IN GO unix域套接字

    Unix domain sockets in Go - Golang News https://golangnews.org/2019/02/unix-domain-sockets-in-go/ pa ...

  3. Unix domain sockets

    #server: SERVER_PATH = "/tmp/python_unix_socket_server" def run_unix_domain_socket_server( ...

  4. php, hhvm与odp & Unix domain Socket方式

    接上一篇,复习一下 启动php或hhvm: php/sbin/php-fpm start hhvm/bin/hhvm_control start 启动nginx或lighttpd: webserver ...

  5. 网络协议之:socket协议详解之Unix domain Socket

    目录 简介 什么是Unix domain Socket 使用socat来创建Unix Domain Sockets 使用ss命令来查看Unix domain Socket 使用nc连接到Unix do ...

  6. 由一个简单需求到Linux环境下的syslog、unix domain socket

    本文记录了因为一个简单的日志需求,继而对linux环境下syslog.rsyslog.unix domain socket的学习.本文关注使用层面,并不涉及rsyslog的实现原理,感兴趣的读者可以参 ...

  7. libpqxx接口的在linux下的使用,解决psql:connections on Unix domain socket "/tmp/.s.PGSQL.5432"错误

    在项目中使用postgresql数据库时要求在windows和linux双平台兼容.于是在windows下使用的接口在linux下爆出异常: psql:connections on Unix doma ...

  8. Unix domain socket IPC

    UNIX Domain socket 虽然网络socket也可用于同一台主机的进程间通讯(通过lo地址127.0.0.1),但是unix domain socket用于IPC更有效率:不需要经过网络协 ...

  9. 问题解决:psql: could not connect to server: No such file or directory Is the server running locally and accepting connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?

    错误提示: psql: could not connect to server: No such file or directory Is the server running locally and ...

  10. UNIX域套接字(unix domain)

    UNIX域套接字用于在同一台机器上运行的进程之间的通信. UNIX域套接字提供流和数据报两种接口. 说明:UNIX域套接字比因特网套接字效率更高.它仅赋值数据:不进行协议处理,如添加或删除网络报头.计 ...

随机推荐

  1. 用Python写一个简单的TCP客户端和服务端

    在渗透测试过程中,经常需要创建一个TCP客户端,用来测试服务.发送数据.进行 fuzz 等等.如果黑客潜伏在某大型企业的内网环境中,则不太可能直接获取网络工具或编译器,有时甚至连复制/粘贴或者连接外网 ...

  2. BFS(一)单词接龙

    对应 LeetCode 127 单词接龙 问题定义 给定一个字典序列 wordList,一个初始的单词 beginWord 和一个目标单词 endWord,现在要求每次变换满足以下条件将 beginW ...

  3. C# 将Word转为PDF时,设置PDF文档保护

    本文以C#代码示例展示如何将Word转为PDF时,设置PDF文档保护,可设置PDF文档打开密码保护以及权限密码保护.附VB.NET代码,有需要可供参考. 程序环境: 1.Word测试文档:.docx ...

  4. 第七部分_Shell脚本之循环

    for循环语句 关键词:爱的魔力转圈圈 1. for循环语法结构 空行相对于for循环类似于空格 ㈠ 列表循环 列表for循环:用于将一组命令执行已知的次数 基本语法格式 for variable i ...

  5. tsconfig.json在配置文件中找不到任何输入,怎么办?

    摘要:原来在我们创建tsconfig.json文件的时候,VSCode会自动检测当前项目当中是否有TS文件:如果没有的话,就会报这个错提示我们去创建一个文件,再去使用. 本文分享自华为云社区<t ...

  6. 想发自己的NFT,你要先搞清楚这6个问题

    摘要:NFT是Web3世界中标记数据资产独特性的标识,是数据权益的载体. 本文分享自华为云社区<加密数字艺术NFT背后你关心的六个问题>,作者: 薛腾飞 . Connect Wallet ...

  7. 云小课 | 使用ROMA API,API管理从此不用愁!

    阅识风云是华为云信息大咖,擅长将复杂信息多元化呈现,其出品的一张图(云图说).深入浅出的博文(云小课)或短视频(云视厅)总有一款能让您快速上手华为云.更多精彩内容请单击此处. 摘要:ROMA API致 ...

  8. appuploader 常规使用登录方法

      转载:登录appuploader 登录appuploader   常规使用登录方法 双击appuploader.exe 启动appuploader 点击底部的未登录,弹出登录框 在登录框内输入ap ...

  9. 揭露ROI提升5倍的秘密!火山引擎A/B测试白皮书重磅发布(内附下载链接)

    - 文末立即下载白皮书原文 -  近期,<火山引擎A/B测试总体经济影响白皮书>正式发布.这份白皮书由市场研究公司Forrester调研撰写,揭示了A/B测试对于企业营收增长.运营成本.生 ...

  10. 火山引擎ByteHouse:云原生数据库如何提升MySQL兼容性?

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 当前各类软件层出不穷,单独某一款软件往往难以满足企业应用需求,一般都需要与各类软件组合使用,这时软件生态兼容性就显 ...