Как мы все знаем, сервер 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 к серверам и отправки команд, чтобы увидеть, что происходит в процессе и как обрабатываются эти события.
Давайте сначала рассмотрим процесс установления соединения между клиентом и сервером.
- Запустите наш сервер Redis (127.0.0.1-8379). После успешного запуска отслеживается событие AE_READABLE сокета сервера (127.0.0.1-8379), которое соответствует подключению процессора ответов. (
server.c/initServer()
)。 - Подключитесь к серверу с помощью redis -cli. Это означает, что серверный сокет (127.0.0.1-8379) сгенерирует событие AR_READABLE, которое запускает выполнение процессора ответа на соединение.(
networking.c/acceptTcpHandler()
)。 - Ответ на запрос на подключение клиента, создайте клиентский сокет, сохраните информацию о состоянии клиента и обработайте событие с возможностью чтения и запрос команды клиентского сокета(
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.
Теперь давайте взглянем на выполнение заказа:
- Клиент отправляет запрос команды на сервер. Клиентский сокет генерирует событие AE_READABLE, запускает readQueryFromClient для выполнения и считывает содержимое команды клиента.
- В соответствии с содержанием команды, отправленной клиентом, соответствующие значения атрибутов значений, такие как argc и argv клиента, форматируются.
- Найдите соответствующую функцию в соответствии с именем команды.
server.c/команда процесса()
вкоманда поиска
Вызов функции; - Функция, связанная с именем команды, выполняется для получения возвращаемого результата, и генерируется клиентский сокет.
server.c/processCommad()
ввызов
Вызовы функций. - Верните ответ на команду и удалите связь между клиентским сокетом и событием AE_WRITABLE.
network.c/writeToClient()
Функция.
На рисунке 7 показана информация о стеке процесса выполнения команды. На рисунке 8 показана информация о стеке процесса ответа на команду.
резюме
- Сервер Redis является драйвером событий, и события, обрабатываемые сервером, делятся на События времени и События документов Двух типов.
- События файла-это абстракции операций сокета. ** Каждый раз, когда сокет становится приемлемым, доступным для записи или чтения, происходит соответствующее событие файла.
- События файла классифицируются на события AE_READABLE (события чтения) и события AE_WRITABLE (события записи).