Элементы, установленные с помощью spymemcached, не могут быть получены с помощью php memcached

Я использую spymemcached. Я поставил пару пунктов. Затем я запускаю php-скрипт, однако тогда я не могу получить все эти элементы с помощью php memcached. PHP-Memcached может получить эти элементы только частично.

Я не могу изменить алгоритм хэширования или стратегию распространения php. В нашей системе мы используем хэширование по умолчанию (которое, согласно документации php.net, является одновременным для jenkin). И стратегия распространения по модулю для php-memcached. Я читал, что spymemcached использует последовательное хеширование. Есть ли способ использовать хеширование по модулю в spymemcached.

Другими словами, как я могу сделать операции набора spymemcached или любые другие операции хранилища совместимыми с операциями получения php-memcached?

Если spymemcached не может этого сделать, есть ли другой клиент memcached в java, который позволит мне это сделать?

Помощь будет не только оценена по достоинству, она также будет вознаграждена щедростью.

Java-код:

public static void main(String [] args) {
    List<InetSocketAddress> addrs = new ArrayList<>();
    addrs.add(new InetSocketAddress("10.90.12.87", 11211));
    addrs.add(new InetSocketAddress("10.90.12.87", 11311));
    try {
        MemcachedClient memcache = new MemcachedClient(addrs);
        memcache.add("foo", 0, "bar");
        memcache.add("sample", 0, "key");
        memcache.add("try", 0, "another");
        memcache.add("ax-spadg-list", 0, "3045,6645");
    } catch (IOException ex) {
        Logger.getLogger(CategoryDataOperator.class.getName()).log(Level.SEVERE, null, ex);
    }
    System.out.println("Done");
}

PHP-код:

<?php
$mem = new Memcached();
$mem->addServer('10.90.12.87', 11211);
$mem->addServer('10.90.12.87', 11311);
var_dump $mem->get('foo');
var_dump($mem->get('try'));
var_dump($mem->get('sample'));
var_dump($mem->get('ax-spadg-list'));

person Shades88    schedule 25.09.2013    source источник
comment
Вам может быть интересно прочитать здесь: Java Memcached Client.   -  person hakre    schedule 01.10.2013
comment
Я уже использую его. Однако элементы, установленные с помощью spymemcached, доставляют мне проблемы при их извлечении с помощью php memcached. Ответ, который я ищу   -  person Shades88    schedule 01.10.2013
comment
Это я прекрасно понял, но посмотрите, ответивший там пользователь написал, что он автор Spymemcachedn, так что, возможно, если вы пропингуете его, вы получите больше информации. Возможно, он знает об этой проблеме.   -  person hakre    schedule 02.10.2013
comment
да, но я не знаю, как с ним связаться. В его профиле нет контактной информации. Плюс я прокомментировал дважды, но он не ответил на это.   -  person Shades88    schedule 03.10.2013
comment
Извините за несколько выпусков, но я неправильно прочитал ваш вопрос и требование, чтобы php-клиент не мог измениться. Я предлагаю вам 3 решения.   -  person Kakawait    schedule 03.10.2013


Ответы (3)


Проблема связана с хэшем, хэш php-memcached по умолчанию

(Дженкинс по одному) алгоритм хэширования ключа элемента

тогда как список хэшей spymemcached:

  • NATIVE_HASH: просто Native hash (String.hashCode()). не совпадает с php-memcached по умолчанию Memcached::HASH_DEFAULT
  • CRC_HASH => Memcached::HASH_CRC
  • FNV1_64_HASH => Memcached::HASH_FNV1_64
  • FNV1A_64_HASH => Memcached::HASH_FNV1A_64
  • FNV1_32_HASH => Memcached::HASH_FNV1_32
  • FNV1A_32_HASH => Memcached::HASH_FNV1A_32
  • KETAMA_HASH => "Алгоритм хеширования на основе MD5, используемый ketama." Так что, может быть, Memcached::HASH_MD5, но все равно не Memcached::HASH_DEFAULT

Таким образом, между двумя библиотеками нет прямого соответствия, если вы не можете изменить конфигурацию клиента PHP или расширить библиотеку spymemcached.

РЕШЕНИЕ 1: Если вы посмотрите на историю (у вас может быть пример с модификацией хеша клиента php ).

РЕШЕНИЕ 2. В противном случае вы можете создать класс JenkinHash (я копирую код Xmemcached: https://code.google.com/p/xmemcached/source/browse/trunk/src/main/java/net/rubyeye/xmemcached/HashAlgorithm.java?r=801#176 [Но примите во внимание лицензии Xmemcached и сохраните автора/лицензию внутри исходного кода])

import net.spy.memcached.HashAlgorithm;

import java.io.UnsupportedEncodingException;

public class JenkinsHash implements HashAlgorithm {
    @Override
    public long hash(String k) {
        try {
            int hash = 0;
            for (byte bt : k.getBytes("utf-8")) {
                hash += (bt & 0xFF);
                hash += (hash << 10);
                hash ^= (hash >>> 6);
            }
            hash += (hash << 3);
            hash ^= (hash >>> 11);
            hash += (hash << 15);
            return hash;
        } catch (UnsupportedEncodingException e) {
            throw new IllegalStateException("Hash function error", e);
        }
    }
}

тогда:

import net.spy.memcached.*;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Main {

    public static void main(String[] args) throws IOException {
        List<InetSocketAddress> addrs = new ArrayList<InetSocketAddress>();
        addrs.add(new InetSocketAddress("127.0.0.1", 11211));
        addrs.add(new InetSocketAddress("172.28.29.22", 11211));
        try {
            ConnectionFactory connectionFactory = new ConnectionFactoryBuilder()
                .setProtocol(ConnectionFactoryBuilder.Protocol.TEXT)
                .setHashAlg(new JenkinsHash())
                .setLocatorType(ConnectionFactoryBuilder.Locator.ARRAY_MOD).build();
            MemcachedClient memcache = new MemcachedClient(connectionFactory, addrs);
            memcache.add("foo", 0, "bar2");
            memcache.add("sample", 0, "key");
            memcache.add("try", 0, "another");
            memcache.add("ax-spadg-list", 0, "3045,6645");
        } catch (IOException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
        System.out.println("Done");
    }
}

С php-скриптом:

<?php

$memcached = new Memcached();
$memcached->addserver('127.0.0.1', 11211);
$memcached->addserver('172.28.29.22', 11211);
var_dump($memcached->get('foo'));
var_dump($memcached->get('try'));
var_dump($memcached->get('sample'));
var_dump($memcached->get('ax-spadg-list'));

контрольная работа:

$ echo "flush_all" | nc 172.28.29.22 11211 && echo "flush_all" | nc 127.0.0.1 11211
OK
OK
$ php mem.php 
bool(false)
bool(false)
bool(false)
bool(false)

RUN JAVA

$ php mem.php 
string(4) "bar2"
string(7) "another"
string(3) "key"
string(9) "3045,6645"

РЕШЕНИЕ 3. используйте https://code.google.com/p/xmemcached/ с алгоритмом хеширования ONE_AT_A_TIME

import net.rubyeye.xmemcached.HashAlgorithm;
import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.MemcachedClientBuilder;
import net.rubyeye.xmemcached.XMemcachedClientBuilder;
import net.rubyeye.xmemcached.exception.MemcachedException;
import net.rubyeye.xmemcached.impl.ArrayMemcachedSessionLocator;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeoutException;

public class Main {

    public static void main(String[] args) throws IOException, InterruptedException, MemcachedException, TimeoutException {
        List<InetSocketAddress> addrs = new ArrayList<InetSocketAddress>();
        addrs.add(new InetSocketAddress("127.0.0.1", 11211));
        addrs.add(new InetSocketAddress("172.28.29.22", 11211));
        MemcachedClientBuilder builder = new XMemcachedClientBuilder(addrs);
        builder.setSessionLocator(new ArrayMemcachedSessionLocator(HashAlgorithm.ONE_AT_A_TIME));
        MemcachedClient memcachedClient = builder.build();
        memcachedClient.set("foo", 0, "bar2");
        memcachedClient.set("sample", 0, "key");
        memcachedClient.set("try", 0, "another");
        memcachedClient.set("ax-spadg-list", 0, "3045,6645");
        memcachedClient.shutdown();
        System.out.println("Done");
    }
}
person Kakawait    schedule 03.10.2013
comment
Мне потребовалось много времени, чтобы отомстить тебе. Я попробовал решение xmemcached. Однако это все еще не работает. Он пытается найти элемент только на одном сервере. Я устанавливаю элементы из php и пытаюсь получить их в java. Выдает исключение ArrayIndexOutOfBounds! Стратегия дистрибуции нарушена? - person Shades88; 05.12.2013
comment
не могу постить сюда. Код будет выглядеть перепутанным. Мы можем где-нибудь поболтать? Я слишком долго застрял в этом проекте. И кажется, только ты можешь мне помочь. Не могли бы вы прислать мне свой адрес электронной почты или любой другой способ связаться с вами? - person Shades88; 05.12.2013
comment
Построитель MemcachedClientBuilder = новый xmemcachedClientBuilder (AddrUtil.getAddresses (127.0.0.1:11211 127.0.0.1:11311)); builder.setSessionLocator(новый ArrayMemcachedSessionLocator(HashAlgorithm.ONE_AT_A_TIME)); MemcachedClient memcachedClient = builder.build(); System.out.println (Попытка получить 1 миллион элементов); System.out.println(memcachedClient.get(foo)); System.out.println (memcachedClient.get (бар)); System.out.println(memcachedClient.get(инь)); - person Shades88; 05.12.2013
comment
Завтра для чата я не могу сегодня - person Kakawait; 05.12.2013
comment
Может использовать gist или что-то еще :) - person Kakawait; 05.12.2013
comment
давайте продолжим это обсуждение в чате - person Kakawait; 05.12.2013

Алгоритмы хеширования, которые поддерживает spymemcached, приведены здесь: https://github.com/couchbase/spymemcached/blob/master/src/main/java/net/spy/memcached/DefaultHashAlgorithm.java

Вы должны иметь возможность изменить алгоритм хеширования, используя ConnectionFactory для создания MemcachedClient. Сделайте что-то вроде этого:

ConnectionFactoryBuilder builder = new ConnectionFactoryBuilder();
builder.setHashAlgorithm(HashAlgorithm.CRC_HASH);
ConnectionFactory factory = builder.build();
MemcachedClient client = new MemcachedClient(Arrays.asList(new InetSocketAddr("localhost", 11211)), factory);
person mikewied    schedule 25.09.2013
comment
Я показываю cannot find symbol: CRC32. Есть ли другая банка или что-то, что мне нужно добавить для CRC32? - person Shades88; 26.09.2013
comment
Я отредактировал ответ, включив в него один из типов хэшей, включенных в файл выше. Приведенный выше код следует использовать в качестве ссылки. На самом деле я его не компилировал. Обратите внимание, что в файле могут использоваться другие возможные алгоритмы хеширования: NATIVE_HASH, FNV1_64_HASH, KETAMA_HASH и т. д. - person mikewied; 27.09.2013
comment
Спасибо за это. Однако HashAlgorithm - это интерфейс, поэтому в нем не было упомянутых вами полей. Я использовал DefaultHashAlgorithm.CRC_HASH. Однако я перепробовал все алгоритмы. Ничего не получилось :( - person Shades88; 27.09.2013
comment
в php хэширование memcached установлено по умолчанию, то есть jenkin's one by one, как указано на php.net. Я не знаю, что такое хеширование по умолчанию в spymemcached. также php memcached имеет модульную и согласованную стратегию распространения по умолчанию. по модулю по умолчанию. Я выбрал ConnectionFactoryBuilder.Locator.ARRAY_MOD. Но все равно не повезло - person Shades88; 27.09.2013

Re: Kakawait (а также Shades88)

Решение № 2 неверно, поскольку xmemcached неправильно перенес исходный код C хэша Jenkins, в котором используется unsigned. Исправление этого также устранит ArrayIndexOutOfBoundsException, которое видел Shades88.

public class JenkinsHash implements HashAlgorithm {
    @Override
    public long hash(String k) {
        try {
            int hash = 0;
            for (byte bt : k.getBytes("utf-8")) {
                hash += (bt & 0xFF);
                hash += (hash << 10);
                hash ^= (hash >>> 6);
            }
            hash += (hash << 3);
            hash ^= (hash >>> 11);
            hash += (hash << 15);

            // the hash variable in the original C code is a uint32.
            // convert the java signed int to an "unsigned",
            // represented via a long:
            return hash & 0xFFFFFFFFl;
        } catch (UnsupportedEncodingException e) {
            throw new IllegalStateException("Hash function error", e);
        }
    }
}

// Unit test
public class JenkinsHashTest {
    @Test
    public void testHash() throws Exception {
        JenkinsHash j = new JenkinsHash();
        Properties p = new Properties();

        // This file contains k/v mappings,
        // with values generated by the reference C code
        p.load(new FileReader("src/test/resources/jenkinsHashTest.dat"));

        for (Entry<Object, Object> entry : p.entrySet()) {
            long result = j.hash((String)entry.getKey());
            // Print out hash mismatches
            if (result != Long.parseLong((String)entry.getValue())) {
                System.out.println("Key: " + (String)entry.getKey());
                System.out.println("Expected Hash Value: " + Long.parseLong((String)entry.getValue()));
                System.out.println("Actual Hash Value: " + result);
            }
            assertEquals(result, Long.parseLong((String)entry.getValue()));
        }
    }
}

Файл тестовых данных предназначен для сравнения кода Java с кодом C. Создайте код C, затем хешируйте набор случайных слов и сопоставьте их в файле, например:

jenkinsHashTest.dat:

sausage=2834523395
blubber=1103975961
pencil=3318404908
cloud=670342857
moon=2385442906
water=3403519606
computer=2375101981
school=1513618861
network=2981967937
hammer=1218821080

... добавьте столько, сколько хотите

person spudone    schedule 03.01.2014
comment
Да, я понял это некоторое время назад и просто использовал функцию abs для переменной hash. Будет ли приведение типа к long немного быстрее? Я попробую и это. - person Shades88; 08.01.2014
comment
Код, который я добавил, преобразует хэш-переменную обратно в беззнаковую, что вам нужно для эквивалентности коду C. Использование abs() предотвратит исключение ArrayIndexOutOfBoundsException, но даст разные результаты хеширования, что может вызвать проблему совместимости между Java и PHP. Исходный код C, на который я смотрел, находится здесь: en.wikipedia.org/wiki/Jenkins_hash_function - person spudone; 09.01.2014
comment
Последнее замечание: abs() не вызовет проблемы с memcached до тех пор, пока ваш Java-код не наткнется на ключ, который хешируется до отрицательного числа. Вот когда произойдет несовместимость PHP. - person spudone; 09.01.2014
comment
Исправление теперь находится в xmemcached 2.0.0 (github.com/killme2008/xmemcached /релизы/тег/xmemcached-2.0.0) - person spudone; 28.04.2014