Redis到底该如何利用?【转自:http://www.cnblogs.com/capqueen/p/HowToUseRedis.html】
Redis是个好东西,经过上两个星期的研究和实践,目前正在项目里大规模的替换掉原来的本地内存cache。但是替换过程中却发现,Redis这东西高端,大气上档次,似乎不是我想象里的使用方法。
在没有深入Redis之前,在我的概念里,缓存,就是key-value。而使用方式肯定不需要改动多少代码,一 切都是Get/Set。但是实际用的时候却发现,我错了,不是所有的场景都是简单的Get/Set。也不是所有的数据都适合key-Value,于是有了 这个问题,Redis到底该如何使用?我问自己,也向园子里的朋友们求助,希望帮忙解答。当然,这篇文章抛砖引玉,先谈谈我这两周的感悟。
使用场景
在我的项目里,有一个提供给Autocomplete的功能,数据量大概在几万。这篇文章里我用姓名检索的例子来说明,列表请戳来自Redis作者的Demo。
在这样的列表里全是用户名,例如我们的系统里有一个用户对象:

public Class User
{
public string Id{get; set;}
public string Name {get; set;}
....
public string UserHead {get; set;}
}

系统里需要一个用户的下拉列表,由于数据量大不能一次显示完,于是就加上了一个AutoComplete功能。如果是不用Redis这样的集中式缓存,直接缓存在本机内存里,那么结构很简单如下:
var users = new List<User>{...};//读到一个用户列表
MemoryCache.Set("capqueen:users", users);//放入内存
//读取
var users = MemoryCache.Get<List<User>>("capqueen:users");
因为都是在内存里,所以直接存List就可以了,搜索的时候也可以直接的如下:
var findUsers = users.Where(user => user.Name.StartWith("A")).ToList();例如输入的字符是 “A“
相当简单,完全不用考虑如何存储,存储的数据结构。但是换到了Redis这些集中式缓存服务之后,咱们再来思考,该如何存储。
方案一:类似内存式的缓存实现。
本文里使用的Redis链接库是StactkExchange.Redis,出自StackOverFlow的开源产品。

var db = redis.GetDataBase();//获取0数据库
var usersJson = JsonConvert.SerializeObject(users)//序列化
db.StringSet("capqueen:users", usersJson);//存储
var usersString = db.StringGet("capqueen:users");
var userList = JsonConvert.DeserializeObject<List<User>>(users);//反序列化

上面的方式逻辑上是没有问题的,编译也可以通过。但是仔细想一想,Redis作为独立的缓存服务和appSever是分开来的,这样的读取方式对redis服务器的IO是个负担,甚至这样的读取比本地内存缓存慢了太多了。
那如何解决呢?试想key-value的精髓是在于Key,那么对于List来说应该要把item分开来存储。
方案二:Keys模糊匹配。
在查看了Redis的命令文档(见参考资料4)之后,发现了命令Keys,如获至宝,立马修改了方案。首先我们需 要把要搜索的关键词建立为key,这里我把key定义为 "capqueen:user:{id}:{name}",其中{}内的是要用item对应属性替换的。代码如下:

var redis = ConnectionMultiplexer.Connect("localhost");
var db = redis.GetDatabase();
var users = new List<User> {
new User{Id = 6, Name = "aaren", Age=10},
new User{Id = 7, Name = "issy", Age=11},
new User{Id = 8, Name = "janina", Age=13},
new User{Id = 9, Name = "karena", Age=14}
};
users.ForEach(item => {
var key = string.Format("capqueen:user:{0}:{1}", item.Id, item.Name);
var value = JsonConvert.SerializeObject(item);
db.StringSet(key, value);
});

建立好的缓存如下图所示:

所有的user都以单独的Key-Value方式存储,那么如何利用Keys搜索呢?我们来看下Redis的Keys命令:

KEYS pattern 查找所有符合给定模式 pattern 的 key 。 KEYS * 匹配数据库中所有 key 。
KEYS h?llo 匹配 hello , hallo 和 hxllo 等。
KEYS h*llo 匹配 hllo 和 heeeeello 等。
KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo 。
特殊符号用 \ 隔开

也就是说Keys能够进行简单的模糊匹配,那么我们这里的搜索就可以换成如下的方式:

var redis = ConnectionMultiplexer.Connect("192.168.10.178");
var db = redis.GetDatabase();
var server = redis.GetServer("192.168.10.178", 6379);
var keys = server.Keys(pattern: "capqueen:user:*:a*");
var values = db.StringGet(keys.ToArray());
//反序列化
var jsonValues = new StringBuilder("[");
values.ToList().ForEach(item => jsonValues.Append(item).Append(","));
jsonValues.Append("]");
var userList = JsonConvert.DeserializeObject<List<User>>(jsonValues.ToString());

注意以上的代码里,因为每个value是一个json,为了增加转化时的效率,我先处理成json arry再进行反序列化。
这种方案,确实是解决了我目前的问题,然而我注意到了Redis文档里的一段话:
KEYS 的速度非常快,但在一个大的数据库中使用它仍然可能造成性能问题,如果你需要从一个数据集中查找特定的 key ,你最好还是用 Redis 的集合结构(set)来代替。
这段话换而言之就是慎用Keys搜索的意思,那么有什么更好的解决方案呢?由于这篇文章我拖得很久了,这里留个问题在末尾,期待有大牛能够帮忙解答,感激不尽。当然还有下一篇内容,我会讲讲我目前的处理方法。
下篇文章里,我会根据Redis作者的博客(资料1)里的做法以及我最后查到的资料,做一个新的方案,请大家到时指教。
参考资料
- Redis作者博客,这是其中一篇讲如何基于Redis实现AutoComplete的文章:http://oldblog.antirez.com/post/autocomplete-with-redis.html
- Redis 第三方管理工具 For Windows:http://redisdesktop.com/
- Redis .NET链接工具的Top20:http://nugetmusthaves.com/Tag/Redis
- Redis命令中文文档:http://redisdoc.com/
Redis到底该如何利用?【转自:http://www.cnblogs.com/capqueen/p/HowToUseRedis.html】的更多相关文章
- Redis到底该如何利用?
Redis是个好东西,经过上两个星期的研究和实践,目前正在项目里大规模的替换掉原来的本地内存cache.但是替换过程中却发现,Redis这东西高端,大气上档次,似乎不是我想象里的使用方法. 在没有深入 ...
- Redis到底该如何利用(三)?
上两篇受益匪浅,秉着趁热打铁,不挖到最深不罢休的精神,我决定追加这篇.上一篇里最后我有提到实现分级缓存管理应该是个可行的方案,因此今天特别实践了一下.不过缓存分级之后也发现了一些问题,例如下图: 当a ...
- Redis到底该如何利用(二)?
上一篇文章里我简述了使用Keys作为Redis搜索的方式,确实感受到了社区的力量,写文章好处多.首先谢谢各位前辈的指导,我知道了拿Redis作为搜索是个错误的方向.本来这篇文章我觉得确实没必要发了,但 ...
- redis弱密码漏洞利用
背景: redis无认证,或者弱密码,可以成功连接到redis服务器 反弹shell拿到的权限取决于redis的启动账号 操作: 1. Centos7安装redis客户端 #yum install r ...
- Redis07——Redis到底能用在什么地方(下)
在前一篇文章中,我们已经介绍过Redis的一些实际应用.如KV缓存.分布式锁.消息队列,由于篇幅原因,并未介绍完全.接下来将继续为各位带来Redis的更多应用. bitmat(位图) 实现 位图的基本 ...
- Redis配置及攻击利用
Redis配置及攻击利用 Redis及其安全配置 Redis介绍 redis默认会绑定在 0.0.0.0:6379,如果没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源 ip 访问等,这样 ...
- Redis入门和Java利用jedis操作redis
Redis入门和Java利用jedis操作redis Redis介绍 Redis 是完全开源的,遵守 BSD 协议,是一个高性能的 key-value 数据库. Redis 与其他 key - val ...
- 利用Word发布文章到cnblogs博客
利用Word发布文章到cnblogs博客 用博客园cnblogs:http://www.cnblogs.com/博客名称/services/metablogapi.aspx,word老是提醒" ...
- Redis 到底是单线程还是多线程?我要吊打面试官!
最近在Java技术栈公众号发布的一篇文章,其中有一道题: Redis是多线程还是单线程?(回答单线程的请回吧,为什么请回,请往下看) 好些粉丝在后台问我:为什么请回,Redis不是单线程吗? 大家注意 ...
随机推荐
- python时间相关
1.格式化时间time.strftime,返回字符串 import time time.strftime('%Y-%m-%d %H:%M:%S') 2.时间差 timedelta from datet ...
- http协议状态码对照表
1**:请求收到,继续处理 2**:操作成功收到,分析.接受 3**:完成此请求必须进一步处理 4**:请求包含一个错误语法或不能完成 5**:服务器执行一个完全有效请求失败 100——客户必须继续发 ...
- hql 关联查询
HQL 带的连接语句只能是实体与 该实体的属性 进行连接 其意义就是为了优化(通过延迟加载查询关联的属性)需要进行配置 from A left join A.B where (b.flag is nu ...
- js设计模式-建造者模式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Redis+php-resque实现消息队列
服务器硬件配置 Dell PowerEdge R310英特尔单路机架式服务器 Intel Xeon Processor X3430 2.4GHz, 8MB Cache 8GB内存(2 x 4GB) ...
- hbase删除region块的脚本
删除hbase表region块脚本 文件hua.txt格式: CHAT_INFO,1318153079100530000314050,1318173760068.991ca04ff164c3f7987 ...
- 由后序遍历结果构造二叉查找树 && 二叉查找树链表化
二叉查找树通俗说就是左孩子比父亲小,右孩子比父亲大.构造这么一个树,树嘛,递归即可. 例如一棵树后序遍历是这样(下图的树):2 9 8 16 15 10 25 38 45 42 30 20.最后的20 ...
- view上添加点手势 button无法响应点击事件
在view 上添加手势 有的时候 会把Button的 点击事件盖掉,这个 时候 我们用UITapGestureRecognizer的代理方法 //手势的代理方法 - (BOOL)gestureRec ...
- 使用HTML5构建下一代的Web Form
HTML语言作为如今编程最为广泛的语言,具有易用.快捷.多浏览平台兼容等特点,但是随着时代的进步,HTML的标准却停滞不前,这一次还在不断开发中的[color=#444444 !important]H ...
- mysql快速上手1
mysql简介 1.什么是数据库 ? 数据库(Database)是按照数据结构来组织.存储和管理数据的仓库,它产生于距今六十多年前,随着信息技术和市场的发展,特别是二十世纪九十年代以后,数据管理不再仅 ...