Pull to refresh
6
0
Алексей Кашавкин @AKashavkin

Linux kernel, eBPF, network stack and protocols

Send message

С включенной rosett'ой runcher desktop, работает в разы быстрее docker desktop'a и при переходе на ранчер intellisense перестал тупить при работе с кодом ядра.

Попробовали? Если да, то как впечатления? По производительности в сравнении с Docker Desktop пошустрее? Я наоборот на арме (М1) сейчас играюсь с dev контейнерами под проект на x86 с линуксом, впечатления положительные, но компиляция простеньких тулов происходит по времени не очень конечно и разницы по времени компиляции в контейнере, запущенного в ранчере или докере, пока не вижу.

А как именно пришли к мысли с аккаунтингом softirq? В статье не совсем углядел для себя причинно-следственную связь после инструментированния упомянутых функций. Спрашиваю, поскольку сам перечитываю переодически сетевые статьи с пакетклауда, для освежения в памяти, и использую для трассирования интрументы, скрипты bcc/bpftrace/xdp. И собственно, я бы к такому выводу после интрументирования, описанного в статье, не пришел бы. Не исключаю, что у меня опыта по исследованию проблем с сетевым стеком будет по менее. Я в это все окунулся можно сказать недавно, поэтому видимо такой вывод не кажется мне очевидным. В связи с этим интересно узнать, как Вы все-таки к этому пришли поподробнее.

Купил книгу и прочитал, спасибо за перевод, за то что он есть. В сложных темах иногда все же лучше обратиться к русскоязычным источникам, но стоит отметить, что с переводом местами проблема. У меня есть еще в чтении книги от вашего издательства и там пока перевод нареканий не вызывает.

Что здесь с переводом не так?! Очень часто дословно переведено слово print, обязательно в книге оно переводится как напечатать, но чаще всего по контексту логичнее "print" перевести как "вывести/вывести на экран", был еще момент с переводом image применительно к контейнерам, которое так же перевели дословно, но корректнее было бы употребить - образ/шаблон, что в том же абзаце и делалось. Так же в 7 главе есть обилие терминов, которые переведены не то, чтобы некорректно, но как минимум неуместно и нужно признаться (хоть я и сам стараюсь избегать англицизмов в своей речи), но все же некоторую терминологию лучше оставить без перевода как есть, это такие слова как polling, offload, mitigation и т.д и т.п. Русский язык уже плохо адаптирован под описание современных технологий или систем, поэтому из некоторых слов уже пора самим делать новые англицизмы для описания тех или иных вещей, связанных с ИТ, иначе их перевод только сбивает с толку, мне действительно порой приходилось заглядывать в оригинал, чтобы понять, что же имелось в том или ином абзаце ввиду.

Есть еще пример в главе 8 с capabilities, признаюсь я сам до сих пор не знаю как корректно употреблять в русском языке этот термин и его значение, но если между коллегами я применяю слово "возможности" меня всегда могут понять двусмысленно. Хороший пример с англицизмом есть в этой же главе, переводчик не стал как либо переводить слово alias и так и написал алиас, по такому примеру считаю все выше описанное должно было быть переведено (поллинг, оффлоад и т.д.).

В остальном, могу только еще раз поблагодарить за книгу, я узнал действительно очень много нового и нужного материала, думаю читая в оригинале было бы гораздо труднее освоить такую тему. Надеюсь, что вы еще будете переводить книги связанные с BPF или внутренним устройством ядра Linux.

Однозначно огромное спасибо за статью! Впервые прочитал такой подробный разбор по хождению трафика в опенстеке, очень было нужно.

То есть полученный пакет улетит в порт 3, за которым уже находится виртуальная машина instance-00000003.

Поправьте, пожалуйста, тут на instance-00000002. Это в абзаце: Две машины на разных гипервизорах в одной L2 сети. При беглом прочтении не много сбило с толку.

Собственно, солюшины какие-либо я для этого не читал, модуль нашел не гуглением, а просмотром доступных реп в гитхабе и исследованием их.

Вся проблема лишь в том, что у меня нет углубленного опыта работы с nginx'ом, поскольку я больше ориентируюсь на проекты связанные с виртуализацией, а для проксирования ранее больше использовал haproxy. Nginx в основном ранее настраивал для простых вещей и меня ввела в заблуждение сама его документации, что ssl терминация для проксирования tcp доступна в его платной версии (ссылку я скидывал в одном из комментов и она есть в статье, там конечно явно это не написано, но в prerequisites не упоминается опенсорсный nginx).

В остальном, я видел немалое количестве проектов, чтобы предположить, что не всегда есть возможность, работая с «динозавровым» легаси «строить очень гибкие и эффективные пайплайны» и возможно в одном из таких проектов кому-то будет удобно задействовать кафку именно таким образом. Статья не истинна в последней инстанции и сама Кафка обладает достаточной гибкостью, чтобы в нее писать так как захочется желающему работать с ней и не использовать то, что я написал. Это лишь +еще один способ.
Схема рабочая — бесспорно. :) Но я делаю лог-сервис для наших пользователей, они могут использовать различные лог шиперы, главное, чтобы они имели возможность писать в Кафку и для меня было важно обеспечить им шифрованный канал. А далее, как в статье написано, поскольку наши серты кафка не приняла из-за их схемы шифрования, я поработал над костылем, но мы его не используем. Договорились с СБ и конвертнули серты, прописав их в конфигурацию Кафки. Nginx нам теперь не нужен, а сама статья больше для поделиться опытом и думаю будет кому-нибудь полезной.
Ваша правда — да, это действительно работает, не без танцев, но было действительно интересное исследование.

Что по итогу получилось: tcp-стрим с SSL-терминацией действительно настроить можно, но сразу записать что-либо в топик не удалось, при трейсинге любого клиента, я заметил интересную особенность их поведения (не важно на чем они написаны: python, go, java и какую либу внутри себя используют). В общем, при инициализации первого соединения клиентом к брокеру, он проходил через nginx и в нем он запрашивают общую инфу о брокере, хостнейм брокера у меня является так же fqdn'ом, клиент получал тем самым fqdn брокера, резолвил его и вторым запросом уже устанавливал коннект к брокеру напрямую, миную nginx, при этом в логах кафки с трейсингом, никакой инфы о том, что клиент хочет писать с SSL. Там буквально ни слова об этом, но из-за этого клиент записать в топик ничего не мог, поскольку в клиенте я указал security_protocol='SSL', а брокер у меня работает по PLAINTEXT. Xтобы обмануть клиента, я на клиенте в хостс прописал fqdn брокера с адресом самого nginx'a и запись в топики пошла. Подампил трафик между клиентом, nginx'ом и кафкой, и действительно теперь вижу шифрованный трафик от клиента до nginx'a и не шифрованный от nginx'a до кафки. Это действительно работает, благодарю за комментарии, получил интересный опыт. :)

Прикладую трейс сети до хука в хостс:
Скрытый текст
strace -s100000 -f -e trace=network python3 k_send.py
strace: Process 18077 attached
[pid 18077] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=18077, si_uid=0, si_status=0, si_utime=0, si_stime=0} ---
socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, [3, 4]) = 0
socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_IP) = 6
setsockopt(6, SOL_TCP, TCP_NODELAY, [1], 4) = 0
connect(6, {sa_family=AF_INET, sin_port=htons(9092), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress)
connect(6, {sa_family=AF_INET, sin_port=htons(9092), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
getsockname(6, {sa_family=AF_INET, sin_port=htons(60682), sin_addr=inet_addr("127.0.0.1")}, [16]) = 0
getpeername(6, {sa_family=AF_INET, sin_port=htons(9092), sin_addr=inet_addr("127.0.0.1")}, [16]) = 0
getsockopt(6, SOL_SOCKET, SO_TYPE, [1], [4]) = 0
getpeername(6, {sa_family=AF_INET, sin_port=htons(9092), sin_addr=inet_addr("127.0.0.1")}, [16]) = 0
strace: Process 18078 attached
[pid 18076] sendto(4, "x", 1, 0, NULL, 0) = 1
[pid 18076] sendto(4, "x", 1, 0, NULL, 0) = 1
[pid 18078] recvfrom(3, "xx", 1024, 0, NULL, NULL) = 2
[pid 18078] recvfrom(3, 0x7fa4d40032a0, 1024, 0, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable)
[pid 18076] sendto(4, "x", 1, 0, NULL, 0) = 1
[pid 18076] sendto(4, "x", 1, 0, NULL, 0) = 1
[pid 18078] recvfrom(3, "xx", 1024, 0, NULL, NULL) = 2
[pid 18078] recvfrom(3, 0x7fa4d4005e60, 1024, 0, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable)
[pid 18078] socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 7
[pid 18078] connect(7, {sa_family=AF_UNIX, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
[pid 18078] socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 7
[pid 18078] connect(7, {sa_family=AF_UNIX, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
[pid 18078] socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 7
[pid 18078] setsockopt(7, SOL_IP, IP_RECVERR, [1], 4) = 0
[pid 18078] connect(7, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("172.28.0.253")}, 16) = 0
[pid 18078] sendmmsg(7, [{msg_hdr={msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="\6\364\1\0\0\1\0\0\0\0\0\0\17kafka-0-15-186\2back\2gcorelabs\3local\0\0\1\0\1", iov_len=43}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, msg_len=43}, {msg_hdr={msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="\354\17\1\0\0\1\0\0\0\0\0\0\17kafka-0-15-186\2back\2gcorelabs\3local\0\0\34\0\1", iov_len=43}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, msg_len=43}], 2, MSG_NOSIGNAL) = 2
[pid 18078] recvfrom(7, "\6\364\201\200\0\1\0\1\0\2\0\4\17kafka-0-15-186\2back\2gcorelabs\3local\0\0\1\0\1\300\f\0\1\0\1\0\0\1\32\0\4\n\\@\272\300\37\0\2\0\1\0\0\1\25\0\23\3ns1\tgcorelabs\3net\0\300\37\0\2\0\1\0\0\1\25\0\23\3ns2\4ns\10services\0\300f\0\1\0\1\0\0\1f\0\4\\\337M5\300G\0\1\0\1\0\0\1f\0\4\\\337d5\300f\0\34\0\1\0\09\206\0\20*\3\220\300\231\220\0\0\0\0\0\0\0\0 S\300G\0\34\0\1\0\1\213\6\0\20*\3\220\300\231\220\0\0\0\0\0\0\0\0\20S", 2048, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("172.28.0.253")}, [28->16]) = 209
[pid 18078] recvfrom(7, "\354\17\201\200\0\1\0\0\0\1\0\0\17kafka-0-15-186\2back\2gcorelabs\3local\0\0\34\0\1\300\34\0\6\0\1\0\0\1,\0>\3ns1\tgcorelabs\3net\0\7support\tgcorelabs\3com\0`\267\307\16\0\0\25\30\0\0\25\30\0\22u\0\0\0\1,", 65536, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("172.28.0.253")}, [28->16]) = 117
[pid 18078] socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_IP) = 7
[pid 18078] setsockopt(7, SOL_TCP, TCP_NODELAY, [1], 4) = 0
[pid 18078] connect(7, {sa_family=AF_INET, sin_port=htons(9092), sin_addr=inet_addr("10.0.15.186")}, 16) = -1 EINPROGRESS (Operation now in progress)
[pid 18078] connect(7, {sa_family=AF_INET, sin_port=htons(9092), sin_addr=inet_addr("10.0.15.186")}, 16) = -1 EALREADY (Operation already in progress)
[pid 18078] connect(7, {sa_family=AF_INET, sin_port=htons(9092), sin_addr=inet_addr("10.0.15.186")}, 16) = 0
[pid 18078] getsockname(7, {sa_family=AF_INET, sin_port=htons(42378), sin_addr=inet_addr("10.0.15.140")}, [16]) = 0
[pid 18078] getpeername(7, {sa_family=AF_INET, sin_port=htons(9092), sin_addr=inet_addr("10.0.15.186")}, [16]) = 0
[pid 18078] getsockopt(7, SOL_SOCKET, SO_TYPE, [1], [4]) = 0
[pid 18078] getpeername(7, {sa_family=AF_INET, sin_port=htons(9092), sin_addr=inet_addr("10.0.15.186")}, [16]) = 0
[pid 18076] sendto(4, "x", 1, 0, NULL, 0) = 1
[pid 18078] +++ exited with 0 +++
+++ exited with 0 +++

И после:
Скрытый текст
strace -s100000 -f -e trace=network python3 k_send.py
strace: Process 18208 attached
[pid 18208] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=18208, si_uid=0, si_status=0, si_utime=0, si_stime=0} ---
socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, [3, 4]) = 0
socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_IP) = 6
setsockopt(6, SOL_TCP, TCP_NODELAY, [1], 4) = 0
connect(6, {sa_family=AF_INET, sin_port=htons(9092), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress)
connect(6, {sa_family=AF_INET, sin_port=htons(9092), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
getsockname(6, {sa_family=AF_INET, sin_port=htons(60744), sin_addr=inet_addr("127.0.0.1")}, [16]) = 0
getpeername(6, {sa_family=AF_INET, sin_port=htons(9092), sin_addr=inet_addr("127.0.0.1")}, [16]) = 0
getsockopt(6, SOL_SOCKET, SO_TYPE, [1], [4]) = 0
getpeername(6, {sa_family=AF_INET, sin_port=htons(9092), sin_addr=inet_addr("127.0.0.1")}, [16]) = 0
strace: Process 18209 attached
[pid 18207] sendto(4, "x", 1, 0, NULL, 0) = 1
[pid 18207] sendto(4, "x", 1, 0, NULL, 0) = 1
[pid 18209] recvfrom(3, "xx", 1024, 0, NULL, NULL) = 2
[pid 18209] recvfrom(3, 0x7ff7d40032a0, 1024, 0, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable)
[pid 18207] sendto(4, "x", 1, 0, NULL, 0) = 1
[pid 18207] sendto(4, "x", 1, 0, NULL, 0) = 1
[pid 18209] recvfrom(3, "xx", 1024, 0, NULL, NULL) = 2
[pid 18209] recvfrom(3, 0x7ff7d4005e60, 1024, 0, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable)
[pid 18209] socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 7
[pid 18209] connect(7, {sa_family=AF_UNIX, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
[pid 18209] socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 7
[pid 18209] connect(7, {sa_family=AF_UNIX, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
[pid 18209] socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_IP) = 7
[pid 18209] setsockopt(7, SOL_TCP, TCP_NODELAY, [1], 4) = 0
[pid 18209] connect(7, {sa_family=AF_INET, sin_port=htons(9092), sin_addr=inet_addr("10.0.15.140")}, 16) = -1 EINPROGRESS (Operation now in progress)
[pid 18209] connect(7, {sa_family=AF_INET, sin_port=htons(9092), sin_addr=inet_addr("10.0.15.140")}, 16) = 0
[pid 18209] getsockname(7, {sa_family=AF_INET, sin_port=htons(33920), sin_addr=inet_addr("10.0.15.140")}, [16]) = 0
[pid 18209] getpeername(7, {sa_family=AF_INET, sin_port=htons(9092), sin_addr=inet_addr("10.0.15.140")}, [16]) = 0
[pid 18209] getsockopt(7, SOL_SOCKET, SO_TYPE, [1], [4]) = 0
[pid 18209] getpeername(7, {sa_family=AF_INET, sin_port=htons(9092), sin_addr=inet_addr("10.0.15.140")}, [16]) = 0
[pid 18207] sendto(4, "x", 1, 0, NULL, 0) = 1
[pid 18209] +++ exited with 0 +++
+++ exited with 0 +++

10.0.15.140 — nginx, 10.0.15.186 — брокер кафки
  • ngx_http_kafka_log_module перенаправляет запросы с Nginx'a в Kafk'у.
  • Syslog стандарт и система управления логами.

Тут не провести параллель для сравнения между ними.
Заменил формулировку по поводу проксирования, она действительно была неверной, основной причиной выбора не в пользу tcp-стрима было отсутсвие SSL-терминации. Мне нужно было шифровать трафик до Nginx'a и не шифровать до Kafk'и, все подрбности теперь в самой публикации в части Зачем это нужно
Заменил формулировку
проксировать в Kafka из коробки веб-сервер не может
в публикации, она была действительно неверная. Вспомнил, что дело было не в роутинге, а то, что мне нужен был SSL. Теперь там указана основная причина, почему все сделано именно так:
Однако, поскольку Kafka не использует протокол HTTP для коммуникаций — REST Proxy от Confluent не в счет из-за условий лицензии, — а SSL-терминация при проксирования TCP доступна только в платной версии Nginx, использовать доступные из коробки модули для проксирования было нельзя.

Проблема с сертификатами связана со схемой шифрования, они добавляются в конфигурацию брокеров Kafk'и, поэтому какой-либо нативный клиент эту проблему решить не сможет, поскольку это отдельная сущность.

вы можете принимать сообщения для Kafka

Если рассматривать формулировку с позиции модуля, то да, технически верно написать — отправка сообщений в Kafk'у, но это взято из контекста. В этой формулировке сделан акцент на саму Kafk'у, она принимает/получает сообщения, Nginx является лишь прослойкой, чтобы обеспечить их прием по HTTP/HTTPS.

Связка Kafka — Elasticsearch будет работать через компонент Kafka Connect. Пока проект еще в разработке, мы тестируем различные коннекторы и по готовности посвятим этому отдельную статью со всеми подробностями.
Изначально пробовал настроить передачу сообщений с помощью этого модуля, но не смог в нем реализовать механизм распределения сообщений по топикам. Калтуровский модуль как раз предоставляет такую возможность.
Спасибо, в принципе это я и предполагал, но думал может есть какие-либо еще другие предостережения.
А не подскажите еще такой момент, общее число реплик на пул у нас стоит 3, минимально — 2. Чем будет плохо минимальное значение выставить в 1, оставив общее в 3?
Спасибо за статью, есть теперь чем оперировать перед руководством)) Я сейчас как раз в процессе обновления с 0.94 до Luminous.

Не могли бы Вы только подсказать, вообще сильно ли может влиять разноразмерность дисков на хостах? Я искал бегло инфу на этот счет, но все равно однозначного негатива не находил, но и положительных отзывов с этим тоже. Мы как-то уперлись в такую ситуацию, что серверов под расширения еще нет, они ожидались из-за проблем в финансировании в течении полугода, а мы уже подходили к 80% наполнения всего массива. Из-за этого как не играй с весами, каждое утро я мог наблюдать near full разных OSD. В общем, решили добавлять диски в свободные слоты, но дисков того же объема у нас не оказалось, (тогда у нас было 9 хостов, в каждом по 14 дисков объемом в 900Гб) мы нашли у себя в запасах диски по 1.8Тб и поставили по два в каждый хост, прирост в 32Тб позволил нам дожить до поставок, но уже не рискнули их выводить. Спрашиваю я это к тому, что мне начало казаться, что массив стал более медленным, но я могу ошибаться, просто у нас как-то пока не доходит сделать нормальный мониторинг под все это дело.
Попробуйте импортировать в свою БД и проверьте работоспособность, если заработает, то я тогда внесу это в публикацию.
Такая возможность есть. Почему «важно» было не запускать и не настраивать ownСloud перед подключением формы регистрация, так это только из-за того, что при первой настройке и подключении БД добавляются все таблицы в нее из файла db_structure.xml. И если просмотреть этот файл из архива, то там есть в конце таблица pending_regist, именно ее нужно добавить в sql'ную базу (она и ответственна за форму регистрации), можете с помощью phpMyAdmin добавить эту таблицу, если используете MySQL ну или же через другие WebUI для иных БД. Для добавлении таблицы попробуйте:
CREATE TABLE IF NOT EXISTS `pending_regist` (
  `requested` int(10) NOT NULL,
  `email` varchar(64) NOT NULL,
  `token` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

ALTER TABLE `pending_regist`
 ADD PRIMARY KEY (`requested`);

но скрипт не проверял и гарантии дать не могу, что он с работает.

Information

Rating
Does not participate
Date of birth
Registered
Activity