Элементы, установленные с помощью spymemcached, не могут быть извлечены с помощью php memcached
Я использую spymemcached. Я задал пару вопросов. Затем я запускаю PHP-скрипт, однако тогда я не могу получить все эти элементы с помощью php memcached. PHP-Memcached может только частично получить эти элементы.
Я не могу изменить алгоритм хеширования php или стратегию распространения. В нашей системе мы используем хэширование по умолчанию (которое является дженкином один-на-время в соответствии с php.net документация). И стратегия распространения по модулю для php-memcached. Я читал, что spymemcached использует последовательное хеширование. Есть ли способ я могу использовать хеширование дулю в spymemcached.
другими словами, как я могу сделать операции набора spymemcached или любые другие операции хранилища совместимыми с операциями get 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'));
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 lib.
Решение 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'));
хэш-алгоритмы, которые поддерживает 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);
Re: Kakawait (а также Шейдам88)
решение #2 неверно, потому что xmemcached неправильно портировал исходный код C хэша Дженкинса, который использует неподписанный. Исправление этого также решит исключение 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.дат:
sausage=2834523395
blubber=1103975961
pencil=3318404908
cloud=670342857
moon=2385442906
water=3403519606
computer=2375101981
school=1513618861
network=2981967937
hammer=1218821080
... добавить столько, сколько вы хотите