

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 用戶端的最佳實務 (Memcached)
<a name="BestPractices.Clients.memcached"></a>

了解 ElastiCache for Memcached 叢集常見案例的最佳實務。

**Topics**
+ [設定 ElastiCache 用戶端以實現高效率的負載平衡 (Memcached)](BestPractices.LoadBalancing.md)
+ [使用 Memcached 驗證的用戶端](network-type-validated-clients-memcached.md)
+ [為雙堆疊叢集設定偏好的通訊協定 (Memcached)](network-type-configuring-dual-stack-memcached.md)

# 設定 ElastiCache 用戶端以實現高效率的負載平衡 (Memcached)
<a name="BestPractices.LoadBalancing"></a>

**注意**  
本節適用於節點型多節點 Memcached 叢集。

若要有效使用多個 ElastiCache Memcached 節點，您需要將快取索引鍵分散到各個節點。負載平衡叢集與 *n* 個節點的簡單方法是計算物件金鑰的雜湊，並以 *n*： 修改結果`hash(key) mod n`。產生的值 (0 到 *n*–1) 便是您置放物件的節點數。

只要節點數 (*n*) 為常數，此方法便相當簡易且運作良好。但是，每當您新增節點到叢集，或從叢集移除節點時，需要移動的鍵數便是 *(n - 1) / n* (其中 *n* 是新的節點數)。因此，此方法會導致移動大量的鍵，引發大量的初始快取遺漏，尤其是在節點數越來越大時。從 1 個擴展到 2 個節點會導致 (2-1)/2 (50%) 的索引鍵移動，這是最佳情況。從 9 個擴展到 10 個節點會導致 (10–1)/10 (90%) 的索引鍵移動。若您因為流量的峰值而向上擴展，您不會希望發生大量的快取遺漏。大量的快取遺漏會導致資料庫遭受衝擊，尤其是藉時資料庫已經因為流量峰值而超載了。

此難題的解決方案便是一致性雜湊。一致雜湊所使用的演算法，會讓節點新增到叢集或從叢集移除節點時需移動的索引鍵數約為 *1/n* (其中 *n* 是新節點的數量)。從 1 擴展到 2 個節點會導致 1/2 (50%) 的鍵移動，此為最壞情況。從 9 擴展到 10 個節點會導致 1/10 (10%) 的鍵移動。

做為使用者，您可以控制要用於多節點叢集的雜湊演算法。建議您設定用戶端，以使用一致性雜湊。所幸，在大多數的熱門語言中，有許多 Memcached 用戶端程式庫都實作了一致性雜湊。檢查您使用的程式庫文件，查看其是否支援一致性雜湊以及其實作方式。

若您使用 Java、PHP 或 .NET，建議您使用其中一個 Amazon ElastiCache 用戶端程式庫。

## 使用 Java 的一致性雜湊
<a name="BestPractices.LoadBalancing.Java"></a>

ElastiCache Memcached Java 用戶端是以開放原始碼的 spymemcached Java 用戶端為基礎，其內建了一致雜湊功能。程式庫包含實作一致性雜湊的 KetamaConnectionFactory 類別。根據預設，spymemcached 中會關閉一致性雜湊。

如需詳細資訊，請參閱 [KetamaConnectionFactory](https://github.com/RTBHOUSE/spymemcached/blob/master/src/main/java/net/spy/memcached/KetamaConnectionFactory.java) 中的 KetamaConnectionFactory 文件。

## 搭配 Memcached 使用 PHP 的一致雜湊
<a name="BestPractices.LoadBalancing.PHP"></a>

ElastiCache Memcached PHP 用戶端是內建 Memcached PHP 程式庫的包裝函數。根據預設，Memcached PHP 程式庫會關閉一致性雜湊。

請使用以下程式碼來開啟一致性雜湊。

```
$m = new Memcached();
$m->setOption(Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT);
```

除了上述程式碼之外，我們建議也在您的 php.ini 檔案中開啟 `memcached.sess_consistent_hash`。

 如需詳細資訊，請參閱位於 [http://php.net/manual/en/memcached.configuration.php](http://php.net/manual/en/memcached.configuration.php) 的 Memcached PHP 執行時間設定文件。請特別注意 `memcached.sess_consistent_hash` 參數。

## 使用 .NET 搭配 Memcached 的一致雜湊
<a name="BestPractices.LoadBalancing.dotNET"></a>

ElastiCache Memcached .NET 用戶端是 Enyim Memcached 的包裝函數。根據預設，Enyim Memcached 用戶端會開啟一致性雜湊。

 如需詳細資訊，請參閱 `memcached/locator` 說明文件，網址為 [https://github.com/enyim/EnyimMemcached/wiki/MemcachedClient-Configuration\$1user-content-memcachedlocator](https://github.com/enyim/EnyimMemcached/wiki/MemcachedClient-Configuration#user-content-memcachedlocator)。

# 使用 Memcached 驗證的用戶端
<a name="network-type-validated-clients-memcached"></a>

下列用戶端已經過特別驗證，可搭配 Memcached 的所有支援網路類型組態使用。

已驗證的用戶端：
+ 適用於 [AWS Php 的 ElastiCache 叢集用戶端 Memcached](https://github.com/awslabs/aws-elasticache-cluster-client-memcached-for-php) – [版本 \$13.6.2](https://github.com/awslabs/aws-elasticache-cluster-client-memcached-for-php/tree/v3.2.0)
+ [AWS 適用於 Java 的 ElastiCache 叢集用戶端 Memcached](https://github.com/awslabs/aws-elasticache-cluster-client-memcached-for-java) – Github 上的最新主伺服器

# 為雙堆疊叢集設定偏好的通訊協定 (Memcached)
<a name="network-type-configuring-dual-stack-memcached"></a>

針對 Memcached 叢集，您可以使用 IP 探索參數，控制用戶端用來連線至叢集中節點的通訊協定。IP 探索參數可以設為 IPv4 或 IPv6。

IP 探索參數可控制設定取得叢集輸出中使用的 IP 通訊協定。這也會決定用戶端使用的 IP 通訊協定，這些通訊協定支援 ElastiCache for Memcached 叢集的自動探索功能。

變更 IP 探索不會導致連線用戶端停機。但是，該變更需要一些傳播時間。

監控 Java 的 `getAvailableNodeEndPoints` 輸出，針對 Php 則監控 `getServerList` 的輸出。一旦這些函數的輸出報告了叢集中使用更新通訊協定的所有節點 IP，就表示變更已完成傳播。

Java 範例：

```
MemcachedClient client = new MemcachedClient(new InetSocketAddress("xxxx", 11211));

Class targetProtocolType = Inet6Address.class; // Or Inet4Address.class if you're switching to IPv4

Set<String> nodes;
    
do {
    nodes = client.getAvailableNodeEndPoints().stream().map(NodeEndPoint::getIpAddress).collect(Collectors.toSet());

    Thread.sleep(1000);
} while (!nodes.stream().allMatch(node -> {
            try {
                return finalTargetProtocolType.isInstance(InetAddress.getByName(node));
            } catch (UnknownHostException ignored) {}
            return false;
        }));
```

Php 範例：

```
$client = new Memcached;
$client->setOption(Memcached::OPT_CLIENT_MODE, Memcached::DYNAMIC_CLIENT_MODE);
$client->addServer("xxxx", 11211);

$nodes = [];
$target_ips_count = 0;
do {
    # The PHP memcached client only updates the server list if the polling interval has expired and a
    # command is sent
    $client->get('test');
 
    $nodes = $client->getServerList();

    sleep(1);
    $target_ips_count = 0;

    // For IPv4 use FILTER_FLAG_IPV4
    $target_ips_count = count(array_filter($nodes, function($node) { return filter_var($node["ipaddress"], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6); }));
 
} while (count($nodes) !== $target_ips_count);
```

在更新 IP 探索之前建立的任何現有用戶端連線仍會使用舊通訊協定進行連線。一旦在叢集探索命令的輸出中偵測到變更，所有經過驗證的用戶端都會使用新的 IP 通訊協定自動重新連線至叢集。但是，這仍取決於用戶端的操作。