NoSQL数据转储(同步)方式

在使用数据库方面,我们经常会遇到读/写瓶颈,只要不是达到门户级的瓶颈,多数情况都能很好的解决。这段时间NoSQL的崛起,极大的方便解决写瓶颈。写瓶颈的解决方法是先把数据缓冲到NoSQl中,然后定时转储回RMDB里,毕竟RMDB的查询能力更强。所以,会遇到一个问题,就是数据怎么同步回RMDB?

假如,有这样的应用场景,我们使用了NoSQL来存储文章点击数(pv),并定时将点击数存储到MySQL里。

[b][size=large]一.用户触发转储[/size][/b]
首先给文章增加一个最后同步数据的时间戳,用于记录上次同步数据的时间戳,每次都先对比下最后同步时间是否大于n,大于n的话就同步回MySQL,然后将这次同步的时间戳保存回去。这个最后同步时间戳不一定要保存到MySQL里,如果使用了Memcached的话,可以保存到Memcached就可以了。

缺点:
1.如果静态化了,用户将触发不到这个机制
2.每次会有少量数据没同步到MySQL,因为没有达到时间间隔N的话就触发不了
3.并发大话,可能同一时间内会同步多次,所以要尽快保存最后同步时间戳,或者利用memcached的add方法来模拟锁,add方法如果key存在的话返回false,返回false表示被锁,可以不同步点击数。

[b][size=large]二.Redis[/size][/b]
Redis最明显的优势是支持数据结构,其次就是高性能。

[b]1.Multiple DB[/b]
Redis可以更换db,一个Redis我们可以划分多个db。用于存储不同维度的数据,避免混合在一起,例如,日志相册分db存储,更管各的。

[b]2.KEYS[/b]
KEYS可以返回所有的复合模式的Key,Redis天生对遍历Key提供了很良好的支持。

[b]3.SADD和SMEMBERS[/b]
Redis支持set结构,可以用set结构来存储有更新的文章id,然后通过这个列表去同步数据。
SADD对于已经存在的元素是不会添加到集合中的,也就是元素在set里是唯一的。SMEMBERS可以返回set里的所有元素。
也就是说,set里只是用来保存点击数有变动的文章id,然后通过这些文章id,去其它NoSQL里读取点击数,同步到数据库。

缺点:
1.专门部署Redis似乎不太值得
2.Redis是基于定时内存转储了,可能丢失部分数据
3.Redis太依赖内存,数据大于内存,使用swap,性能下降

[b][size=large]三.遍历Memcached[/size][/b]
虽然遍历Memcached不是一个好的方法,但是相信有其适用的场景。使用stats items和stats cachedump能得到所有的key。

[b]1.扩展memcache[/b]
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。

[b]2.扩展Memcached[/b]
到目前为止,Memcached::getStats不支持参数("items", "sizes", "slabs"...)

[b]3.山寨socket版[/b]
写了个socket版,作为后备使用。用正则来匹配,主要是不想循环去解析每行。
function memcachedGetKeys($host, $port) {
$keys = array();
$fp = fsockopen($host, $port, $errno, $errstr, 30);

if ($fp) {
fwrite($fp, "stats items\r\n");

$response = '';

while (substr($response, -5) != "END\r\n" && substr($response, -5) != "ERR\r\n") {
$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\n");

while (substr($response, -5) != "END\r\n" && substr($response, -5) != "ERR\r\n") {
$response .= fread($fp, 1024);
}

preg_match_all("/ITEM (.+) \[\d+ b; \d+ s\]/", $response, $matches);

$keys = array_merge($keys, $matches[1]);
}
}

return $keys;
}


缺点:
1.需要专门启动一个memcached来保存,遍历才不会有多余Key
2.memcached是保存在内存,数据丢失概率大。
3.memcached的LRU机制,内存不足的时候会导致数据被挤出

[b][size=large]四.全量更新、增量更新以及Key的命名[/size][/b]
[b]1.Key的命名[/b]
因为value是用来保存点击数,我们可以用key来保存逻辑数据,这样我们可以从key来判断出属于哪篇文章,例如:前缀_文章id(article_1)、前缀_文章id_某天的日期(article_1_2010-05-01)

[b]2.全量更新[/b]
如果只是想知道点击总数,那在统计和同步方面会比较简单,同步的时候直接全量更新就可以了。例如 UPDATE article SET view_count = ? WHERE article_id = ?

[b]3.增量更新[/b]
有时候,我们的需求是细化到每天的点击数和总点击数,那总点击数的更新就不得不使用增量更新了,因为我们只记录了每天的点击数,没有一个总点击数,当然也可以同时递增2个key,那总点击数依然可以使用全量更新。

增量更新的话,我们只增量昨天和昨天之前的数据,因为今天的数据还在更新。同步完后可以把昨天和昨天之前的数据删除了。例如 UPDATE article SET view_count = view_count + ? WHERE article_id = ?

有时候,需要及时知道今天的数据,那今天的数据就不删除了,等到明天删除,如果是全量更新的话就很好办了。但是如果是增量更新的话,那只能在程序里加一下点击数,而不同步到MySQL里。

说了很多,需求不一致,或许不能直接解决问题,只希望提供一点思路。

参考资料:
[url=http://www.cnblogs.com/sunli/archive/2008/11/01/1324153.html]如何对memcache的数据(key-value)进行遍历操作[/url]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值