Отличие unix сокетов от tcp сокетов
Работать в пятницу после обеда первого апреля не хочется — вдруг ещё техника выкинет какую-нибудь шутку. Потому решил о чем-либо написать.
Не так давно на просторах хабра в одной статье огульно охаяли сразу Unix-сокеты, mysql, php и redis. Говорить обо всём в одной статье не будем, остановимся на сокетах и немного на redis.
Итак вопрос: что быстрее Unix- или TCP-сокеты?
Вопрос, который не стоит и выеденного яйца, однако, постоянно муссируемый и писать не стал бы если б не опрос в той самой статье, согласно которому едва-ли не половина респондентов считает, что лучше/надёжнее/стабильнее использовать TCP-сокеты.
Тем, кто и так выбирает AF_UNIX, можно дальше не читать.
Начнём с краткой выжимки из теории.
Сокет — один из интерфейсов межпроцессного взаимодействия, позволяющий разрабатывать клиент-серверные системы для локального или сетевого использования. Так как мы рассматриваем в сравнении (с одной стороны) Unix-сокеты, то в дальнейшем будем говорить об IPC в пределах одной машины.
В отличии от именованных каналов, при использовании сокетов прослеживается отличие между клиентом и сервером. Механизм сокетов позволяет создавать сервер к которому подключается множество клиентов.
Как реализуется взаимодействие со стороны сервера:
— системный вызов socket создаёт сокет, но этот сокет не может использоваться совместно с другими процессами;
— сокет именуется. Для локальных сокетов домена AF_UNIX(AF_LOCAL) адрес будет задан именем файла. Сетевые сокеты AF_INET именуются в соответствии с их ip/портом;
— системный вызов listen(int socket, int backlog) формирует очередь входящих подключений. Второй параметр backlog определяет длину этой очереди;
— эти подключения сервер принимает с помощью вызова accept, который создаёт новый сокет, отличающийся от именованного сокета. Этот новый сокет применяется только для взаимодействия с данным конкретным клиентом.
С точки зрения клиента подключение происходит несколько проще:
— вызывается socket;
— и connect, используя в качестве адреса именованный сокет сервера.
Остановимся внимательнее на вызове int socket(int domain, int type, int protocol) второй параметр которого определяет тип обмена данными используемого с этим сокетом. В нашем сравнении мы будем рассматривать его возможное значение SOCK_STREAM, являющееся надежным, упорядоченным двунаправленным потоком байтов. То есть в рассмотрении участвуют сокеты вида
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
и
sockfd = socket(AF_INET, SOCK_STREAM, 0);
Структура сокета в домене AF_UNIX проста:
В домене AF_INET несколько сложнее:
и на её заполнение мы понесём дополнительные расходы. В частности, это могут быть расходы на ресолвинг (gethostbyname) и/или выяснение того с какой стороны разбивать яйца (htons).
Также сокеты в домене AF_INET, несмотря на обращение к localhost, «не знают» того, что они работают на локальной системе. Тем самым они не прилагают никаких усилий, чтобы обойти механизмы сетевого стека для увеличения производительности. Таким образом мы «оплачиваем» усилия на переключения контекста, ACK, TCP управление потоком, маршрутизацию, разбиение больших пакетов и т.п. То есть это «полноценная TCP работа» несмотря на то, что мы работаем на локальном интерфейсе.
В свою очередь сокеты AF_UNIX «осознают», что они работают внутри одной системы. Они избегают усилий на установку ip-заголовков, роутинг, расчёт контрольных сумм и т.д. Кроме того, раз в домене AF_UNIX используется файловая система в качестве адресного пространства, мы получаем бонус в виде возможности использования прав доступа к файлам и управления доступа к ним. Тем самым мы можем без существенных усилий ограничивать процессам доступ к сокетам и, опять же, не несём затрат на этапы обсепечения безопасности.
Проверим теорию на практике.
Мне лень писать серверную часть, потому воспользуюсь тем же redis-server. Его функционал отлично для этого подходит и заодно проверим справедливы ли были обвинения в его адрес. Клиентские части набросаем свои. Будем выполнять простейшую команду INCR со сложностью O(1).
Создание сокетов намеренно помещаем внутри циклов.
TCP-клиент:
Тестируем с одним клиентом:
И теперь для двадцати паралелльных клиентов отправляющих 500000 запросов каждый.
для TCP: 6:12.86
для UNIX: 4:11.23
Тем самым, в целом, аргументами в пользу TCP-сокетов может служить лишь мобильность применения и возможность простого масштабирования. Но если же вам требуется работа в пределах одной машины, то выбор, безусловно, в пользу UNIX-сокетов. Поэтому выбор между TCP- и UNIX-сокетами — это, в первую очередь, выбор между переносимостью и производительностью.
На сим предлагаю любить Unix-сокеты, а вопросы тупоконечностей оставить жителям Лилипутии и Блефуску.
Сокет UNIX представляет собой механизм межпроцессного взаимодействия , который позволяет осуществлять обмен данными между двунаправленных процессов , работающих на одной и той же машине.
Сокеты IP (особенно сокеты TCP / IP) - это механизм, позволяющий осуществлять связь между процессами по сети. В некоторых случаях вы можете использовать сокеты TCP / IP для связи с процессами, запущенными на одном компьютере (с помощью интерфейса обратной связи).
Доменные сокеты UNIX знают, что они выполняются в одной и той же системе, поэтому они могут избежать некоторых проверок и операций (например, маршрутизации); что делает их быстрее и легче, чем IP-сокеты. Поэтому, если вы планируете взаимодействовать с процессами на одном хосте, это лучший вариант, чем IP-сокеты.
Редактирование: Согласно комментарию Нильса Тедтманна : сокеты домена UNIX подчиняются разрешениям файловой системы, в то время как сокеты TCP можно контролировать только на уровне фильтра пакетов.
Возможно, добавьте, что сокеты домена UNIX подчиняются разрешениям файловой системы, а сокеты TCP - нет. В результате гораздо проще регулировать, какие пользователи имеют доступ к сокету домена UNIX, чем к сокету TCP.
@Pacerier Unix-сокеты - это просто один из способов достижения Unix IPC (совместно используемой межпроцессной памяти среди других), поэтому было бы неправильно называть unix-сокеты Unix IPC.
TCP-сокеты тоже обрабатываются Unix? TCP-сокеты является частью спецификации протокола TCP или любой протокол может использовать IP-сокеты?
@Federico Я опубликовал ответ, который пытается ответить на ваш запрос. Если вам требуется больше информации, пожалуйста, отправьте новый вопрос.
Вы можете перечислить локальные unix-сокеты своего компьютера с помощью следующей команды:
@expert, именованные каналы в Windows равны именованным каналам в Unix. Сокеты IPC в Unix не имеют аналогов в Windows
В чем разница между сокетом Unix и сокетом TCP / IP?
Разъем TCP / IP используется для связи по сетям TCP / IP. Подключенный TCP-сокет идентифицируется по комбинации локального IP-адреса, локального порта, удаленного IP-адреса и удаленного порта. Прослушивающий сокет TCP определяется локальным портом и, возможно, локальным IP. AIUI по крайней мере в сокетах Linux / TCP / IP всегда приводит к генерации и декодированию пакетов TCP / IP, даже если клиент и сервер находятся на одном компьютере.
Сокет домена unix (иногда сокращенный до сокета unix), с другой стороны, работает на одном компьютере. Прослушивающие сокеты живут в иерархии файловой системы, и доступ к ним может контролироваться разрешениями файловой системы.
Кроме того, процесс, принимающий соединение через сокет Unix, может определить идентификатор пользователя процесса, который подключается. Это может избежать необходимости в шаге аутентификации. Вместо того, чтобы генерировать пароль для вашего сервера базы данных и включать его копию в код вашего веб-приложения, вы можете просто сообщить серверу базы данных, что пользователь, выполняющий веб-приложение, имеет доступ к соответствующей учетной записи пользователя в базе данных.
TCP-сокеты тоже обрабатываются Unix?
TCP-сокеты являются частью спецификации протокола TCP
Спецификации интернет-протокола имеют тенденцию касаться только того, что происходит в сети, спецификация TCP содержит определение Socket, но это определение не совпадает с тем, как термин используется в «API сокетов».
«API сокетов», как мы знаем, было введено BSD, но позже было скопировано повсеместно и включено как часть стандарта posix. Основные вещи для сокетов TCP и UDP, как правило, одинаковы для разных платформ, но более сложные вещи и вещи, взаимодействующие с другими частями ОС, различаются, например, в Unix-подобных системах сокет идентифицируется дескриптором файла и может быть прочитанным / записанным файловыми API, это не относится к Windows.
Некоторые расширения API сокетов были задокументированы в rfcs, но эти RFC являются только «информационными».
или любой протокол может использовать IP-сокеты?
Когда приложение явно создает сокет, используя функцию «сокет» (сокеты также создаются функцией accept), он передает три параметра: «домен», «тип» и «протокол». Между ними эти три параметра могут использоваться для выбора множества различных типов сокетов.
- домен выбирает семейство используемых протоколов / адресов, например, AF_INET для ipv4, AF_INET6 для ipv6, AF_Unix для путей файловой системы unix и т. д.
- Тип выбирает семантику связи, основными из которых являются датаграмма и поток, но есть и другие более специализированные типы.
- протокол выбирает протокол для использования, если он установлен в 0, будет использоваться протокол по умолчанию для комбинации Домена и типа.
«Прослушивающие сокеты живут в иерархии файловой системы, и доступ к ним может контролироваться разрешениями файловой системы». Означает ли это, что два сервера, которые имеют доступ к одной и той же файловой системе, могут обмениваться данными через сокет?
Работа над приложением на базе Android и iOS, которое требует связи с сервером, работающим на том же устройстве. В настоящее время используется петлевое соединение TCP для связи с приложением и сервером (приложение написано на пользовательском уровне, сервер написан на C ++ с использованием Android NDK)
Мне было интересно, улучшит ли производительность замена межсетевого взаимодействия на сокет домена Unix?
Или в целом есть какие-либо доказательства / теории, подтверждающие, что сокет домена Unix даст лучшую производительность, чем соединение с обратной связью TCP?
Помните, что локальным сокетам (сокетам домена UNIX) нужен файл в файловой системе. Использование адреса обратной связи TCP позволяет сохранить все в памяти. А если вам нужно использовать удаленные сокеты TCP, может быть проще интегрировать другой сокет TCP, чем возиться с новым семейством сокетов и адресов.
@JoachimPileborg При разработке только для Linux (Android) есть возможность использовать абстрактные адреса сокетов домена UNIX, которым не нужен файл в файловой системе.
@Someprogrammerdude Им нужен файл в файловой системе, но это не значит, что все идет на диск и обратно.
@Someprogrammerdude В файловой системе сохраняется только информация о имени файла, владельце и правах доступа. Вся фактическая передача данных происходит полностью в памяти.
Да, локальная межпроцессная связь через сокеты домена unix должна быть быстрее, чем связь через loopback-соединения localhost, потому что у вас меньше накладных расходов TCP, см. Здесь .
первая ссылка цитирует вторую ссылку, которая датируется 2005 годом (старая). и это касается только FreeBSD
Этот ответ неверен, при тестировании loopback tcp на современном Linux так же быстро, а иногда и быстрее, чем UDS. при необходимости может предоставить эталонный тест
Это абсолютно правильный ответ. Интерфейс обратной связи по-прежнему является TCP, что означает, что у вас все еще есть накладные расходы TCP (контроль перегрузки, управление потоком, управление потоком (упорядочение IP-пакетов, повторная передача и т. Д.)). Доменные сокеты Unix не выполняют ничего из вышеперечисленного, потому что он был разработан с нуля для локального запуска, что означает отсутствие проблем с перегрузкой, отсутствие разницы в скорости между сервером / клиентом, требующим управления потоком, отсутствие отброшенных пакетов и т. Д. Google, если есть сомнения , а не новость.
Снижение задержки на 66% и увеличение пропускной способности почти в 7 раз объясняют, почему для большинства критически важного по производительности программного обеспечения есть собственный протокол IPC.
Мне кажется, их продукт - это ответ на проблему! Может быть, поэтому они отвечают на эти вопросы; потому что они знают ответ.
Это отличный ответ, потому что в нем есть цифры. Пропускная способность от TCP к UNIX на 350% лучше, от UNIX к PIPE - на 40% на i5.
@GreenReaper Ответ действительно актуален, но линейка нашего продукта Torusware Speedus . поставляется с двумя версиями, Speedus Lite и Speedus Extreme Performance (EP) нет, и это заставляет все это звучать как дешевую рекламу.
Спам. И нет, его продукт не имеет отношения к сравнению сокетов TCP и Unix. Есть много разумных альтернатив сокетам - каждая из них выходит за рамки того, что запрашивает OP
Использование этого инструмента недостаточно объяснено. Есть ли какая-то страница, объясняющая, как вызывать клиент и сервер?
Redis тесты показывают доменный сокет Unix может быть значительным быстрее , чем TCP шлейф.
Когда программы тестирования сервера и клиента работают на одном компьютере, можно использовать как петлевые сокеты TCP / IP, так и сокеты домена unix. В зависимости от платформы сокеты домена unix могут достигать примерно на 50% большей пропускной способности, чем петля TCP / IP (например, в Linux). По умолчанию redis-benchmark использует петлевую проверку TCP / IP.
Однако эта разница имеет значение только при высокой пропускной способности.
When the host is "localhost", MySQL Unix clients use a Unix socket, AKA Unix Domain Socket, rather than a TCP/IP socket for the connection, thus the TCP port doesn't matter.
3 Answers 3
A UNIX socket, AKA Unix Domain Socket, is an inter-process communication mechanism that allows bidirectional data exchange between processes running on the same machine.
IP sockets (especially TCP/IP sockets) are a mechanism allowing communication between processes over the network. In some cases, you can use TCP/IP sockets to talk with processes running on the same computer (by using the loopback interface).
UNIX domain sockets know that they’re executing on the same system, so they can avoid some checks and operations (like routing); which makes them faster and lighter than IP sockets. So if you plan to communicate with processes on the same host, this is a better option than IP sockets.
Edit: As per Nils Toedtmann's comment: UNIX domain sockets are subject to file system permissions, while TCP sockets can be controlled only on the packet filter level.
Maybe add that UNIX domain sockets are subject to file system permissions, while TCP sockets are not. As a result, it is much easier to regulate which users have access to a UNIX domain socket than it is for a TCP socket.
@Pacerier Unix sockets is simply one way to achieve unix IPC (shared Interprocess memory amongst others), so it wouldn't be correct to call unix sockets unix IPC .
TCP sockets are handled by Unix too? TCP sockets is part of the TCP protocol specification or any protocol could use IP Sockets ?
@Federico I posted an answer which tries to address your query, if you require more depth please post a new question.
You can list your own machine local unix sockets with the following command:
MacOS: [jbmeerkat comment]
@expert, named pipes in Windows is equal to named pipes in Unix. IPC sockets in Unix have no equivalence in Windows
What's the difference between Unix socket and TCP/IP socket?
A TCP/IP socket is used for communication across TCP/IP networks. A connected TCP socket is identified by the combination of local IP, local port, remote IP and remote port. A listening TCP socket is identified by local port and possibly local IP. As I understand it, at least on linux TCP/IP sockets always result in the generation and decoding of TCP/IP packets, even if the client and server are on the same machine.
A unix domain socket (sometimes shortened to unix socket) on the other hand operates on a single machine. Listening sockets live in the filesystem hierarchy and access to them can be controlled by filesystem permissions.
Furthermore a process accepting a connection on a Unix socket can determine the user ID of the process that connects. This can avoid the need for an authentication step. Rather than generating a password for your database server and including a copy of it in your webapp's code you can just tell the database server that the user running the webapp has access to the corresponding user account in the database.
TCP sockets are handled by Unix too?
TCP sockets is part of the TCP protocol specification
Internet protocol specifications only tend to concern what happens on the wire, the TCP spec contains a definition of Socket but that definition is not the same as how the term is used by the "sockets API".
The "sockets API" as we know it was introduce by BSD but was later copied all over the place and is included as part of the posix standard. The basic stuff for TCP and UDP sockets tends to be much the same across different platforms but more advanced stuff and stuff that interacts with other parts of the OS varies, for example on unix-like systems a socket is identified by a file handle and can be read/written by the file APIs, this is not the case on windows.
Some extensions to the sockets API have been documented in rfcs but those RFCs are only "informational".
or any protocol could use IP Sockets ?
When an application explicitly creates a socket using the "socket" function (sockets are also created by the accept function) it passes three parameters, "domain", "type" and "protocol". Between them these three parameters can be used to select many different types of socket.
Мы в PushAll обрабатываем несколько тысяч запросов в секунду для получения статистики доставки и открытия уведомлений и для передачи контента оповещений. Обычная БД вроде MySQL не справляется с таким потоком запросов и не может так быстро отвечать.
Стараясь все больше операций перенести на быстрые NoSQL хранилища вроде Redis, мы хотим знать как эффективнее его использовать и не будет ли у нас проблем с большим количеством соединений.
Также для работы мы используем форки PHP и нам было интересно, а как поведет себя Redis, если мы будем делать несколько тысяч соединений в одновременно в нескольких потоках. Мы решили поделиться с сообществом нашими тестами.
Мы тестируем на одном из VPS PushAll:
CPU: Intel Xeon E5-1650v2 3.5 Ghz — 2 ядра.
RAM: 3 Gb DDR3 1866Mhz
Мы написали многопоточного бота PHP, который:
- Делает форки в цикле — 100 форков без каких либо задержек
- Каждый форк в своем цикле, 1000 раз создает соединение с Redis и производит инкремент
- Родительский процесс ждет 3 секунды и берет значение, если не ждать — Redis вернет не полное значение инкеремента
Также мы протестировали вариант с 1000 форками и как будут отличаться результаты при использовании UNIX-сокета и TCP.
100 форков, 1000 соединений в каждом, TCP
100 форков, 1000 соединений в каждом, UNIX-сокет
TCP-сокет в среднем на 30% медленнее. (напомню, тут испытывается больше не производительность работы самого Redis, а то, как он обрабатывает соединения)
1000 форков, 1000 соединений в каждом, TCP+UNIX
За 3 секунды Redis не успел их у себя до конца обработать — это одна из деталей, которую надо учитывать. Если слишком быстро считывать значения, можно поймать момент, когда они еще старые.
Что самое интересное, при проведение того же самого теста, но для unix-сокета, мы получаем ошибки:
То есть, unix-сокет не смотря на то, что он быстрее, может обрабатывать несколько меньшее количество запросов. Либо как вариант — возможно, что из за того что он такой быстрый не справляется уже сам сервер Redis'а.
Мы проводили подобные тесты и для php-fpm — там также TCP-сокет давал меньше ошибок со связкой с NGINX чем UNIX-сокет. Разница в скорости была там незначительна.
Оказывается pconnect работает в форках (странно)
Взял случай 100 процессов TCP:
pconnect
Для сравнения UNIX сокет на 100 форках:
pconnect
Причем, что интересно, при использовании pconnect — разница между TCP и UNIX сокетом не такая уж и большая 5-10%. При этом даже сделав все, что мне предлагали в комментариях — мне не удалось заставить работать unix-сокеты при 1000 форках.
UNIX Socket
pconnect
connect — падает в Fatal error: Uncaught RedisException: Redis server went away in…
Читайте также: