8

spymemcached を使用しています。いくつかのアイテムを設定しました。次に、php スクリプトを実行しますが、php memcached を使用してこれらのアイテムをすべて取得することはできません。PHP-Memcached は、これらのアイテムを部分的にしか取得できません。

PHP のハッシュ アルゴリズムや分散戦略を変更できません。私たちのシステムでは、デフォルトのハッシュを使用しています(これは、php.netのドキュメントによると、一度に1つずつジェンキンです)。また、分散戦略は php-memcached のモジュロです。spymemcached がコンシステント ハッシュを使用していることを読みました。spymemcached でモジュロ ハッシュを使用する方法はありますか。

つまり、spymemcached の set 操作またはその他のストア操作を php-memcached の get 操作と互換性を持たせるにはどうすればよいでしょうか?

spymemcached でそれができない場合、それを可能にする Java の他の memcached クライアントはありますか?

支援は感謝されるだけでなく、報奨金も与えられます。

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'));
4

3 に答える 3

9

問題はハッシュに関するもので、デフォルトの php-memcached ハッシュは

(Jenkins 1 つずつ) アイテム キー ハッシュ アルゴリズム

一方、spymemcached ハッシュのリストは次のとおりです。

  • NATIVE_HASH: デフォルトの php-memcached と単純Native hash (String.hashCode()).に一致しません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=> 「ketama が使用する MD5 ベースのハッシュ アルゴリズム。」そうかもしれませんMemcached::HASH_MD5が、とにかくそうではありませんMemcached::HASH_DEFAULT

そのため、PHP クライアントの構成を変更したり、spymemcached ライブラリを拡張したりできない場合、2 つのライブラリが直接一致することはありません。

解決策 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");
    }
}
于 2013-10-03T09:07:34.810 に答える
3

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);
于 2013-09-25T21:29:06.257 に答える
1

Re: Kakawait (Shades88 にも)

解決策 2 は正しくありません。これは、xmemcached が未署名を使用する Jenkins ハッシュの元の C コードを適切に移植していないためです。これを修正すると、Shades88 で発生していた ArrayIndexOutOfBoundsException も解決されます。

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

... 好きなだけ追加

于 2014-01-03T18:17:48.460 に答える