• Memcached, PHP, Ketama. Если нет, но очень хочется.

      Хочется.
      Кетаму в PHP, да еще чтобы хоть из чего доступ был.
      Это я про не PHP. В смысле про доступ. Ну и из PHP тоже.

      Ну ладно, приступим.
      Что имеем.
      Инет, Google …
      … все :(
      Аааа, чуть не забыл. Самое главное. Потолок, чтобы было куда тупо уставиться.

      Итак гуглим.
      В PHP кетама нет. А где есть то.
      Гы, на last.fm.
      www.lastfm.ru/user/RJ/journal/2007/04/10/rz_libketama_-_a_consistent_hashing_algo_for_memcache_clients
      Вот только после 10 апреля 2007 версию 0.1.1 никто не обновлял, да и набор функционала какой-то куцый. На danga. com вон уже gets’ы, cas’ы и т.п. дребедени полно. Мож оно и можно, да вот только разбираться влом.

      Гуглим дальше …
      tangent.org

      Что имеем.
      Memcached Functions for MySQL
      libmemcached 0.23

      WOW!!!!
      Clients using the library:
      Ruby: github.com/fauna/memcached/tree/master
      Perl: code.google.com/p/perl-libmemcached
      Python: code.google.com/p/python-libmemcached
      PHP: (In Japanese) labs.gree.jp/Top/OpenSource/libmemcached.html

      Идем туда где PHP.
      КАРАУЛ!!! Шалашики.
      Блин и версия 0.1.0. Зато свежая, от 18.09.2008. Короче глюки в ней еще не исправлены, потому что никто их поискать не успел.
      … все.
      Больше нету ничего.

      Ну что, будем пробовать.
      Наверное с шалашиков лучше не начинать.
      Хоть у меня по буржуйски весь словарный запас это: hi, yes, no, problem, thank и все.
      … ну не все конечно, есть еще fuck, но он мне не поможет.
      По японски он всяко короче.

      Ставлю libmemcached и Memcached Functions for MySQL на сервер БД. На вебсервер libmemcached.
      Поднимаю четырех демонов memcached. Одного на вебсервере, трех на сервере БД. Почему? А фиг его знает, так получилось.
      Инсталлирую функции.

      Хм, список впечатляет
      memc_add
      memc_add_by_key
      memc_servers_set
      memc_server_count
      memc_set
      memc_set_by_key
      memc_cas
      memc_cas_by_key
      memc_get
      memc_get_by_key
      memc_delete
      memc_delete_by_key
      memc_append
      memc_append_by_key
      memc_prepend
      memc_prepend_by_key
      memc_increment
      memc_decrement
      memc_replace
      memc_replace_by_key
      memc_servers_behavior_set
      memc_udf_version
      memc_list_behaviors
      memc_stats
      memc_stat_get_keys
      memc_stat_get_value

      Не понял. Если есть cas? Где gets? На кой мне сдался cas без gets’а!!!
      Ладно, мы им это припомним. Наверное.

      Определяем сервера
      SELECT memc_servers_set(‘192.168.0.10:11211, 192.168.0.11:11211, 192.168.0.11:11212, 192.168.0.11:11213);

      Пихаем в кэш десяток ключей
      SELECT memc_set(‘key1’, ‘val1’);

      SELECT memc_set(‘key10’, ‘val10’);


      Берем их из кэша
      SELECT memc_get(‘key1’);

      SELECT memc_get(‘key10’);


      Вроде нормально, отдает то, что положили.

      Теперь валим одного демона memcached. Как и следовало ожидать – два ключа накрылись. Снова ложим в кэш 10 этих же ключей.
      Фиг вам. Те же пропавшие два, так и не объявились. Кетамой и не пахнет. Ну ничего, readme почитать мне не западло.

      В Memcached Functions for MySQL ничего умного не нашел. Пойдем на tangent.org.
      Блин, как все запущено.

      Ага вот оно про оно кажется
      docs.tangent.org/libmemcached/memcached_behavior.html
      Согласно translate.ru behavior это поведение.
      По дефолту MEMCACHED_BEHAVIOR_DISTRIBUTION стоит MEMCACHED_DISTRIBUTION_MODULA, а нам надо MEMCACHED_DISTRIBUTION_CONSISTENT, и MEMCACHED_BEHAVIOR_HASH чтоб было MEMCACHED_HASH_KETAMA.

      И делает это memcached_behavior_set(). В MySQL это надо полагать memc_servers_behavior_set.
      Бррр, стоп. А это что такое в доке memcached_behavior.pod

      =item MEMCACHED_BEHAVIOR_DISTRIBUTION
      Using this you can enable different means of distributing values to servers.
      The default method is MEMCACHED_DISTRIBUTION_MODULA. You can enable
      consistent hashing by setting MEMCACHED_DISTRIBUTION_CONSISTENT.
      Consistent hashing delivers better distribution and allows servers to be
      added to the cluster with minimal cache losses. Currently
      MEMCACHED_DISTRIBUTION_CONSISTENT is an alias for the value
      MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA.

      =item MEMCACHED_BEHAVIOR_KETAMA
      Sets the default distribution to MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA
      and the hash to MEMCACHED_HASH_MD5.

      Что-то каша в голове начинается.
      Ага, наверное понял, надо сделать MEMCACHED_BEHAVIOR_KETAMA …
      Как это?
      Пошли дальше читать. Похоже тупо надо все подряд. Еще по буржуйски понимать быыыы.

      Похоже это оно
      For simple on or off options you just need to pass in a value of 1.
      Значит надо MEMCACHED_BEHAVIOR_KETAMA set 1.

      Ну что попробуем.
      SELECT memc_servers_behavior_set (‘MEMCACHED_BEHAVIOR_KETAMA’, 1);

      Мдааа. Кирдык фулльный.
      mysql>SELECT memc_servers_behavior_set('MEMCACHED_BEHAVIOR_KETAMA', 1);
      ERROR 2013 (HY000): Lost connection to MySQL server during query
      mysql>

      Лечится только рестартом MySQL сервера …

      Ну ладно. Напишем разработчикам
      forums.mysql.com/read.php?150,231325,231325#msg-231325

      Быстро … отписался
      forums.mysql.com/read.php?150,231325,231359#msg-231359

      А если так
      forums.mysql.com/read.php?150,231325,231442#msg-231442
      То-то же.

      Это похоже надолго.
      Придется тупо смотреть в потолок. Может там что есть?
      Точно. Есть. Только вот мысли какие-то не умные, а грязные.
      Если откуда то берется не то, что мне нужно. Значит где то это туда положили. Нужно всего-то найти это где то и положить туда то, что мне нужно.

      Ой блин. Лезть в исходники. А они на сях. А я про С только название знаю. В смысле, что язык так называется.
      Ну да ладно. Делать нечего, будем искать знакомые слова.
      В MySQL библиотеке наверное не стоит, она так, прокладка. Лезем в саму libmemcached.

      Ага вот оно. В memcached.c. строка 29
      ptr->distribution= MEMCACHED_DISTRIBUTION_MODULA;
      целых два знакомых слова.

      И конструкция название имеет многообещающее: memcached_st *memcached_create(memcached_st *ptr).
      Теперь попытаемся понять кто такой memcached_st.
      Наверное понятно. Согласно libmemcached.pod, если translate.ru мне все правильно объяснил, это то самое место, где лежит не то что мне надо.
      Сходим еще раз на на tangent.org. Конфы там нет, но есть майлин глист lists.tangent.org/mailman/listinfo/libmemcached. Там не так много чего. Тупо поищем знакомые слова.

      Что то есть.
      lists.tangent.org/pipermail/libmemcached/2008-September/000434.html
      Если правильно понял, надо MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT’у сделать set сколько-нибудь. Там пишут 10, я попробую 3.

      lists.tangent.org/pipermail/libmemcached/2008-August/000429.html
      ну и мы так же сделаем.

      Итак. Попытаемся подправить исходники. В смысле положить то что надо.

      Вместо ptr->distribution= MEMCACHED_DISTRIBUTION_MODULA;
      Напишем ptr->distribution= MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA;
      Надо же. Мои первые в жизни 0,5 строки на C.

      Вместо ptr->retry_timeout= 0;
      Напишем ptr->retry_timeout= 60;

      Ыыыыыыыыы. Вместо чего написать про MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT?
      Опять тупо смотрим в потолок.

      А че смотреть то. Искать про SERVER_FAILURE_LIMIT в исходниках.
      Есть. В memcached_behavior.c. Стр.166, называется ptr->server_failure_limit.
      Добавим по аналогии с остальным
      ptr->server_failure_limit= 3;
      Может прокатит. В принципе если что – сервер раком ляжет. Дык так же его и поставим.

      Вот что получилось

      memcached_st *memcached_create(memcached_st *ptr)
      {
      memcached_result_st *result_ptr;

      if (ptr == NULL)
      {
      ptr= (memcached_st *)malloc(sizeof(memcached_st));

      if (!ptr)
      return NULL; /* MEMCACHED_MEMORY_ALLOCATION_FAILURE */

      memset(ptr, 0, sizeof(memcached_st));
      ptr->is_allocated= MEMCACHED_ALLOCATED;
      }
      else
      {
      memset(ptr, 0, sizeof(memcached_st));
      }
      result_ptr= memcached_result_create(ptr, &ptr->result);
      WATCHPOINT_ASSERT(result_ptr);
      ptr->poll_timeout= MEMCACHED_DEFAULT_TIMEOUT;
      ptr->connect_timeout= MEMCACHED_DEFAULT_TIMEOUT;
      ptr->retry_timeout= 60;
      ptr->distribution= MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA;
      ptr->server_failure_limit= 3;

      return ptr;
      }

      Все. Перекомпилим либу и вперед. Приступаем к онани… ну вы поняли, к итерациям.

      Определяем сервера
      SELECT memc_servers_set(‘192.168.0.10:11211, 192.168.0.11:11211, 192.168.0.11:11212, 192.168.0.11:11213);

      Пихаем в кэш десяток ключей
      SELECT memc_set(‘key1’, ‘val1’);

      SELECT memc_set(‘key10’, ‘val10’);


      Берем их из кэша
      SELECT memc_get(‘key1’);

      SELECT memc_get(‘key10’);


      Вроде нормально, отдает то, что положили.

      Валим одного демона memcached.
      Не понял. Какого черта. Почему они ВСЕ живые? Это я про данные которые в кэш положил.

      Ладно. Валим второго.
      Ну мы так не договаривались. Они ВСЕ живые.

      Ну а если третьего.
      Блин, все живые.

      Ну нас так просто не возьмешь. Против лома нет приема. Валим последнего четвертого демона memcached.
      То то же. Живых не осталось.
      Начинаем убивать, поднимать, сохранять в, доставать из …
      … короче итерациями заниматься.
      НЕ МОГУ УБИТЬ!!!

      Мда. Работает. Даже больше того.

      Ну нет. Нас так просто не возьмешь.
      Все УБИЛ!!!
      Оставил живой одну ноду. По тихому поднял вторую. Не устраивая никаких обращений к memcached, свалил первую.
      Все, не пережила. Знай наших, кого хочешь раком положим.

      Уфф. О чем это я.
      Вообще то про PHP.

      Ну что, пойдем в шалашики labs.gree.jp/Top/OpenSource/libmemcached.html

      Так, слава богу хоть исходники не в шалаше
      github.com/kajidai/php-libmemcached/tree/master

      Привинчиваем.
      labs.gree.jp/Top/OpenSource/libmemcached/Document.html

      Пробуем

      <?php
      $memcached = new Memcached();
      $memcached->addserver('192.168.0.10', 11211);
      $memcached->addserver('192.168.0.11', 11211);
      $memcached->addserver('192.168.0.11', 11212);
      $memcached->addserver('192.168.0.11', 11213);
      $memcached->set('key1', 'val1');
      $ret = $memcached->get('key1');
      Echo $ret. “<br>”;


      Работает сволочь…
      Вместе с MySQL работает.
      Корректно данные отрабатывают в паре.
      Валим, поднимаем, пишем, читаем – все корректно.

      Да кстати. На вебсервере подпиленную libmemcached привинтил.

      А что по функционалу мы тут имеем?

      Не плохо
      memcached_ctor
      memcached_server_add
      memcached_add
      memcached_add_by_key
      memcached_append
      memcached_append_by_key
      memcached_behavior_get
      memcached_behavior_set
      memcached_cas
      memcached_cas_by_key
      memcached_delete
      memcached_delete_by_key
      memcached_get
      memcached_get_by_key
      memcached_set
      memcached_set_by_key
      memcached_increment
      memcached_decrement
      memcached_prepend
      memcached_prepend_by_key
      memcached_replace
      memcached_replace_by_key
      memcached_server_list
      memcached_mget
      memcached_fetch
      memcached_server_list_append
      memcached_server_push

      gets’а тоже нету.

      А как с глюками …
      А фиг его знает.
      Узнать бы. Ну в самом деле не писать же автору на моем русском английском в Японию. Ответит ведь мне на своем японском английском.
      Так и война ведь начнется.

      Ладно, полезем в исходники. Я ведь на С уже целых 2,5 строки в сумме в своей жизни написал.

      Блин, как то все просто …
      Аааа, въехал. Он же просто по zend’у обертку для трансляции вызовов написал. Блин и накосячить то наверное особо здесь негде.

      Ну что.
      Подведем итоги.

      Во первых. Я написал свои первые 2,5 строки на С.
      Во вторых. У меня теперь кетама в PHP есть.
      В третьих. Хрен этот кэш так просто свалишь.
      В четвертых. Похрену из чего, нормальный доступ к данным в memcached, хоть из С, хоть из Perl, хоть из PHP c MySQL. Один ложит, пофигу откуда и кто другой корректно читает.

      PS. Снимаю шляпу перед Brian Aker brian.krow.net