NoSQLデータダンプ(同期)方式


データベースの使用では、ポータルレベルのボトルネックに達していない限り、多くの場合、読み取り/書き込みのボトルネックに遭遇します.この間のNoSQLの台頭は、書くボトルネックを解決するのに極めて便利でした.書き込みボトルネックの解決策は、まずデータをNoSQlにバッファリングし、その後、RMDBにタイミングよくダンプすることです.結局、RMDBのクエリー能力はもっと強いです.だから、データがどのようにRMDBに同期して戻るのかという問題があります.
もし、このようなアプリケーションシーンがあれば、NoSQLを使用して文章クリック数(pv)を格納し、タイミングよくクリック数をMySQLに格納します.
一.ユーザトリガダンプ
まず文章に最後の同期データのタイムスタンプを追加して、最後の同期データのタイムスタンプを記録して、毎回最後の同期時間がnより大きいかどうかを比較して、nより大きいならMySQLに同期して帰って、それから今度の同期のタイムスタンプを保存します.この最後の同期タイムスタンプはMySQLに保存する必要はありませんが、Memcachedを使用すればMemcachedに保存できます.
欠点:
1.静態化された場合、ユーザはこのメカニズムをトリガーできない
2.毎回少量のデータがMySQLに同期していないので、時間間隔Nに達していないとトリガーできない
3.同時に大きい場合は、同じ時間内に複数回同期する可能性があるので、できるだけ早く最後の同期タイムスタンプを保存するか、memcachedのaddメソッドを利用してロックをシミュレートし、addメソッドがkeyが存在する場合はfalseに戻り、falseに戻ってロックされていることを示し、クリック数を同期しなくてもよい.
二.Redis
Redisの最も顕著な利点は、データ構造をサポートすることであり、次いで高性能である.
1.Multiple DB
Redisはdbを交換することができ、1つのRedisは複数のdbを分割することができます.異なる次元のデータを格納し、混在しないようにします.たとえば、ログアルバムはdbに分けて格納され、より管理されます.
2.KEYS
KEYSはすべての複合モードのKeyを返すことができ,Redisは生まれながらにしてKeyを遍歴するのに良好なサポートを提供した.
3.SADDとSMEMBERS
Redisはset構造をサポートし、set構造で更新された文章idを格納し、このリストでデータを同期することができる.
SADDは既に存在する要素に対して集合に追加されない,すなわち要素はsetにおいて一意である.SMEMBERSはsetのすべての要素を返すことができます.
つまり、setにはクリック数が変動した文章idを保存するだけで、これらの文章idを通じて、他のNoSQLに行ってクリック数を読み取り、データベースに同期します.
欠点:
1.Redisの専門的な導入はあまり価値がないようです
2.Redisはタイミングメモリに基づいてダンプされ、データの一部が失われる可能性がある
3.Redisはメモリに依存しすぎて、データはメモリより大きくて、swapを使って、性能は下がります
三.Memcachedを巡る
Memcachedを巡るのは良い方法ではありませんが、適用可能なシーンがあると信じています.stats itemsとstats cachedumpを使用すると、すべてのkeyが得られます.
1.拡張memcache
class Memcache_Plus extends Memcache {

	public function getKeys() {
		$items = $this->getStats('items');
		$keys = array();

			$serverItems = $items['items'];

			foreach ($serverItems as $slabId => $item) {
				$slabKeys = $this->getStats('cachedump', $slabId, 0);

					foreach ($slabKeys as $slabKey => $slabKeyStatus) {
						$keys[] = $slabKey;
					}
			}

		return $keys;
	}

	public function getExtendedKeys() {
		$items = $this->getExtendedStats('items');
		$keys = array();

		foreach ($items as $server) {
			$serverItems = $server['items'];

			foreach ($serverItems as $slabId => $item) {
				$slabKeys = $this->getExtendedStats('cachedump', $slabId, 0);

				foreach ($slabKeys as $slabServer => $slabServerKeys) {
					foreach ($slabServerKeys as $slabServerKey => $slabServerKeyStatus) {
						$keys[] = $slabServerKey;
					}
				}
			}
		}

		return $keys;
	}
}}

次の操作を行います.
$memcache = new Memcache_Plus;
$memcache->addServer('192.168.80.128', 11211);

$keys = $memcache->getKeys();

getKeysは単一のサーバを返すkeyであり、getExtendedKeysはすべてのサーバを返すkeyである.
2.拡張Memcached
これまでMemcached::getStatsはパラメータをサポートしていません(「items」,「sizes」,「slabs」...)
3.socket版のパクリ
バックアップとしてsocket版を書きました.正則でマッチングするのは、主に各行をループして解析したくないからです.
function memcachedGetKeys($host, $port) {
	$keys = array();
	$fp = fsockopen($host, $port, $errno, $errstr, 30);

	if ($fp) {
		fwrite($fp, "stats items\r
"); $response = ''; while (substr($response, -5) != "END\r
" && substr($response, -5) != "ERR\r
") { $response .= fread($fp, 1024); } preg_match_all("/STAT items:(\d+):/", $response, $matches); $slabIds = array_flip(array_flip($matches[1])); foreach ($slabIds as $slabId) { $response = ''; fwrite($fp, "stats cachedump $slabId 0\r
"); while (substr($response, -5) != "END\r
" && substr($response, -5) != "ERR\r
") { $response .= fread($fp, 1024); } preg_match_all("/ITEM (.+) \[\d+ b; \d+ s\]/", $response, $matches); $keys = array_merge($keys, $matches[1]); } } return $keys; }

欠点:
1.memcachedを起動して保存する必要があります.
2.memcachedはメモリに保存されており、データ損失の確率が高い.
3.memcachedのLRUメカニズムは、メモリが不足した場合にデータが押し出される
四.フル・アップデート、インクリメンタル・アップデート、Keyのネーミング
1.Keyの命名
valueはクリック数を保存するために使用されるため、keyで論理データを保存することができ、keyからどの文章に属しているかを判断することができます.例えば、接頭辞_文章id(article_1)、接頭辞_記事id_ある日の日付(article_1_2010-05-01)
2.全量更新
クリック総数を知りたいだけなら、統計や同期が簡単で、同期時に直接全量更新すればいいのです.例えばUPDATE article SET view_count = ? WHERE article_id = ?
3.増分更新
时には、私たちの需要は毎日のクリック数と総クリック数に細分化して、その総クリック数の更新は増分更新を使用しなければなりません.私たちは毎日のクリック数だけを記録しているので、総クリック数は1つもありません.もちろん、同時に2つのkeyを増やすこともできます.その総クリック数は依然として全量更新を使用することができます.
増分更新では、昨日と昨日までのデータだけを増分します.今日のデータはまだ更新されているからです.同期が終わったら、昨日と昨日までのデータを削除することができます.例えばUPDATE article SET view_count = view_count + ? WHERE article_id = ?
时には、今日のデータをタイムリーに知る必要があるので、今日のデータは削除しません.明日削除するまで待って、全量更新すればやりやすいです.しかし、インクリメンタル更新であれば、MySQLに同期せずにプログラムにクリック数を追加するしかありません.
たくさん言ったが、需要が一致していないので、直接問題を解決できないかもしれないが、少し考えを提供したいだけだ.
参考資料:
memcacheのデータ(key-value)の遍歴操作方法