Рубрики
Uncategorized

Что значит прочитать исходный код – драйвер событий Redis 4 – сервера с помощью Dabin? (I)

Автор оригинала: David Wong.

Как мы все знаем, сервер Redis является драйвером событий. Итак, что означает событийный подход для Redis? Как реализовать управление событиями в исходном коде? Сегодня давайте познакомимся с драйверами событий серверов Redis.

Для Redis сервер должен обрабатывать следующие два типа событий:

  • Событие файла Сервер Redis соединяется с клиентом через сокет, а событие файла-это абстракция работы сокета сервером. Связь между сервером и клиентом приведет к соответствующим событиям файла, и сервер выполнит ряд операций сетевого взаимодействия, отслеживая и обрабатывая эти события.
  • Событие времени Некоторые операции на серверах Redis (например, функции Cron сервера) должны выполняться в определенный момент времени, и события времени являются абстракцией таких операций синхронизации сервером.

Далее давайте рассмотрим следующие события.

Redis разработала собственный процессор сетевых событий на основе режима реактора, который называется Обработчик событий файлов :

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

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

1 Состав обработчика событий файлов

На рисунке 1 показаны четыре компонента процессора файловых событий:

  • Разъем;
  • Программа мультиплексирования ввода-вывода;
  • Диспетчер событий файлов;
  • Обработчик событий;

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

Мультиплексоры ввода-вывода отслеживают несколько сокетов и распределяют те сокеты, которые генерируют события, диспетчеру событий файлов.

Хотя одновременно может происходить несколько событий с файлами, мультиплексоры ввода-вывода всегда помещают все сокеты, генерирующие события, в очередь, а затем передают через очередь в Порядок и синхронизацию Таким образом, каждый сокет передается диспетчеру событий файлов. Когда событие, сгенерированное предыдущим сокетом, обработано (то есть сокет выполняется обработчиком событий, связанным с событием), мультиплексор ввода-вывода продолжит передачу следующего сокета диспетчеру событий файлов. Как показано на рисунке 2:

Диспетчер событий файлов получает сокеты от мультиплексора ввода-вывода и вызывает соответствующий обработчик событий в соответствии с типом событий, генерируемых сокетами.

Сервер связывает различные обработчики событий для сокетов, которые выполняют разные задачи. Эти процессоры, по сути, являются функцией . Они определяют действия, которые сервер должен выполнять при возникновении события.

Реализация программы мультиплексирования 2 ввода-вывода

Все функции мультиплексора ввода-вывода Redis являются общими благодаря упаковке Select, epoll, newport и kqueue Реализованы эти библиотеки мультиплексирования ввода-вывода. Каждая библиотека мультиплексирования ввода-вывода соответствует одному файлу в исходном коде Redis, такому как ae_select.c, ae_poll.c, ae_kqueue.c и т. Д.

Поскольку Redis реализует один и тот же API для каждой библиотеки мультиплексоров ввода-вывода, базовая реализация мультиплексора ввода-вывода является взаимозаменяемой, как показано на рисунке 3:

Исходный код реализации мультиплексора ввода-вывода Redis #включить Макрос определяет соответствующие правила, и программа ** автоматически выбирает библиотеку мультиплексирования ввода-вывода с наивысшей производительностью в системе во время компиляции в качестве базовой реализации программы мультиплексирования ввода-вывода Redis, что гарантирует совместимость и высокую производительность Redis на различных платформах. Соответствующий исходный код выглядит следующим образом:

/* Include the best multiplexing layer supported by this system.
 * The following should be ordered by performances, descending. */
#ifdef HAVE_EVPORT
#include "ae_evport.c"
#else
    #ifdef HAVE_EPOLL
    #include "ae_epoll.c"
    #else
        #ifdef HAVE_KQUEUE
        #include "ae_kqueue.c"
        #else
        #include "ae_select.c"
        #endif
    #endif
#endif

Виды мероприятий

Мультиплексор ввода-вывода может отслеживать несколько сокетов ae.h/AE_READABLE и ae.h/AE_WRITABLE События, эти два типа событий и операций с сокетами имеют следующую соответствующую взаимосвязь:

  • Когда сокет сервера становится читаемым, сокет генерирует событие AE_READABLE . Читаемость сокета здесь относится к событию AE_READABLE, которое происходит, когда клиент выполняет операции записи или закрытия сокета или когда появляется новый приемлемый сокет (клиент выполняет операции подключения к прослушивающему сокету сервера).
  • Когда сокет сервера становится доступным для записи, сокет генерирует событие AE_WRITABLE.

Мультиплексор ввода-вывода позволяет серверу одновременно прослушивать события AR_READABLE сокета и события AE_WRITABLE. Если сокет генерирует два события одновременно, диспетчер файлов сначала обработает событие AE_READABLE, а затем событие AE_WRITABLE. Проще говоря, если сокет можно прочитать и записать, сервер сначала прочитает сокет, а затем запишет сокет.

4 Обработчик Событий Файлов

Redis записывает несколько процессоров для событий файлов, которые используются для реализации различных требований к сетевому взаимодействию. Например:

  • Чтобы ответить каждому клиенту, подключающемуся к серверу, серверу необходимо Подключить процессор ответов для прослушивания сокетов
  • Чтобы получать запросы команд от клиентов, серверу необходимо Запросить процессор для команды, связанной с клиентским сокетом
  • Чтобы вернуть клиенту результат выполнения команды, серверу необходимо Вернуть процессор для команды ассоциации клиентских сокетов
  • Когда главный и подчиненный серверы реплицируются, Как главному, так и подчиненному серверам требуется соответствующий процессор репликации

Среди этих обработчиков событий наиболее часто используются серверы Процессор ответов на подключение, Процессор запросов команд и Процессор ответов на команды для связи с Клиентом

1) Подключите процессор ответов

сеть.c/принять Tcp-Дескриптор Эта функция представляет собой процессор ответа на подключение Redis, который используется для ответа клиентам, подключающимся к серверам для прослушивания сокетов. Реализация выглядит следующим образом sys/socket.h/accept Упаковка функций.

Когда сервер Redis инициализирован, программа связывает процессор ответа на соединение с событием AE_READABLE сокета прослушивания сервера. Соответствующий исходный код выглядит следующим образом

# server.c/initServer
...
/* Create an event handler for accepting new connections in TCP and Unix
 * domain sockets. */
for (j = 0; j < server.ipfd_count; j++) {
    if (aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE,
        acceptTcpHandler,NULL) == AE_ERR)
        {
            serverPanic(
                "Unrecoverable error creating server.ipfd file event.");
        }
}
...

Когда есть клиент sys/scoket.h/connect , когда сервер функционального подключения прослушивает сокет, сокет генерирует событие AE_READABLE, запускает процессор ответа на соединение для выполнения и выполняет соответствующую операцию ответа на сокет. Как показано на рисунке 4:

2) Процессор командных запросов networking.c/readQueryFromClient Функция является процессором командных запросов Redis, который считывает содержимое командного запроса, отправленного клиентом из сокета, и реализует его следующим образом unistd.h/read Упаковка функций.

Когда клиент успешно подключается к серверу через процессор ответов на подключение, сервер связывает событие AE_READABLE клиентского сокета с процессором запросов команд.( networking.c/acceptCommonHandler Функция).

Когда клиент отправляет запрос команды на сервер, сокет генерирует событие AR_READABLE, запускает процессор запросов команд для выполнения и выполняет соответствующую операцию чтения сокета, как показано на рисунке 5:

В течение всего процесса подключения клиента к серверу сервер всегда запрашивает у процессора команду ассоциации событий AE_READABLE клиентского сокета.

3) Процессор ответов на команды networking.c/sendreplytoclient Функция-это процессор ответов на команды Redis, который отвечает за возврат ответа на команды, полученного сервером после выполнения команды клиенту через сокет.

Когда у сервера есть ответ на команду для отправки клиенту, сервер связывает событие AE_WRITABLE клиентского сокета с обработчиком ответов на команды.( networking.c/handleClientsWithPendingWrites Функция).

Когда клиент будет готов получить ответ на команду от сервера, будет сгенерировано событие AE_WRITABLE, которое запускает процессор ответов на команды для выполнения и выполнения соответствующей операции записи сокета. Как показано на рисунке 6:

Когда ответ на команду будет отправлен, сервер отменит корреляцию события AE_WRITABLE между обработчиком ответа на команду и клиентским сокетом. Соответствующий исходный код выглядит следующим образом:

# networking.c/writeToClient
...
if (!clientHasPendingReplies(c)) {
    c->sentlen = 0;
    # Buffer Buffer Command Reply Sent, Delete Socket and Event Association
    if (handler_installed) aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);

    /* Close connection after entire reply has been sent. */
    if (c->flags & CLIENT_CLOSE_AFTER_REPLY) {
        freeClient(c);
        return C_ERR;
    }
}
...

5 Событий Подключения Клиент-Сервер

Ранее у нас было общее представление о процессе соединения между клиентом и сервером в форме отладки. Теперь, с точки зрения событий файлов, мы снова будем отслеживать весь процесс подключения клиентов Redis к серверам и отправки команд, чтобы увидеть, что происходит в процессе и как обрабатываются эти события.

Давайте сначала рассмотрим процесс установления соединения между клиентом и сервером.

  1. Запустите наш сервер Redis (127.0.0.1-8379). После успешного запуска отслеживается событие AE_READABLE сокета сервера (127.0.0.1-8379), которое соответствует подключению процессора ответов. ( server.c/initServer() )。
  2. Подключитесь к серверу с помощью redis -cli. Это означает, что серверный сокет (127.0.0.1-8379) сгенерирует событие AR_READABLE, которое запускает выполнение процессора ответа на соединение.( networking.c/acceptTcpHandler() )。
  3. Ответ на запрос на подключение клиента, создайте клиентский сокет, сохраните информацию о состоянии клиента и обработайте событие с возможностью чтения и запрос команды клиентского сокета( networking.c/acceptCommonHandler () ), чтобы сервер мог получать запросы команд от клиента.

На данный момент клиент успешно установил соединение с сервером. В описанном выше процессе мы все еще можем отлаживать с помощью GDB, чтобы увидеть процесс выполнения функции. Конкретный процесс отладки выглядит следующим образом:

gdb ./src/redis-server
(gdb) B acceptCommonHandler # Set breakpoints for acceptCommonHandler functions
(gdb) R redis-conf -- port 8379#Start the server

Откройте другое окно и используйте redis-cli для подключения к серверу: redis-cli -p 8379

Вернувшись в окно сервера, мы увидим, что вошли в режим отладки GDB, введите: в стек Вы можете увидеть информацию о стеке, показанную на рисунке 6.

Теперь давайте взглянем на выполнение заказа:

  1. Клиент отправляет запрос команды на сервер. Клиентский сокет генерирует событие AE_READABLE, запускает readQueryFromClient для выполнения и считывает содержимое команды клиента.
  2. В соответствии с содержанием команды, отправленной клиентом, соответствующие значения атрибутов значений, такие как argc и argv клиента, форматируются.
  3. Найдите соответствующую функцию в соответствии с именем команды. server.c/команда процесса() в команда поиска Вызов функции;
  4. Функция, связанная с именем команды, выполняется для получения возвращаемого результата, и генерируется клиентский сокет. server.c/processCommad() в вызов Вызовы функций.
  5. Верните ответ на команду и удалите связь между клиентским сокетом и событием AE_WRITABLE. network.c/writeToClient() Функция.

На рисунке 7 показана информация о стеке процесса выполнения команды. На рисунке 8 показана информация о стеке процесса ответа на команду.

резюме

  1. Сервер Redis является драйвером событий, и события, обрабатываемые сервером, делятся на События времени и События документов Двух типов.
  2. События файла-это абстракции операций сокета. ** Каждый раз, когда сокет становится приемлемым, доступным для записи или чтения, происходит соответствующее событие файла.
  3. События файла классифицируются на события AE_READABLE (события чтения) и события AE_WRITABLE (события записи).