Redis到底该如何利用?【转自:http://www.cnblogs.com/capqueen/p/HowToUseRedis.html】

news/2025/5/22 1:19:05

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/

转载于:https://www.cnblogs.com/TF12138/p/4107507.html

文章来源:https://blog.csdn.net/weixin_30905133/article/details/94999809
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:https://dhexx.cn/news/show-17927.html

相关文章

Java基础之伪泛型和类型擦除

Java基础之伪泛型和类型擦除一、理解1、泛型的类型擦除原则2、无限制类型擦除3、有限制类型擦除4、擦除方法定义中的类型参数二、类型擦除1、原始类型相等2、通过反射添加其它类型元素3、类型擦除后保留的原始类型4、举例一、理解 1、泛型的类型擦除原则 消除类型参数声明&am…

数据结构实验之链表七:单链表中重复元素的删除

数据结构实验之链表七&#xff1a;单链表中重复元素的删除 Time Limit: 1000MS Memory limit: 65536K 题目描述 按照数据输入的相反顺序&#xff08;逆位序&#xff09;建立一个单链表&#xff0c;并将单链表中重复的元素删除&#xff08;值相同的元素只保留最后输入的一个&…

21-栈(基于数组实现)

目录 1.概念 2.应用 ①函数调用栈 ②浏览器的返回 ③编辑器的撤销ctrl Z ④编辑器的括号匹配 ⑤算术运算的符号优先级匹配 ⑥箱子 3.核心操作 ①pop()&#xff1a;移除栈顶元素&#xff08;出栈&#xff09; ②peek()&#xff1a;查看栈顶元素但不删除 ③push()&a…

Java基础之如何理解泛型的编译期检查

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录一、编译期检查二、泛型的桥接一、编译期检查 public class Test { public static void main(String[] args) { ArrayList<String> list1 new ArrayList()…

Phoenix使用SALT_BUCKETS创建预分区表

1. 基础知识 Phoenix Salted Table是phoenix为了防止hbase表rowkey设计为自增序列而引发热点region读和热点region写而采取的一种表设计手段。通过在创建表的时候指定SALT_BUCKETS来实现pre-split(预分割)。如下表示创建表的时候将表预分割到6个region里面。 默认情况下&…

ERPCore实现原理(二)

程序初始化后&#xff0c;就创建主窗体 procedure TMain.FormCreate(Sender: TObject); beginTObjFactoryEx.Create([IMainForm,IFormMgr],self);SetSysSkin(dxSkinController);if not LoadSysModule then exit;LoadUserModule;if not Sys.Login.Login thenbeginApplication.Sh…

Java基础之SPI机制

Java基础之SPI机制一、SPI机制的简单示例1、案例分层2、接口3、实现类4、测试类5、结果二、SPI机制的缺陷一、SPI机制的简单示例 1、案例分层 resources 接下来可以在resources下新建META-INF/services/目录&#xff0c;然后新建接口全限定名的文件&#xff1a;com.example.d…

phoenix 创建 Pre-split(预分区)表

当可以提前知道 row key 的分布的时候&#xff0c;可以指定每个预分区的 region 的分割点&#xff0c;上面命令创建的表中&#xff0c;有 5 个 Region create table testlocal (id integer primary key, name varchar, age integer, address varchar) split on (10, 20, 30, …

varargin

matlab中varargin可以看做“Variable length input argument list”的缩写。在matlab中, varargin提供了一种函数可变参数列表机制。 就是说&#xff0c; 使用了“可变参数列表机制”的函数允许调用者调用该函数时根据需要来改变输入参数的个数。【功能描述】返回函数输入参数列…

菜根谭#235

宾朋云集&#xff0c;剧饮淋漓乐矣&#xff0c;俄而漏尽烛残香销茗冷&#xff0c;不觉反成呕咽&#xff0c;令人索然无味。天下事率类此&#xff0c;奈何不早回头也。转载于:https://www.cnblogs.com/star4knight/p/4109707.html