Введение в HandlerSocket: описание протокола и расширения php-handlersocket

// Декабрь 20th, 2010 // Highload, Memcached, MySQL, NoSQL, PHP, Ruby, Ubuntu

Сейчас на волне популярности различных NoSQL решений создана интересная разработка — плагин для MySQL, реализущий NoSQL доступ к нему, представленный 20 октября 2010г Yoshinori Matsunobu.  В этой заметке я рассмотрю сам протокол, а также его реализацию в php-расширении php-handlersocket.

Что такое HandlerSocket

HandlerSocket — это протокол, реализованный в одноимённом плагине для РСУБД MySQL, позволяющий использовать NoSQL методику для доступа к данным, хранящимся в InnoDB таблицах. Подробнее вы можете прочитать в этой заметке.  Основаная причина, по которой используют NoSQL решения — это очень быстрый поиск по первичному ключу.

HandlerSocket работает как демон внутри процесса mysql, принимая TCP соединения и выполняя запросы клиентов. Он не поддерживает SQL запросы, вместо этого он предоставляет простой язык запросов для CRUD операций с таблицами. Именно поэтому, он гораздо быстрее mysqld/libmysql в некоторых случаях:

  • HandlerSocket оперирует данными без парсинга SQL запроса, что приводит к уменьшению загрузки процессора.
  • Он поддерживает пакетное выполнение запросов. Можно отправить несколько запросов сразу и получить результат за один раз, что опять же снижает нагрузку на процессор и на сеть.
  • Протокол HandlerSocket более компактный чем у mysql/libmysql, что приводит к сокращению нагрузки на сеть.

Текущая версия работает только под GNU/Linux, версия под Windows пока не планируется.
Чтобы не повторяться, я попытаюсь сравнить HandlerSocket с другими решениями.

HandlerSocket VS Memcached

+ Более высокая скорость, как показывают тесты.

+ Постоянное хранение данных.

HandlerSocket работает быстрее, так зачем теперь нужен Memcached? Ах  да, мы же может создать кластер сервером memcached. Но никто нам не мешает наладить репликацию и получить тоже самое 😉

HandlerSocket VS MongoDB, CouchDB, Redis …

+ Мы используем одну базу для SQL-доступа, и для NoSQL-доступа. Не нужно никакое другое ПО для обслуживание данных.

+ Всё что доступно для MySQL (репликация, партиционирование, и огромное количество наработок) по факту доступно и для HandlerSocket, т.к. БД одна и та же.

Недостатки HandlerSocket

— Свой язык запросов, не совместимый с другими  NoSQL решениями. Но, т.к. они и между собой не совместимы, то я не считаю это серьезным недостатком.  Зато есть клиенты под большинство языков. (PHP, Perl, Ruby).

— Индексы хранятся в памяти. Подключаем SSD, и это перестает быть недостатком.

— Для использования с MySQL необходимо скачать исходники и бинарники, сам плагин, скомпилить его и подключить. Но можно просто скачать Percona Server и установить его по моему мануалу. HandlerSocket уже есть в нём (для всех кроме lucid).

-/+ Даже не знаю, к чему это отнести. У HandlerSocket один порт — для запросов на чтение, а второй для запросов на запись.

Протокол HandlerSocket

Основные сведения

— Протокол HandlerSocket строковый. Каждая строка заканчивается символом  LF(0x0a).
— Каждая строка состоит из конкатенации токенов, разделённых символом HT(0x09).
— Токеном может быть либо символ NULL либо закодированная строка. Важно отличать NULL от пустой строки, т.к. БД тоже отличают их.
— NULL записывается одним символом  NUL(0x00).
— Закодированная строка это строка, которая кодируется по следующим правилам:
— Символы находящиеся в диапазоне [0x10 — 0xff] не кодируются.
— Символы в диапазоне [0x00 — 0x0f] обозначаются префиксом 0x01 и сдвигаются на 0x40. Например, 0x03 кодируется как 0x01 0x43.
— Не забывайте, что строки  могут быть пустыми. Последовательность 0x09 0x09 значит, что между двумя символами содержится пустая строка. Последовательность  0x09 0x0a значит, что в конце последовательности есть пустая строка (в тексте обозначена как пробел).

Запрос и ответ

— Протокол HandlerSocket — это простой протокол типа «запрос-ответ». После установления соединения, клиент посылает запрос, а сервер возвращает ему ответ.
— И запрос и ответ представляют собой одну строку.
— Запросы могут быть конвейерными; Это значит, что вы можете посылать много запросов сразу (много строк)  за один раз, и получать ответ сразу на все запросы. По сути это аналог Multi-GET в Memcache протоколе.

Запрос на открытия индекса OPEN_INDEX

Запрос ‘open_index’ имеет следующий синтаксис.

P <indexid> <dbname> <tablename> <indexname> <columns>

— <indexid> это уникальный номер индекса.
— <dbname>, <tablename>, и <indexname> это строки. Для открытия индекса на первичный ключ, используйте PRIMARY в качестве <indexname>.
— <columns> список колонок, резделённых запятыми.

Когда вызывается команда открытия индекса, плагин HandlerSocket открывает указанный индекс и хранит его до закрытия соединения с клиентом. Каждый открытый индекс имеет свой уникальный <indexid>. Если индекс уже открыт, старый индекс закрывается. Вы можете открывать разные индексы с одинаковыми значениями <dbname> <tablename> <indexname> много раз, возможно с отличающимся набором колонок <clumns>. Для увеличения производительности старайтесь использовать маленькие значения <indexid>.

Запрос на получение данных FIND

Запрос «find» имеет следующий синтаксис.

<indexid> <op> <vlen> <v1> … <vn> <limit> <offset>

— <indexid> это номер индекса, по которому необходимо производить поиск. Он должен быть таким же, как и <indexid> в команде open_index.
— <op> определяет операцию сравнения, которая будет производиться при поиске. Текущая версия поддерживает следующие операции: specifies  ‘=’, ‘>’, ‘>=’, ‘<‘, и ‘<=’.
— <vlen> определяет длину строки параметров <v1> … <vn>. Их количество должно быть меньше или равно количеству колонок в индексе, определённых в предшествующей команде open_index.
— <v1> … <vn>определяет значения колонок, которые нужно искать.
— <limit> и <offset> это числа.  Аналогичны LIMIT и OFFSET параметрам в SQL-запросе. Это необязательные параметры. Когда они опущены, используются значения 1 и 0 для них.

Обновление/удаление данных FIND_MODIFY

Запрос ‘find_modify’ имеет следующий синтаксис.

<indexid> <op> <vlen> <v1> … <vn> <limit> <offset> <mop> <m1> … <mk>

— <mop> это КОП (код операции) ‘U’ (при обновлении) или ‘D’ (при удалении). Кто изучал Ассемблер, сразу его вспомнит :-)
— <m1> … <mk> определяют значения для колонок, которые надо установить. Количество <m1> …
<mk> должно быть меньше или равно количеству колонок <columns> в открытом индексе  ‘open_index’. Если <mop> равен ‘D’, эти параметры игнорируются.

Вставка данных INSERT

Запрос ‘insert’ имеет следующий синтаксис.

<indexid> ‘+’ <vlen> <v1> … <vn>

— <vlen> определяет длину строки параметров <v1> … <vn>. Их количество должно быть меньше или равно количеству колонок в индексе, определённых в предшествующей команде open_index.
— <v1> … <vn>определяет значения колонок, которые нужно записать. Для тех колонок, которых нет в <columns> будут выставлены значения по-умолчанию.

Формат ответа от HandlerSocket сервера

Сервер HandlerSocket возвращает ответ следующего синтаксиса для каждого запроса.

<errorcode> <numcolumns> <r1> … <rn>

— <errorcode> это статус ответа. 0 — значит запрос выполнен успешно
другое значение — код ошибки.
— <numcolumns> это количество колонок в результирующем наборе.
— <r1> … <rn> это результирующий набор. Длина <r1> … <rn> всегда кратна <numcolumns>. Она либо равна <r1> … <rn> либо пуста (empty).

Если <errorcode> не равен нулю, <numcolumns> всегда равно 1 а в <r1> содержится текст сообщения об ошибке, но иногда <r1> может не возвращаться.

Ответ на запрос OPEN_INDEX

Если индекс открыт успешно, HandlerSocket возвращает следующую строку.

0 1

Ответ на запрос FIND

Если запрос ‘find’ выполнен успешно, HandlerSocket возвратит строку следующего формата.

0 <numcolumns> <r1> … <rn>

— <numcolumns> всегда равно количеству колонок <columns> соответствующего запроса ‘open_index’.
— <r1> … <rn> это результирующий набор. Если N строк найдено, длина <r1>… <rn> будет равна ( <numcolumns> * N ).

Ответ на запрос FIND_MODIFY

Если запрос ‘find_modify’ выполнен успешно, HandlerSocket возвратит строку такого вида:

0 1 <numfound>

<numfound>- это количество строк, подошедших под условие запроса.

Ответ на запрос INSERT

Если запрос ‘insert’ выполнен успешно, HanderSocket возвратит строку такого вида:

0 1

Расширение PHP-HandlerSocket

Само расширение можно найти в GitHub’е: http://code.google.com/p/php-handlersocket/

Как вы уже знаете, HandlerSocket демон использует два порта. Один (9998) для чтения и другой (9999) для записи. Поэтому при инстанцировании объекта класса, необходимо использовать тот или иной порт, в зависимости от типа запроса.

Структура класса:

HandlerSocket {
    /* Constants */
    const HandlerSocket::PRIMARY;

    /* Methods */
    __construct  ( string $host, int $port, [ array $options ])
    public bool openIndex ( int $id, string $db, string $table, string $index, string $fields )
    public mixed executeSingle ( int $id, string $op, array $fields [, int $limit, int $skip, strint $modop, array $values ] )
    public mixed executeMulti ( array $requests )
    public int executeUpdate ( int $id, string $op, array $fields, array $values [, int $limit, int $skip ] )
    public int executeDelete ( int $id, string $op, array $fields [, int $limit, int $skip ] )
    public bool executeInsert ( int $id, array $values )
    public string getError ( void )
}

Дальше предлагаю посмотреть на пример из документации, чтобы понять, как именно работает расширение.

openIndex(1, $dbname, $table, HandlerSocket::PRIMARY, 'k,v')))
{
    echo $hs->getError(), PHP_EOL;
    die();
}

$retval = $hs->executeSingle(1, '=', array('k1'), 1, 0);

var_dump($retval);

// Чтение данных Multi-Get (find по тому же индексу)
$retval = $hs->executeMulti(
    array(array(1, '=', array('k1'), 1, 0),
          array(1, '=', array('k2'), 1, 0)));

var_dump($retval);

unset($hs);

// Обновление данных (open_index & find_modify mod = U)
$hs = new HandlerSocket($host, $port_wr);
if (!($hs->openIndex(2, $dbname, $table, '', 'v')))
{
    echo $hs->getError(), PHP_EOL;
    die();
}

if (!($hs->executeUpdate(2, '=', array('k1'), array('V1'), 1, 0)))
{
    echo $hs->getError(), PHP_EOL;
    die();
}

unset($hs);

// Вставка данных (open_index & insert)
$hs = new HandlerSocket($host, $port_wr);
if (!($hs->openIndex(3, $dbname, $table, '', 'k,v')))
{
    echo $hs->getError(), PHP_EOL;
    die();
}

if (!($hs->executeInsert(3, array('k2', 'v2'))))
{
    echo $hs->getError(), PHP_EOL;
}
if (!($hs->executeInsert(3, array('k3', 'v3'))))
{
    echo 'A', $hs->getError(), PHP_EOL;
}
if (!($hs->executeInsert(3, array('k4', 'v4'))))
{
    echo 'B', $hs->getError(), PHP_EOL;
}

unset($hs);

// Удаление данных (open_index & find_modify mod = D)
$hs = new HandlerSocket($host, $port_wr);
if (!($hs->openIndex(4, $dbname, $table, '', '')))
{
    echo $hs->getError(), PHP_EOL;
    die();
}

if (!($hs->executeDelete(4, '=', array('k2'))))
{
    echo $hs->getError(), PHP_EOL;
    die();
}

Драйвера для языков программирования

  • PHP
    http://openpear.org/package/Net_HandlerSocket
    http://github.com/tz-lom/HSPHP
    http://code.google.com/p/php-handlersocket/
  • Java
    http://code.google.com/p/hs4j/
    http://code.google.com/p/handlersocketforjava/
  • Python
    https://code.launchpad.net/~songofacandy/+junk/pyhandlersocket
  • Ruby
    https://github.com/winebarrel/ruby-handlersocket
    https://github.com/miyucy/handlersocket
  • JavaScript(Node.js)
    https://github.com/koichik/node-handlersocket

Вообще мне очень нравится эта разработка. Если у кого-то есть что добавить, буду рад услышать ваше мнение.

Share

Спасибо!


Если вам помогла статья, или вы хотите поддержать мои исследования и блог - вот лучший способ сделать это:


54 Responses to “Введение в HandlerSocket: описание протокола и расширения php-handlersocket”

  1. Mixail:

    В статье вы говорите

    есть клиенты под большинство языков. (PHP, Perl, Ruby)

    А в конце статьи я не нашел ссылку на модуль для perl. На cpan`е модуль так же не был найден.

  2. Aleksey:

    — Индексы хранятся в памяти.
    Не могли бы пояснить более детально о чем речь.
    Спасибо.

    • google.com Андрей Токарчук:

      Да, Алексей. Вот смотрите, MySQL использует оперативную память для кэширования индексов. При работе с типом таблиц MyISAM, MySQL использует кэш индексов. Это означает, что при чтении индекса таблицы с диска, он оставляет копию этого индекса в оперативной памяти. При последующих обращениях к этим элементам индекса, нет необходимости обращаться к диску, а значит, мы повышаем производительность сервера. Наличие кэша в оперативной памяти также может влиять на решение оптимизатора по работе с таблицей: ведь обращение к памяти происходит гораздо быстрее, чем обращение к диску. HandlerSocket открывает индексы, которые держит в оперативной памяти, и осуществляет поиск по ним.

      • Aleksey:

        Интересно. А что с innodb? А именно, остаются ли валидны оптимизации innodb plugin при работе , например, с secondary indeexes? Работает ли insert buffering?

        • google.com Андрей Токарчук:

          Да, работает, т.к. HandlerSocket работает над уровнем движка хранения (InnoDB/MyIsam) вместо SQL-уровня.

  3. puchuu:

    пост интересный спасибо.
    но я одного не понимаю.
    почему вы загоняетесь с этим пхп?
    пхп — для быстрой как понос реализации любых требований заказчика
    а если заказчику важен «быстрый поиск по первичному ключу» то никто о пхп даже и думать не станет
    а вот для джавы сейчас скачаем поглядим.
    однако не помешало бы еще под с++…

    • google.com Андрей Токарчук:

      Дело в том, что я большую часть времени работаю с PHP, вот и разбирался с актуальным для себя клиентом для HS.

  4. cheburator:

    + Более высокая скорость, как показывают тесты.
    + Постоянное хранение данных.

    В той статье говорится о таблицах MEMORY.
    Так что ни о каком постоянном хранении речи не идет.
    Падает сервер, пропадают данные.

    • google.com Андрей Токарчук:

      В какой статье?
      Не могу с вами согласиться. HandlerSocket работает с любыми движками хранения (InnoDB/MyIsam…). Автор лично тестировал его на InnoDB.

      In our benchmarks, we could get 750,000+ qps on a commodity MySQL/InnoDB 5.1 server from remote web clients.

      Пруф-линк

      • cheburator:

        На которую вы же даете ссылку.
        http://l-o-n-g.livejournal.com/153756.html

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

      • cheburator:

        Ну да, я ошибся, не MEMORY.
        Цитата:
        Мы используем HandlerSocket только на серверах, на которых практически все данные помещаются в памяти.

        На диске таких скоростей, что обгонят memcache, не достигнуть.

        • google.com Андрей Токарчук:

          Так и Memcached с диском тоже не работает :-)
          Вы очевидно не поняли, индексы хранятся в памяти. Движок может хранить данные где угодно, хоть в Memory, хоть в MyISAM/InnoDB, но индекс будет в памяти. При этом операции чтения/записи будут быстрыми, потому что они работают с памятью. Если произойдет вытеснение на диск (система будет своппиться), то тут и MongoDB со товарищами тоже будут тормозить, и выход здесь (во всех случаях) один — SSD диск.

          • cheburator:

            Я про «+ Постоянное хранение данных.».
            Тут либо скорость, либо постоянное хранение.
            Либо синхронизовать, либо, если можно было бы, запихать базу насильно в буферный кэш.

          • google.com Андрей Токарчук:

            Скорость дает хранение индексов в памяти, а постоянное хранение — persistance. Если все данные не влезают в память — юзаем либо репликацию с кучей слейвов/партиционирование либо SSD. См. этот пост.

          • cheburator:

            Скорость дает хранение индексов в памяти, а постоянное хранение – persistance. Если все данные не влезают в память – юзаем либо репликацию с кучей слейвов/партиционирование либо SSD.

            Тут все ясно, индексы всегда в памяти будут. Просто вы пишите: бестрее memcahce + постоянное хранение. Это не так. При постоянном храниении данные на диске, следовательно медленнее memcache.

          • cheburator:

            Я имею ввиду скорость будет, когда и данные будут в памяти. Но тогда разговор о персистенс уже не идет.

  5. Den:

    Эта технология по сути своей — ограничена, самим MySQL
    То что она реально выигрывает по скорости у реального мускула — это бесспорно.НО врядли ее можно сравнить с реддисом или мемкешд которые висят на постой в оперативке. SSD для мускула — это не решение — не для этого предназначены SSD-шники :) Ну конечно можете в виртуальный диск в оперативку записать мускул (базу данных) — но это тоже не решение (зачем извращаться?).
    В целом это все равно что поставить двиг от феррари в какую то Волгу. Да будет конечно быстро ездить, но врядли можно сравнивать ее с феррари. И не факт что будет работать надежно при больших объемах данных.

    • google.com Андрей Токарчук:

      НО врядли ее можно сравнить с реддисом или мемкешд которые висят на постой в оперативке.

      А почему нельзя, ведь HS-индексы также висят в оперативке? Какие критерии сравнения вы можете предложить, и по каким критериям нельзя их сравнивать?

      SSD для мускула – это не решение – не для этого предназначены SSD-шники

      Почему нет?

      И не факт что будет работать надежно при больших объемах данных.

      Вот это надо проверить. Если сможете протестить — выложите пожалуйста результаты.

  6. Den:

    >> НО врядли ее можно сравнить с реддисом или мемкешд >>которые висят на постой в оперативке.

    >А почему нельзя, ведь HS-индексы также висят в оперативке? Какие критерии сравнения вы можете предложить, и по каким критериям нельзя их сравнивать?

    Ну я так понял в этом случае только индексы висят, а данные хранятся на диске и по индексу (айдишке) прийдется обращаться к диску, это будет дольше чем в реддисе, где данные уже хранятся в памяти.

    SSD для мускула не прокатит — т к имеет маленький ресурс записи на одну ячейку, и он будет сыпаться очень скоро. ССД-шки больше для статики нужны которая редко меняется но часто «читается».

    Да это можно попытаться проверить (на больших объемах) но вопрос опять же — зачем? чем проверенные (вышеописанные) и концептуально более новые технологии не устраивают ?

    • google.com Андрей Токарчук:

      > SSD для мускула не прокатит – т к имеет маленький ресурс записи на одну ячейку, и он будет сыпаться очень скоро. ССД-шки больше для статики нужны которая редко меняется но часто «читается».

      Старые да. Но сейчас вышли новые модели, разработанные специально для серверов — SLC, например Intel X25, у которых срок службы на порядок (10x) больше.

  7. Art:

    Дело в том, что в статье рассматривается движок InnoDB. Там есть буфер в памяти, задается параметром innodb_buffe_pool_size. В буфере хранятся как индексы, так и данные. При записи новых данных они сбрасываются на HDD. Так вот, технология дает прирост в производительности, если все данные, запрашиваемые через этот плагин находятся в буфере. Тут и персистентность и данные в памяти. И ни с какими SSD колхозить не надо.
    Единственный недостаток (на мой взгляд) в том, что сервера memcached можно объединить в кластер, при этом данные «размазываются» по кластеру и суммарный объем данных, хранящихся в ОЗУ существенно выше, чем здесь. Тут же можно только реплицировать, а это значит дублировать данные.

    • google.com Андрей Токарчук:

      Вот! Спасибо за развернутый ответ, именно об этом я и пытался сказать юзеру cheburator.

  8. Anton Kazennikov:

    А вы пробовали гонять на индексах, отличных от PRIMARY?
    У меня почему-то не работает. Я делаю примерно следующее:
    CREATE TABLE test (id INT PRIMARY, value INT UNIQUE);
    INSERT INTO test VALUES (10, 15);

    По идее, mysql создает индекс для value. Но даже если создать такой индекс руками, то запросы ключей к нему не проходят. Я не могу понять, это так и должно быть, или я что-то не так делаю.

    • google.com Андрей Токарчук:

      Нет, так не пробовал. Кстати, очень хороший вопрос. После праздников проверю этот случай. А почему вы считаете, что MySQL должен создать индекс для value автоматически?

  9. Добрый день. Помогите!
    Пытаюсь протестировать handlersocket на c++, делаю два последовательных запроса (request_buf_exec_generic), второй запрос не проходит и возвращается ошибка:
    request_buf_exec_generic: protocol out of sync.
    Вы с таким не встречались? Может кто знает, что не так. Может какие настройки установить надо?

  10. Alexandre:

    спасибо автору за статью

    >Пытаюсь протестировать handlersocket на c++,

    в папке client надо сделать make hstest
    потом запускаем один из тестов *.sh

  11. Alexandre:

    вопрос: доступ по PRIMARY получается без проблем
    а возможен доступ по INDEX ?
    [code]
    $hs->openIndex(2, $dbname, $table, ‘name’, ‘id,name’);
    // name is INDEX for field name
    [/code]

  12. Petr:

    Здравствуйте, Андрей. Планируется ли версия HendlerSocket под FreeBSD? По словам нашего админа под FreeBSD плагин не портировали, а попробовать было бы интересно.

  13. Petr:

    к сожалению нет ..
    а жаль :(

    Can’t open shared library ‘handlersocket.so’
    (errno: 0 API version for DAEMON plugin is too different)
    Couldn’t load plugin named ‘handlersocket’
    with soname ‘handlersocket.so’.

  14. IAD:

    Как думаете, имеет ли смысл использовать HandlerSocket к MySQL, если в проекте есть возможность использовать MongoDB в полный рост?

    • google.com Андрей Токарчук:

      Думаю, что нет. Однако надо не забывать, что у MongoDB есть куча своих граблей. Например невозможность сделать count() для коллекций > 20 000 записей.

      • IAD:

        Возможно это ограничение когда-то раньше было:
        > db.pages.find().count()
        36020

        • google.com Андрей Токарчук:

          У нас на коллекции 700 000 записей, срывается в MongoCursorTimeoutException.

          • ]Mantyr[:

            Интересно, а можно ли получить count() через HS, судя по описанию стандартной библиотеки — нет, в протокол по этому вопросу пока не смотрел, надо будет на досуге:)

          • google.com Андрей Токарчук:

            Нет, только хардкор, только циклом :-)

            COUNT() would be done by writing a loop to «read next» until you run out of rows, counting as you go.

            Есть заявка на эту функцию, присоединяйтесь!

  15. Саня М.:

    Спасибо, Андрюха! Сейчас изучаю эту задачу. Если что, к тебе обращусь напрямую, не понятны некоторые моменты.

  16. ]Mantyr[:

    Собственно в документации теперь так достаются данные:
    The ‘find’ request has the following syntax.

    … [LIM] [IN] [FILTER …]
    https://github.com/DeNADev/HandlerSocket-Plugin-for-MySQL/blob/master/docs-en/protocol.en.txt

    Интересно как воспользоваться IN, я пробовал и в консоли и через php-handlersocket — не заработало.

    0 = 1 130 10,0
    0 3 131 130 группа1 132 130 группа2 133 130 группа3

    0 = 1 1 10 0 1 1 130
    2 1 readonly
    Пробывал различные комбинации, @ в том числе, но это не дало результатов.

  17. ]Mantyr[:

    Смотрим в git hist и видим:
    * | f5f7443 2011-04-06 | fixed that filters did not work with ‘IN’ [Akira Higuchi]
    * | c1043ba 2011-04-05 | temp commit: implements ‘IN’ [Akira Higuchi]
    * | b4d3ab9 2011-04-05 | temp commit: implements ‘IN’ [Akira Higuchi]

    https://github.com/DeNADev/HandlerSocket-Plugin-for-MySQL/commit/f5f7443
    Тест 22… попробуем запустить это через тест на перле…

  18. ]Mantyr[:

    А таки работает:)
    $hs->openIndex(1, $dbname, $table, », ‘k,v,v2’, ‘v2’);

    $retval = $hs->executeSingle(1, ‘=’, array(»), 10000, 0, null, null, array(array(‘F’, ‘=’, 0, ‘1’)), 0, array(‘k10’, ‘k20x’, ‘k30’, ‘k40’, ‘k50’));

  19. Alex:

    Добрый день, интересует возможность реализации счетчика скачиваний через HS. Если считывать данные и делать +1 на PHP, будут потери при высоких нагрузках. В Redis существует команда INCR, есть ли варианты под HS?

    • google.com Андрей Токарчук:

      Думаю, что да. Посмотрите насчёт update. Хотя я в данный момент склоняюсь к той же MongoDB для реализации атомарных операций (при большом потоке запросов на запись).

Комментировать