InnoDB memcached プラグイン利用時にはdelete()メソッド利用で未COMMITデータが失われる事がある

# 結論
InnoDB memcachedプラグインにて、存在しないキーに対するdelete()メソッドを利用すると未COMMITのデータが失われてしまうことがある。

# 前提条件
パフォーマンスチューニングとして、daemon_memcached_r_batch_size および daemon_memcached_w_batch_size の値を両方共増やした状態であるとする。
https://dev.mysql.com/doc/refman/5.6/ja/innodb-memcached-tuning.html

この時、システムがクラッシュすると未COMMITのデータが失われるのは当然の話なので許容範囲としますが、クラッシュしなくても未コミットのデータが失われるケースがある。

# 検証コード
以下、検証はRDS for MySQLにおける結果です。

## 検証コード1：正しい動作
```php:test1.php
<?php

  define ("RDS_HOST_NAME",  "******");

  $memcache_obj = new Memcache;
  $memcache_obj->addServer(RDS_HOST_NAME, 11211);

  $memcache_obj->set("key1","value1", 0 ,10);

  $memcache_obj->set("key2","value2", 0 ,10);
  $memcache_obj->delete("key2");  // set()したキーを削除する

  echo "rtn = ". $memcache_obj->get("key1")."\n";
```
→ rtn = value1 が出力される

## 検証コード2：set()したばかりのkey1の値が取得できない
```php:test1.php
<?php

  define ("RDS_HOST_NAME",  "******");

  $memcache_obj = new Memcache;
  $memcache_obj->addServer(RDS_HOST_NAME, 11211);

  $memcache_obj->set("key1","value1", 0 ,10);

  // $memcache_obj->set("key2","value2", 0 ,10);
  $memcache_obj->delete("key2");  // set()していないキーを削除する

  echo "rtn = ". $memcache_obj->get("key1")."\n";
```
→ rtn = が出力される

## 対策
以下のいずれかの対策が必要

1. daemon_memcached_r_batch_size および daemon_memcached_w_batch_size の値を1にする
2. delete()を行わずに、削除済みを表現するデータを1秒間だけset()する。

※2. のケースでnullを入れる場合にはnullを明示的にキャッシュするパターンとの検証は必要です。

# [おまけ]InnoDB memcached プラグインをセッションストレージとして利用したい理由
一言で言うと、お手軽にそれなりに信頼性のあるセッションストレージを準備出来るため。

※通常のMemcachedをセッションストレージとして利用したい場合には、冗長化対応が難しい。
参考：http://qiita.com/taruhachi/items/a844bf373623991873ff


## メリット
- MultiAZ環境であればノード障害時に自動フェイルオーバーが実行される
- スケールアップ、スケールイン時にキャッシュが揮発しない
- 能力を超えたスパイク時にもレイテンシが低下するだけで、深刻な障害に直結しにくい
- memcachedプロトコルを利用可能なので開発環境を整えやすい

## デメリット
- スケール変更時に若干のダウンタイムが発生する
- 自動でのスケール変更ができない
- memcachedと比較した場合にはコストパフォーマンスが悪い


## 他のセッションストレージとの比較
|  | ElastiCache Memcached | ElastiCache Redis | DynamoDB | RDS for MySQL memcached plugin |
|:----------:|:----------:|:----------:|:----------:|:----------:|
|ノード障害時の挙動 | 該当キャッシュが揮発する<br/>該当のキャッシュの汚染が発生する | 自動フェイルオーバー実行 | 自動フェイルオーバー実行 | 自動フェイルオーバー実行|
|性能上限 | 比較的高速 | 比較的高速 | 比較的高速 | スケールアップの上限あり|
|オートスケール | 出来ない | 出来ない | 出来る | 出来ない|
|スケール変更時のデータ担保 | "該当キャッシュが揮発する<br/>該当のキャッシュの汚染が発生する | キャッシュが全て揮発する | 影響が発生しない | 影響が発生しない|
|スケール変更時の挙動 | そもそもデータが担保されない | そもそもデータが担保されない | ダウンタイムが発生しない | ダウンタイムが発生する(数十秒)|
|メンテナンスウインドウ | あり（キャッシュが揮発する） | あり（キャッシュが揮発しない） | あり（キャッシュが揮発しない） | あり（キャッシュが揮発しない）|
|スパイク時の挙動 | レイテンシが低下する | レイテンシが低下する | キャパシティユニットの追加が完了するまでの間、スロットルされた以上のリクエストに対してエラーが発生する | レイテンシが低下する|
|特記事項（メリット） | memcachedプロトコルを利用可能 |  | 使用頻度が低い時に低コスト | memcachedプロトコルを利用可能|
|特記事項（デメリット） | 高負荷時にはノード間のデータ汚染はかなりの頻度で発生する。 | スケール変更ができないので、高コストになりがちである。 | ・独自プロトコルであるため変更しにくい<br/>・使用頻度が高い時に高コストである<br/>・一度パーティション分割が進んでしまうと、その後恒常的にスロットルが発生し始めることがある。 | del()利用時にロールバックされる。<br/>同時接続数を1024より増やせない。<br/>永続的接続時に接続の切断が発生する。 |

デメリットとしてコストパフォーマンスの悪さがあるが、スケール変更や障害時におけるデータの担保のしやすさなどからのメリットも多そうである。

# 追記
アプリケーションを構築し、負荷試験を実施したところ、2点問題が発覚しました。

## 問題1
永続的接続を利用した際に、サーバからの接続の切断が頻繁に発生する。（そもそも永続化されていない可能性あり？？）

## 問題2
順次負荷を増やしていったところ、
``` MemcachePool::set(): Server [HOSTNAME] (tcp 11211, udp 0) failed with: Connection refused (111)" ```
というエラーが頻発するようになりました。
接続周りのエラーであることから、
``` MAX_SIMULTANEOUS_CONNECTIONS ```
を変更しようとしたのですが、RDSではこの値の範囲は10-1024の範囲でしか設定できないようです。