[转] 分布式Redis架构设计和踩过的那些坑们

2015-07-12 08:12:13 查看评论 2138 人阅读    

此文根据【QCON高可用架构群】分享内容,由群内【编辑组】志愿整理,转发请注明出处。

      黄东旭,Ping CAP CTO,开源项目Codis的co-author。之前在豌豆荚从事infrastructure相关的工作,现在在创业公司PingCAP,方向依然是分布式存储领域(NewSQL)。


本次分享的内容主要包括五个大部分:

  • Redis、RedisCluster和Codis;

  • 我们更爱一致性;

  • Codis在生产环境中的使用的经验和坑们;

  • 对于分布式数据库和分布式架构的一些看法;

  • Q & A环节。

  Codis是一个分布式Redis解决方案,与官方的纯P2P的模式不同,Codis采用的是Proxy-based的方案。今天我们介绍一下Codis及下一个大版本RebornDB的设计,同时会介绍一些Codis在实际应用场景中的tips。最后抛砖引玉,会介绍一下我对分布式存储的一些观点和看法,望各位首席们雅正。

一、 Redis,RedisCluster和Codis


  Redis:想必大家的架构中,Redis已经是一个必不可少的部件,丰富的数据结构和超高的性能以及简单的协议,让Redis能够很好的作为数据库的上游缓存层。但是我们会比较担心Redis的单点问题,单点Redis容量大小总受限于内存,在业务对性能要求比较高的情况下,理想情况下我们希望所有的数据都能在内存里面,不要打到数据库上,所以很自然的就会寻求其他方案。 比如,SSD将内存换成了磁盘,以换取更大的容量。更自然的想法是将Redis变成一个可以水平扩展的分布式缓存服务,在Codis之前,业界只有Twemproxy,但是Twemproxy本身是一个静态的分布式Redis方案,进行扩容/缩容时候对运维要求非常高,而且很难做到平滑的扩缩容。Codis的目标其实就是尽量兼容Twemproxy的基础上,加上数据迁移的功能以实现扩容和缩容,最终替换Twemproxy。从豌豆荚最后上线的结果来看,最后完全替换了Twem,大概2T左右的内存集群。

  Redis Cluster  :与Codis同期发布正式版的官方cluster,我认为有优点也有缺点,作为架构师,我并不会在生产环境中使用,原因有两个:

  • cluster的数据存储模块和分布式的逻辑模块是耦合在一起的,这个带来的好处是部署异常简单,all-in-the-box,没有像Codis那么多概念,组件和依赖。但是带来的缺点是,你很难对业务进行无痛的升级。比如哪天Redis cluster的分布式逻辑出现了比较严重的bug,你该如何升级?除了滚动重启整个集群,没什么好办法。这个比较伤运维。

  • 对协议进行了较大的修改,对客户端不太友好,目前很多客户端已经成为事实标准,而且很多程序已经写好了,让业务方去更换Redisclient,是不太现实的,而且目前很难说有哪个Rediscluster客户端经过了大规模生产环境的验证,从HunanTV开源的Rediscluster proxy上可以看得出这个影响还是蛮大的,否则就会支持使用cluster的client了。

  Codis:和Redis cluster不同的是,Codis采用一层无状态的proxy层,将分布式逻辑写在proxy上,底层的存储引擎还是Redis本身(尽管基于Redis2.8.13上做了一些小patch),数据的分布状态存储于zookeeper(etcd)中,底层的数据存储变成了可插拔的部件。这个事情的好处其实不用多说,就是各个部件是可以动态水平扩展的,尤其无状态的proxy对于动态的负载均衡,还是意义很大的,而且还可以做一些有意思的事情,比如发现一些slot的数据比较冷,可以专门用一个支持持久化存储的server group来负责这部分slot,以节省内存,当这部分数据变热起来时,可以再动态的迁移到内存的server group上,一切对业务透明。比较有意思的是,在Twitter内部弃用Twmeproxy后,t家自己开发了一个新的分布式Redis解决方案,仍然走的是proxy-based路线。不过没有开源出来。可插拔存储引擎这个事情也是Codis的下一代产品RebornDB在做的一件事情。btw,RebornDB和它的持久化引擎都是完全开源的,见https://github.com/reborndb/reborn和https://github.com/reborndb/qdb。当然这样的设计的坏处是,经过了proxy,多了一次网络交互,看上去性能下降了一些,但是记住,我们的proxy是可以动态扩展的,整个服务的QPS并不由单个proxy的性能决定(所以生产环境中我建议使用LVS/HA Proxy或者Jodis),每个proxy其实都是一样的。

640.png


分类: Nosql 标签: codis redis 分布式

[转]通过telnet连接查看memcache服务器

2015-01-06 05:50:16 查看评论 883 人阅读    

memcache作为一款优秀的进程外缓存,常常被运用于高并发系统架构中。这里主要谈谈怎么通过telnet工具,查看memcache运行状况并对其key进行管理维护。假设memcache安装目录:/usr/local/memcached

          
1、启动memcache

# /usr/local/memcached/bin/memcached -d -m 512  -u root -l 192.168.119.70 -p 12000 -c 512 -P /usr/local/memcached/memcached.pid

启动参数详解
 -d:以守护进程方式启动。如果该参数没有指定,当按ctrl+c命令结束,memcache自动关闭
 -m:分配给memcache使用的最大内存数 单位是m,默认是64m
 -u: 指定运行memcache的用户
 -l: 指定监听的ip地址
 -p: 指定监听的tcp端口号,可以通过-u指定udp端口.默认是11211
 -c: 最大并发连接数
 -P: 报错进程id的文件
 memcache 启动之后,我们就可以通过telnet连接memcache,对其进行简单操作管理。


2、telnet连接memcache

# telnet 192.168.119.70 12000

blob.png


分类: Nosql 标签: memcache telnet

[转]Mongodb的常用操作

2014-05-06 15:27:07 查看评论 836 人阅读    

一、查询

find方法

db.collection_name.find();

查询所有的结果:

select * from users;

db.users.find();

指定返回那些列(键):

select name, skills from users;

db.users.find({}, {'name' : 1, 'skills' : 1});

补充说明: 第一个{} 放where条件 第二个{} 指定那些列显示和不显示 (0表示不显示 1表示显示)

where条件:

1.简单的等于:

select name, age, skills from users where name = 'hurry';

db.users.find({'name' : 'hurry'},{'name' : 1, 'age' : 1, 'skills' : 1});

2.使用and

select name, age, skills from users where name = 'hurry' and age = 18;

db.users.find({'name' : 'hurry', 'age' : 18},{'name' : 1, 'age' : 1, 'skills' : 1});

3.使用or

select name, age, skills from users where name = 'hurry' or age = 18;

db.users.find({ '$or' : [{'name' : 'hurry'}, {'age' : 18}] },{'name' : 1, 'age' : 1, 'skills' : 1});

4.<, <=, >, >= ($lt, $lte, $gt, $gte )

select * from users where age >= 20 and age <= 30;

db.users.find({'age' : {'$gte' : 20, '$lte' : 30}});

5.使用in, not in ($in, $nin)

select * from users where age in (10, 22, 26);

db.users.find({'age' : {'$in' : [10, 22, 26]}});

6.匹配null

select * from users where age is null;

db.users.find({'age' : null);

7.like (mongoDB 支持正则表达式)

select * from users where name like "%hurry%";

db.users.find({name:/hurry/}); 

select * from users where name like "hurry%";

db.users.find({name:/^hurry/}); 

8.使用distinct

select distinct (name) from users;

db.users.distinct('name');

9.使用count

select count(*) from users;

db.users.count();

10.数组查询 (mongoDB自己特有的)

如果skills是 ['java','python']

db.users.find({'skills' : 'java'}); 该语句可以匹配成功

$all

db.users.find({'skills' : {'$all' : ['java','python']}}) skills中必须同时包含java 和 python 

$size

db.users.find({'skills' : {'$size' : 2}}) 遗憾的是$size不能与$lt等组合使用

$slice

db.users.find({'skills' : {'$slice : [1,1]}})

两个参数分别是偏移量和返回的数量

11.查询内嵌文档 

db.postings.find( { "author.name" : "joe" } );

注意用法是author.name,用一个点就行了。

举个例子:

> db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})

如果我们要查询 authors name 是Jane的, 我们可以这样:

> db.blog.findOne({"author.name" : "Jane"})

如果不用点,那就需要用下面这句才能匹配:

db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})

下面这句:

db.blog.findOne({"author" : {"name" : "Jane"}})

是不能匹配的,因为mongodb对于子对象,他是精确匹配。

12.强大的$where查询

db.foo.find();                   
{ "_id" : ObjectId("4e17ce0ac39f1afe0ba78ce4"), "a" : 1, "b" : 3, "c" : 10 }
{ "_id" : ObjectId("4e17ce13c39f1afe0ba78ce5"), "a" : 1, "b" : 6, "c" : 6 }

如果要查询 b = c 的文档怎么办?

> db.foo.find({"$where":function(){

    for(var current in this){
        for(var other in this){
            if(current != other && this[current] == this[other]){
                return true;    
            }
        }
    }
    return false;

}});

 

{ "_id" : ObjectId("4e17ce13c39f1afe0ba78ce5"), "a" : 1, "b" : 6, "c" : 6 }

分类: Nosql 标签:

[转]Redis监控技巧

2014-04-26 09:39:20 查看评论 768 人阅读    

本文来自 Bugsnag 的联合创始人 Simon Maynard 的系列文章,作者根据几年来对 Redis 的使用经历,对 Redis 监控方法进行了系统性的总结,干货很多,值得一看。

原文链接:Redis Masterclass – Part 2, Monitoring

Redis 监控最直接的方法当然就是使用系统提供的 info 命令来做了,你只需要执行下面一条命令,就能获得 Redis 系统的状态报告。

redis-cli info

内存使用

如果 Redis 使用的内存超出了可用的物理内存大小,那么 Redis 很可能系统会被 OOM Killer杀掉。针对这一点,你可以通过 info 命令对 used_memory 和 used_memory_peak 进行监控,为使用内存量设定阈值,并设定相应的报警机制。当然,报警只是手段,重要的是你得预先计划好,当内存使用量过大后,你应该做些什么,是清除一些没用的冷数据,还是把 Redis 迁移到更强大的机器上去。

持久化

如果因为你的机器或 Redis 本身的问题导致 Redis 崩溃了,那么你唯一的救命稻草可能就是 dump 出来的 rdb文件了,所以,对 Redis dump 文件进行监控也是很重要的。你可以通过对rdb_last_save_time 进行监控,了解你最近一次 dump 数据操作的时间,还可以通过对rdb_changes_since_last_save 进行监控来知道如果这时候出现故障,你会丢失多少数据。

主从复制

如果你设置了主从复制模式,那么你最好对复制的情况是否正常做一些监控,主要是对 info 输出中的 master_link_status 进行监控,如果这个值是 up,那么说明同步正常,如果是 down,那么你就要注意一下输出的其它一些诊断信息了。比如下面这些:

role:slave
master_host:192.168.1.128
master_port:6379
master_link_status:down
master_last_io_seconds_ago:-1
master_sync_in_progress:0
master_link_down_since_seconds:1356900595
分类: Nosql 标签: