zoukankan      html  css  js  c++  java
  • 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)里的做法以及我最后查到的资料,做一个新的方案,请大家到时指教。

    参考资料

    1. Redis作者博客,这是其中一篇讲如何基于Redis实现AutoComplete的文章:http://oldblog.antirez.com/post/autocomplete-with-redis.html
    2. Redis 第三方管理工具 For Windows:http://redisdesktop.com/
    3. Redis .NET链接工具的Top20:http://nugetmusthaves.com/Tag/Redis
    4. Redis命令中文文档:http://redisdoc.com/
  • 相关阅读:
    创业者,你有梦想吗?
    中型企业能撑过现金危机
    共享经济与优步(Uber)如何获取监管支持?
    TJX:好买手养成记
    问得更少,获悉更多
    成功创新者该问的问题
    物联网革命的核心是“网”,而不是“物”
    成功领导力的10大关键
    人们抗拒组织变革的十大原因
    李彦宏:PC时代结束
  • 原文地址:https://www.cnblogs.com/TF12138/p/4107507.html
Copyright © 2011-2022 走看看