данные, хранящиеся в pylibmc, не могут быть распакованы в php memcached

У нас есть приложение, в котором мы используем python для хранения большого количества данных в memcached. Мы используем pylibmc в python, а на стороне php мы используем библиотеку php-memcached. В качестве резюме

  • pylibmc v.1.2.3
  • php-memcached v.2.0.1
  • libmemcached v1.0.8.

Все остальное в порядке, кроме случаев, когда в игру вступает компрессия. Вот как данные сжимаются в python

import pylibmc

mem = pylibmc.Client(['10.90.15.104:11211'], binary=True)
mem.set('foo','this is a rather long string. this is a rather '+
'long string. this is a rather long string. this is a rather' + 
'long string. this is a rather long string', 0, 10)

проверяя в телнете видим какое-то искаженное значение, значит оно было сжато. Теперь читаем его в php.

$memd = new Memcached();
$memd->addServer('10.90.15.104', 11211);
echo $memd->get('foo');

Когда выше запускается, мы получаем такое же искаженное значение, что означает, что оно не распаковывается. pylibmc использует zlib, поэтому я также изменил тип сжатия php на zlib. Какие еще настройки нужно сделать? Пожалуйста помоги.

Для дальнейшего ознакомления здесь приведены выходные данные memcached после установки строки в python pylibmc.

get foo
VALUE foo 8 40
x+��,V�D��Ē��"����t�⒢̼t=���g\5#
END

А вот вывод memcached для строки, сохраненной с помощью memcached-клиента PHP:

get foo
VALUE foo 48 44
�x�+��,V�D��Ē��"����t�⒢̼t=���g\5#
END

Как видите, в этом есть что-то подозрительное. Сжатый размер в pylibmc составляет 40 байт, а те же данные, сжатые с использованием php-memcached, составляют 44 байта. Также обратите внимание на флаги 8 при сохранении с использованием pylibmc и 48 при сохранении с использованием php-memcached!


person Shades88    schedule 17.12.2012    source источник


Ответы (2)


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

как определено pylibmc

#define PYLIBMC_FLAG_ZLIB (1 << 3) (так что это флаг == 8)

и с помощью php-memcached

#define MEMC_VAL_COMPRESSED (1<<4)

#define MEMC_VAL_COMPRESSION_ZLIB (1<<5)

#define MEMC_VAL_COMPRESSION_FASTLZ (1<<6)

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

Редактировать: Итак, вот небольшой патч, который синхронизирует поддержку сжатия для pylibmc и php-memcached. См. мой форк pylibmc на github.

Большая жирная война — работает только со строками, поэтому, если вы хотите хранить объекты, вы ДОЛЖНЫ выполнить десериализацию самостоятельно (JSON).

person Raber    schedule 17.12.2012
comment
вау, спасибо, что раскопал это. но будет ли модификация этих флагов работать? - person Shades88; 18.12.2012
comment
я бы сказал, что это также зависит от хранимого типа, для простых вещей, таких как ints, он должен работать (при условии, что вы заставите библиотеки согласовывать флаги типа и если вы измените метод сжатия php с FASTLZ на ZLIB), для объектов это будет разные, поскольку я считаю, что php хранит их как JSON, а python - как соленья - person Raber; 18.12.2012
comment
ну, тогда (для строк) просто объединение метода сжатия и флага должно помочь :) - person Raber; 18.12.2012
comment
и ты будешь моим спасителем!! :) - person Shades88; 18.12.2012
comment
Я попробовал ваше решение. Но теперь, когда я получаю доступ к этому элементу через php-memcached, я получаю Warning: Memcached::get(): unknown payload type in uaTestMemcached.php on line 5 bool(false) - person Shades88; 19.12.2012
comment
хорошо, по какой-то причине я думал, что флаги шестнадцатеричные, хотя на самом деле они двоичные, поэтому php, похоже, устанавливает как MEMC_VAL_COMPRESSED, так и MEMC_VAL_COMPRESSION_ZLIB (как видно из OP), попробовал это и получил Memcached::get(): could not decompress value, так что эти 4 байта имеют значение - person Raber; 19.12.2012
comment
конечно, теперь я знаю, что это за 4 байта - php хранит там длину строки перед сжатием (не знаю, почему), поэтому pylibmc просто нужно имитировать это - person Raber; 21.12.2012
comment
Привет. Ваш ответ не помог мне напрямую, но поставил меня на правильный путь. Большое спасибо за это. Эта библиотека была разветвлена, и автор, похоже, решил проблему. Вот ссылка, если вам интересно. github.com/gluedig/pylibmc - person Shades88; 28.12.2012
comment
Не могли бы вы предоставить строки компиляции/конфигурации для всех компонентов? Я использую их на Ubuntu 14 x64 и никаких проблем такого рода. - person Alexey Vesnin; 31.07.2015

Рабер,

Как вы сказали, я внес изменения

  1. Изменение метода сжатия php с FASTLZ на ZLIB
  2. Изменение флага pyLibmc на 1 ‹‹ 5 в файле _pylibmcmodule.h и переустановка pylibmc

    #define PYLIBMC_FLAG_ZLIB (1 << 5)
    

Это правильные изменения? Что-то еще нужно сделать? Потому что это не работает, получая следующую ошибку

Warning: Memcached::get(): unknown payload type in uaTestMemcached.php on line 5

bool(false)
person amolrajoba    schedule 19.12.2012
comment
извините, я ничего не знаю о php и его поддержке memcache, что такое uaTestMemcached.php?, а также как теперь выглядят флаги, когда вы сохраняете что-то, сжатое через python или php? - person Raber; 19.12.2012
comment
uaTestMemcached.php — это тестовый php-скрипт, используемый здесь. Вот вывод memcached после установки строки в python pylibmc (после предложенных вами изменений) get foo VALUE foo 8 42 x+��,V�D��Ē��"����t�⒢̼t=�*�m0<05 END - person amolrajoba; 19.12.2012
comment
кажется, что ваше изменение в pylibmc не вступило в силу, я не могу воспроизвести, потому что php-memcached ничего для меня не сжимает (не знаю почему) - person Raber; 19.12.2012
comment
Вам нужно установить memcached.compression_threshold на «10» байт в php.ini, по умолчанию 2000 байт memcached.compression_threshold=10 - person amolrajoba; 20.12.2012
comment
@amolrajoba: Я знаю эту боль. в документации указано 100 байт, а по умолчанию 2000!! :О - person Shades88; 20.12.2012