[转帖]How fast are Unix domain sockets?
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) andsocket.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, thesocket.SO_REUSEADDRflag have to be set in order to avoidsocket.error: [Errno 98] Address already in useerrors 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 theTIME_WAITstate.
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 ( (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, socket.SOCK_STREAM), so the answer isn’t related to how TCP performs in comparison to another transport protocol like UDP, for instancechecksums 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:
- Beej’s Guide to Unix IPC, 11. Unix Sockets (Brian “Beej Jorgensen” Hall)
- Programmation Systèmes, Cours 9 - UNIX Domain Sockets (Stefano Zacchiroli)
- Unix Domain Sockets - Python Module of the Week (Doug Hellmann)
- unix domain sockets vs. internet sockets (Robert Watson)
- What exactly does SO_REUSEADDR do? (Hermelito Go)
Updates:
- John-Mark Gurney and Justin Cormack pointed out that
SOCK_STREAMdoesn’t mean TCP under Unix domain sockets. This makes sense, but I couldn’t find any reference affirming nor denying it. - 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?的更多相关文章
- PHP 调用 Go 服务的正确方式 - Unix Domain Sockets
* { color: #3e3e3e } body { font-family: "Helvetica Neue", Helvetica, "Hiragino Sans ...
- UNIX DOMAIN SOCKETS IN GO unix域套接字
Unix domain sockets in Go - Golang News https://golangnews.org/2019/02/unix-domain-sockets-in-go/ pa ...
- Unix domain sockets
#server: SERVER_PATH = "/tmp/python_unix_socket_server" def run_unix_domain_socket_server( ...
- php, hhvm与odp & Unix domain Socket方式
接上一篇,复习一下 启动php或hhvm: php/sbin/php-fpm start hhvm/bin/hhvm_control start 启动nginx或lighttpd: webserver ...
- 网络协议之:socket协议详解之Unix domain Socket
目录 简介 什么是Unix domain Socket 使用socat来创建Unix Domain Sockets 使用ss命令来查看Unix domain Socket 使用nc连接到Unix do ...
- 由一个简单需求到Linux环境下的syslog、unix domain socket
本文记录了因为一个简单的日志需求,继而对linux环境下syslog.rsyslog.unix domain socket的学习.本文关注使用层面,并不涉及rsyslog的实现原理,感兴趣的读者可以参 ...
- libpqxx接口的在linux下的使用,解决psql:connections on Unix domain socket "/tmp/.s.PGSQL.5432"错误
在项目中使用postgresql数据库时要求在windows和linux双平台兼容.于是在windows下使用的接口在linux下爆出异常: psql:connections on Unix doma ...
- Unix domain socket IPC
UNIX Domain socket 虽然网络socket也可用于同一台主机的进程间通讯(通过lo地址127.0.0.1),但是unix domain socket用于IPC更有效率:不需要经过网络协 ...
- 问题解决: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 ...
- UNIX域套接字(unix domain)
UNIX域套接字用于在同一台机器上运行的进程之间的通信. UNIX域套接字提供流和数据报两种接口. 说明:UNIX域套接字比因特网套接字效率更高.它仅赋值数据:不进行协议处理,如添加或删除网络报头.计 ...
随机推荐
- 斯坦福 UE4 C++ ActionRoguelike游戏实例教程 12.认识GamePlayTag, 实现技能的互斥
斯坦福课程 UE4 C++ ActionRoguelike游戏实例教程 0.绪论 概述 本篇文章对应Lecture 17 - GameplayTags, 67.67节.本文将会讲述UE4中Gamepl ...
- 占位图片(Placeholder Image)
一.引言 在网页设计和开发中,占位图片(Placeholder Image)是一种常见的技术手段,用于在用户上传图片之前或者图片加载失败时,展示一个临时替代的图片,以提高用户体验.本文将详细介绍占位图 ...
- Quartz.Net系列(一):Windows任务计划程序
1.使用此电脑=>管理 系统工具=>任务计划程序=>任务计划程序库=>创建任务 创建任务 触发器 操作 条件=>去掉只有在计算机使用交流电源时才启动此任务 创建 ...
- DevOps|我们需要什么样的产研项目管理工具
上一篇文章<DevOps|产研运协作工具链上的皇冠-项目管理工具>主要讲了项目管理工具对软件研发的重要性,本篇文章主要想讲清楚我们需要什么样的项目管理工具,项目管理工具必须具备的功能有哪些 ...
- 如何使用 Node.js Stream API 减少服务器端内存消耗?
摘要:让我们看一个示例,展示在内存消耗方面,采用流的编程思路带来的巨大优越性. 本文分享自华为云社区<使用 Node.js Stream API 减少服务器端内存消耗的一个具体例子>,作者 ...
- CartoonGAN论文复现:如何将图像动漫化
摘要:本案例是 CartoonGAN: Generative Adversarial Networks for Photo Cartoonization的论文复现案例. 本文分享自华为云社区<c ...
- 聊聊LiteOS中生成的Bin、HEX、ELF三种文件格式
摘要:我们在使用编译器在编译工程后会要求生成可执行文件,将这些文件烧录到MCU进行运行,达到我们测试和使用程序的目的,再使用工具链进行编译的时候往往生成.bin..hex ..elf ..alf等文件 ...
- Preload与Prefetch的区别以及webpack项目中如何优化
preload 与prefetch 的区别 preload 是一个声明式 fetch,可以强制浏览器在不阻塞 document 的 onload 事件的情况下请求资源. preload 顾名思义就是一 ...
- 超90万个K8S实例可被发现暴露在公网上,14%位于中国
翻译: SEAL安全 原标题: Over 900,000 Kubernetes instances found exposed online 原文链接: https://www.bleepingcom ...
- Solon2 开发之插件,一、插件
Solon Plugin 是框架的核心接口,简称"插件".其本质是一个"生命周期"接口.它可让一个组件类参与程序的生命周期过程(这块看下:<应用启动过程与 ...