Ответ 1
Я подозреваю, что Thrift - это то, что вы хотите. Вам нужно будет написать небольшой код для создания PHP файлов, но это, вероятно, будет более надежным, чем ваш собственный.
и спасибо, что посмотрели на вопрос.
Фон
У меня есть несколько машин, которые непрерывно генерируют несколько (до 300) скриптов в PHP за очень короткий промежуток времени. Эти скрипты выполняются быстро (менее секунды), а затем выходят. Все эти сценарии должны иметь доступ только для доступа к большой структуре trie, которая будет очень дорого загружаться в память каждый раз, когда каждый из запускается скрипт. Сервер работает под управлением Linux.
Мое решение
Создайте C-демона, который сохраняет структуру trie в памяти и получает запросы от клиентов PHP. Он получит запрос от каждого из клиентов PHP, выполнит поиск по структуре памяти и ответит на ответ, сохранив скрипты PHP от выполнения этой работы. Оба запроса и ответы - короткие строки (не более 20 символов).
Моя проблема
Я очень новичок в C-демонах и межпроцессном общении. После долгих исследований я сузил выбор до "Очередей сообщений" и сокетов домена Unix. Очереди сообщений кажутся адекватными, потому что я думаю (возможно, ошибаюсь), что они ставят в очередь все запросы к демону, чтобы они отвечали последовательно. Однако сокеты домена Unix кажутся более простыми в использовании. Однако у меня есть различные вопросы, на которые я не смог найти ответы:
Фактический поиск структуры данных очень быстрый, мне не нужно сложное многопоточное или подобное решение, так как я считаю, что обработка запросов в режиме FIFO будет достаточно. Мне также нужно, чтобы это было просто глупо, поскольку это критически важная услуга, и я довольно новичок в этом типе программы. (Я знаю, но у меня действительно нет никакого способа обойти это, и опыт обучения будет большим)
Мне бы очень понравились фрагменты кода, которые освещают конкретные вопросы, которые у меня есть. Также приветствуются ссылки на руководства и указатели, которые будут способствовать моему пониманию в этом мрачном мире IPC низкого уровня.
Спасибо за вашу помощь!
Зная гораздо больше, чем я, когда я задавал этот вопрос, я просто хотел указать всем, кто заинтересован в том, что Thrift и ZeroMQ делают фантастическую работу по абстрагированию от жесткого программирования на уровне сокета. Thrift даже дает вам леса для сервера бесплатно!
На самом деле, вместо того, чтобы идти на все тяжелые работы по созданию сетевого сервера, подумайте о написании кода сервера приложений с помощью хорошего асинхронного сервера, который уже решил проблему для вас. Конечно, серверы, использующие асинхронный ввод-вывод, отлично подходят для сетевых приложений, которые не требуют интенсивной обработки процессора (или блоков цикла событий).
Примеры для python: Twisted, gevent. Я предпочитаю gevent, и я не включаю торнадо, потому что он сосредоточен на стороне сервера HTTP.
Примеры для Ruby: EventMachine
Конечно, Node.js в основном является выбором по умолчанию для асинхронного сервера в настоящее время.
Если вы хотите углубиться, прочитайте Проблема C10k и Сетевая программа Unix.
Я подозреваю, что Thrift - это то, что вы хотите. Вам нужно будет написать небольшой код для создания PHP файлов, но это, вероятно, будет более надежным, чем ваш собственный.
Вы также можете загрузить структуру данных в общую память с помощью функций общей памяти PHP http://www.php.net/manual/en/book.shmop.php.
О, это не очевидно из документации, но координационная переменная - $key в shmop_open. Каждый процесс, требующий доступа к общей памяти, должен иметь тот же ключ $. Таким образом, один процесс создает разделяемую память с помощью ключа $. Другие процессы затем могут получить доступ к этой общей памяти, если они используют один и тот же ключ $. Я считаю, что вы можете выбрать все, что хотите, для $key.
"Проблема" (может быть, нет?) заключается в том, что в SysV MQ наверняка будет много потребителей/производителей. Хотя вполне возможно, что вы делаете, если у вас не обязательно есть потребность m: n в модели производителя: потребитель к ресурсам, здесь у вас есть модель запроса/ответа.
Вы можете получить некоторые странные зависания с SysV MQ, как есть.
Во-первых, вы уверены, что сокеты INET не достаточно быстры для вас? Быстрый пример PHP с использованием сокетов домена unix находится в http://us.php.net/socket-create-pair (как пример кода, конечно, используйте socket_create() для конечной точки PHP).
Хотя я никогда не пробовал, memcached вместе с соответствующим расширение PHP должно устранить большую часть работы grunt.
Уточнение: я неявно предполагал, что если вы это сделаете, вы поместите отдельные листья три в memcache, используя сплющенные ключи, отбрасывая trie. Разумность и желательность этого подхода, конечно, зависит от многих факторов, в первую очередь от источника данных.
IPC между script можно легко выполнить с помощью Pipes. Это делает очень простую реализацию.
nanomsg закодирован в простой C, поэтому я думаю, что он лучше подходит для ваших нужд, чем Thrift и ZeroMQ, которые закодированы в С++.
У него обертки для многих языков, включая PHP.
Вот рабочий пример с использованием протокола NN_PAIR
: (вы также можете использовать NN_REQREP
)
client.php
<?php
$sock = new Nanomsg(NanoMsg::AF_SP, NanoMsg::NN_PAIR);
$sock->connect('ipc:///tmp/myserver.ipc');
$sock->send('Hello World!', 0);
$sock->setOption(NanoMsg::NN_SOL_SOCKET, NanoMsg::NN_RCVTIMEO, 1000);
$data = $sock->recv(0, 0);
echo "received: " . $data . "\n";
?>
server.c
#include <stdio.h>
#include <string.h>
#include <nanomsg/nn.h>
#include <nanomsg/pair.h>
#define address "ipc:///tmp/myserver.ipc"
int main() {
unsigned char *buf = NULL;
int result;
int sock = nn_socket(AF_SP, NN_PAIR);
if (sock < 0) puts("nn_socket failed");
if (nn_bind(sock, address) < 0) puts("bind failed");
while ((result = nn_recv(sock, &buf, NN_MSG, 0)) > 0) {
int i, size = strlen(buf) + 1; // includes null terminator
printf("RECEIVED \"%s\"\n", buf);
for (i = 0; buf[i] != 0; i++)
buf[i] = toupper(buf[i]);
nn_send(sock, buf, size, 0);
nn_freemsg(buf);
}
nn_shutdown(sock, 0);
return result;
}
Вот рабочий пример, где php script отправляет запрос на C-демон и затем ждет ответа. Он использует сокеты домена Unix в режиме датаграммы, поэтому он быстрый и простой.
client.php
<?php
do {
$file = sys_get_temp_dir() . '/' . uniqid('client', true) . '.sock';
} while (file_exists($file));
$socket = socket_create(AF_UNIX, SOCK_DGRAM, 0);
if (socket_bind($socket, $file) === false) {
echo "bind failed";
}
socket_sendto($socket, "Hello World!", 12, 0, "/tmp/myserver.sock", 0);
if (socket_recvfrom($socket, $buf, 64 * 1024, 0, $source) === false) {
echo "recv_from failed";
}
echo "received: [" . $buf . "] from: [" . $source . "]\n";
socket_close($socket);
unlink($file);
?>
server.c
#include <stdio.h>
#include <sys/un.h>
#include <sys/socket.h>
#define SOCKET_FILE "/tmp/myserver.sock"
#define BUF_SIZE 64 * 1024
int main() {
struct sockaddr_un server_address = {AF_UNIX, SOCKET_FILE};
int sock = socket(AF_UNIX, SOCK_DGRAM, 0);
if (sock <= 0) {
perror("socket creation failed");
return 1;
}
unlink(SOCKET_FILE);
if (bind(sock, (const struct sockaddr *) &server_address, sizeof(server_address)) < 0) {
perror("bind failed");
close(sock);
return 1;
}
while (1) {
struct sockaddr_un client_address;
int i, numBytes, len = sizeof(struct sockaddr_un);
char buf[BUF_SIZE];
numBytes = recvfrom(sock, buf, BUF_SIZE, 0, (struct sockaddr *) &client_address, &len);
if (numBytes == -1) {
puts("recvfrom failed");
return 1;
}
printf("Server received %d bytes from %s\n", numBytes, client_address.sun_path);
for (i = 0; i < numBytes; i++)
buf[i] = toupper((unsigned char) buf[i]);
if (sendto(sock, buf, numBytes, 0, (struct sockaddr *) &client_address, len) != numBytes)
puts("sendto failed");
}
}