Redis 介绍学习
1、Redis 简介
Redis 是一个支持数据结构更多的键值对数据库。它的值不仅可以是字符串等基本数据
类型,也可以是类对象,更可以是 Set、List、计数器等高级的数据结构。
Memcached 也可以保存类似于 Set、List 这样的结构,但是如果说要向 List 中增加元素,
Memcached 则需要把 List 全部元素取出来,然后再把元素增加进去,然后再保存回去,不
仅效率低,而且有并发访问问题。
Redis 内置的 Set、List 等可以直接支持增加、删除元素的操作,效率很高,操作是原子的。
Memcached 数据存在内存中,memcached 重启后数据就消失;而 Redis 会把数据持久
化到硬盘中,Redis 重启后数据还存在。
2、Redis 的安装
redis for windows >=2.8 的版本支持直接安装为 windows 服务
https://github.com/MicrosoftArchive/redis
如果下载 msi 自动装完服务,如果下载 zip 需要按照下面的方法安装为服务:
https://raw.githubusercontent.com/MSOpenTech/redis/3.0/Windows%20Service%20Documenta
tion.md
3、redis 的优点:
1) 支持 string、list、set、geo 等复杂的数据结构。
2) 高命中的数据运行时是在内存中,数据最终还是可以保存到磁盘中,这样服务器重启之后数据还在。
3) 服务器是单线程的,来自所有客户端的所有命令都是串行执行的,因此不用担心并发修改(串行操作当然还是有并发问题)的问题,编程模型简单;
4) 支持消息订阅/通知机制,可以用作消息队列;
5) Key、Value 最大长度允许 512M;
4、redis 的缺点:
1) Redis 是单线程的,因此单个 Redis 实例只能使用一个 CPU 核,不能充分发挥服务器的性能。可以在一台服务器上运行多个 Redis 实例,不同实例监听不同端口,再互相组成集群。
2) 做缓存性能不如 Memcached;
5、Memcached 的优点:
1) 多线程,可以充分利用 CPU 多核的性能;
2) 做缓存性能最高;
6、Memcached 的缺点:
1) 只能保存键值对数据,键值对只能是字符串,如果有对象数据只能自己序列化成 json字符串;
2) 数据保存在内存中,重启后会丢失;
3) Key 最大长度 255 个字符,Value 最长 1M。
7、总结
Memcached 只能当缓存服务器用,也是最合适的;Redis 不仅可以做缓存服务器(性能没有 Memcached 好),还可以存储业务数据。
8、redis 命令行管理客户端:
1)直接启动 redis 安装目录下的 redis-cli 即可。不用管恶心的自动提示。
执行 set name yzk,就是设置键值对 name=yzk 执行 get name 就是查找名字是 name 的值; keys *是查找所有的 key key *n*是查找所有名字中含有 n 的 key
2) 和 Redis 一样,Redis 也是不同系统放到 Redis 中的数据都是不隔离的,因此设定 Key 的
时候也要选择好 Key。
3) Redis 服务器默认建了 16 个数据库,Redis 的想法是让大家把不同系统的数据放到不同
的数据库中。但是建议大家不要这样用,因为 Redis 是单线程的,不同业务都放到同一个 Redis
实例的话效率就不高,建议放到不同的实例中。
因此尽量只用默认的 db0数据库命令行下可以用 select0、select1 这样的指令切换数据库,最高为15。试试在不同数据
库下新建、查询数据。
4) 了解的常用的几个命令就可以。所有对数据的操作都可以通过命令行进行,后面讲
的.net 操作 Redis 的驱动其实就是对这些命令的封装。
9、redis GUI 管理客户端
GUI 客户端非常多,个人推荐使用 RedisDesktopManager安装后点击【Connect to Redis Server】连接服务器。展开节点可以看到所有的 Key,双击 Key 可以查看 Key 的值。在根节点上点右键,选择
【Console】,这样就可以输入命令。
10、.net 操作 Redis
用 StackExchange.Redis ,而不是 ServiceStack.Redis,因为 StackExchange.Redis 依赖组件 少,而且操作更接近原生的 redis 操作,ServiceStack 封装的太厉害,而且有过收费的“前科”。
Install-Package StackExchange.Redis
using (ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost:6379"))
{
IDatabase db = redis.GetDatabase();//默认是访问 db0 数据库,可以通过方法参数指定数
字访问不同的数据库
db.StringSet("Name", "abc");
}
支持设置过期时间:db.StringSet("name", "rupeng.com", TimeSpan.FromSeconds(10))
获取数据:string s = db.StringGet("Name")如果查不到则返回 null
Redis 里所有方法几乎都支持异步,比如 StringGetAsync()、StringSetAsync(),尽量用异步方法。
注意看到访问的参数、返回值是 RedisKey、RedisValue 类型,进行了运算符重载,可以和 string、
byte[]之间进行隐式转换。
11、Key 操作
Key 操作:因为 Redis 里所有数据类型都是用 KeyValue 保存,因此 Key 操作针对所有数据类型,
KeyDelete(RedisKey key):根据 Key 删除;KeyExists(RedisKey key)
判断 Key 是否存在,尽量不要用,
因为会有并发问题;KeyExpire(RedisKey key, TimeSpan? expiry)、KeyExpire(RedisKey key, DateTime?
expiry)设置过期时间;
12、数据类型
Redis 支持的数据结构:string、list、set、sortedset、hash、geo(redis 3.2 以上版本)。对应
的 Redis 客户端里的方法都是 StringXXX、HashXXX、GeoXXX 等方法。
不同数据类型的操作方
法不能混用,比如不能用 ListXXX 写入的值用 StringXXX 去读取或者写 入等操作。
13、String 类型
可以用 StringGet、StringSet 来读写键值对,是基础操作StringAppend(RedisKey key, RedisValue value):向 Key 的 Value 中附加内容,不存在则新建;
可以用作计数器:db.StringIncrement("count", 2.5);
给 count 这个计数器增加一个值,如果不存在则从 0 开始加;db.StringDecrement("count",1)计数器减值;获取还是用 StringGet()获取字符串类型的
值。比如可以用这个来计算新闻点击量、点赞量,效率非常高。
private static string XinWen_Prefix = "WWW_XinWen_"; public async Task<ActionResult> Index(int id) {
using (ConnectionMultiplexer redis = await ConnectionMultiplexer.ConnectAsync("localhost:6379")) { IDatabase db = redis.GetDatabase();//默认是访问 db0 数据库,可以通过方法参数指定数字访 问不同的数据库 //以 ip 地址和文章 id 为 key
string hasClickKey = XinWen_Prefix + Request.UserHostAddress + "_" + id; //如果之前这个 ip 给这个文章贡献过点击量,则不重复计算点击量 if(await db.KeyExistsAsync(hasClickKey)==false)
{ await db.StringIncrementAsync(XinWen_Prefix + "XWClickCount" + id, 1); //记录一下这个 ip 给这个文章贡献过点击量,有效期一天 db.StringSet(hasClickKey, "a", TimeSpan.FromDays(1)); } RedisValue clickCount = await db.StringGetAsync(XinWen_Prefix + "XWClickCount" + id); XinWenModel model = new XinWenModel();
model.ClickCount = Convert.ToInt32(clickCount);
return View(model); } return View(); }
14、list 类型
Redis 中用 List 保存字符串集合。 比如可以把聊天记录保存到 List 中;商品的物流信息记录。也 可以当成双向队列或者双向栈用,list 长度是无限。
ListLeftPush(RedisKey key, RedisValue value)从左侧压栈;RedisValue ListLeftPop(RedisKey key) 从左侧弹出;
ListRightPush(RedisKey key, RedisValue value ) 从右侧压栈;RedisValue ListRightPop(RedisKey key) 从右侧弹出;
RedisValue ListGetByIndex(RedisKey key, long index)获取 Key 为 key 的 List 中第 index 个元素的值; long ListLength(RedisKey key) 获取 Key 为 key 的 List 中元素个数;尽量不要用 ListGetByIndex、 ListLength 因为会有并发问题;。
如果是读取而不 Pop,则使用 ListRange:RedisValue[] ListRange(RedisKey key, long start = 0, long stop = -1)。不传 start、end 表示获取所有数据。指定之后则获取某个范围。
可以把 Redis 的 list 当成消息队列使用,比如向注册用户发送欢迎邮件的工作,可以在注册的流 程中把要发送邮件的邮箱放到 list 中,另一个程序从 list 中 pop 获取邮件来发送。
生产者、消费者模式。把生产过程和消费过程隔离。
15、set 类型
如大家所知,set 是一种元素不重复的集合。
SetAdd(RedisKey key, RedisValue value)向 set 中增加元素
bool SetContains(RedisKey key, RedisValue value) 判断 set 中是否存在某个元素;
long SetLength(RedisKey key) 获得 set 中元素的个数;
SetRemove(RedisKey key, RedisValue value)从 set 中删除元素;
RedisValue[] SetMembers(RedisKey key)获取集合中的元素;
如果使用 set 保存封禁用 id 等,就不用做重复性判断了。
注意 set 不是按照插入顺序遍历的,而是按照自己的一个存储方式来遍历,因为没有保存插入的 顺序。
16、sortedset
如果对于数据遍历顺序有要求,可以使用 sortedset,他会按照打分来进行遍历。
SortedSetAdd(RedisKey key, RedisValue member, double score) 在 key 这个 sortedset 中增加member,并且给这个 member 打分,如果 member 已经存在,则覆盖之前的打分; doubleSortedSetIncrement(RedisKeykey,RedisValuemember,doublevalue) 给key中member这一项增加 value 分;
double SortedSetDecrement(RedisKey key, RedisValue member, double value):给 key 中 member 这一项减 value 分;
SortedSetEntry[] SortedSetRangeByRankWithScores(RedisKey key, long start = 0, long stop = -1,Orderorder=Order.Ascending) 根据排序返回sortedset中的元素以及元素的打分,start、stop用来分页
查询、order 用来指定排序规则。
测试:
db.SortedSetIncrement("Hotwords", "test", 1); db.SortedSetIncrement("Hotwords", "test", 1); db.SortedSetIncrement("Hotwords", "test", 1); db.SortedSetIncrement("Hotwords", "杨中科", 1); db.SortedSetIncrement("Hotwords", "侯宝林", 1); db.SortedSetIncrement("Hotwords", "侯宝林", 1);
SortedSetEntry[] items = db.SortedSetRangeByRankWithScores("Hotwords"); foreach(var item in items) {
Console.WriteLine(item.Element+"="+item.Score); }
RedisValue[] SortedSetRangeByRank(RedisKey key, long start = 0, long stop = -1, Order order =Order.Ascending) 根据打分排序返回值,可以根据序号查询其中一部分;
RedisValue[] SortedSetRangeByScore(RedisKey key, double start = double.NegativeInfinity, doublestop = double.PositiveInfinity, Exclude exclude = Exclude.None, Order order = Order.Ascending, long skip = 0, long take = -1)
根据打分排序返回值,可以只返回 start- stop 这个范围的打分;
sortedset 应用场景:
1) 用户每搜一次一个关键词,就给这个关键词加一分;展示热搜的时候就把前 N 个获取出来就行了;
2) 高积分用户排行榜;
3) 热门商品;
4) 给宝宝投票;
17、Hash
相当于 value 又是一个“键值对集合”或者值是另外一个 Dictionary。 没想到有什么应用场景。
18、Geo 类型
Geo 是 Redis 3.2 版本后新增的数据类型,用来保存兴趣点(POI,point of interest)的坐标信息。
可以实现计算两 POI 之间的距离、获取一个点周边指定距离的 POI。 下面添加兴趣点数据,”1”、”2”是点的主键,点的名称、地址、电话等存到其他表中。
db.GeoAdd("ShopsGeo", new GeoEntry(116.34039, 39.94218,"1"));
db.GeoAdd("ShopsGeo", new GeoEntry(116.340934, 39.942221, "2"));
db.GeoAdd("ShopsGeo", new GeoEntry(116.341082, 39.941025, "3"));
db.GeoAdd("ShopsGeo", new GeoEntry(116.340848, 39.937758, "4"));
db.GeoAdd("ShopsGeo", new GeoEntry(116.342982, 39.937325, "5"));
db.GeoAdd("ShopsGeo", new GeoEntry(116.340866, 39.936827, "6"));
GeoRemove(RedisKey key, RedisValue member)删除一个点
查询两个 POI 之间的举例:double? dist = db.GeoDistance("ShopsGeo", "1", "5", GeoUnit.Meters);// 最后一个参数为距离单位根据点的主键获取坐标:GeoPosition? pos = db.GeoPosition("ShopsGeo", "1")
获取一个 POI 周边的 POI:
GeoRadiusResult[] results = db.GeoRadius("ShopsGeo", "2", 200, GeoUnit.Meters);//获取”2”这个周边 200 米范围内的 POI
foreach(GeoRadiusResult result in results)
{ Console.WriteLine("Id="+result.Member+",位置"+result.Position+",距离"+result.Distance); }
获取一个坐标(这个坐标不一定是 POI)周边的 POI:
GeoRadiusResult[] results = db.GeoRadius("ShopsGeo", 116.34092, 39.94223, 200, GeoUnit.Meters);// 获 取(116.34092, 39.94223)这个周边 200 米范围内的 POI
foreach(GeoRadiusResult result in results)
{ Console.WriteLine("Id="+result.Member+",位置"+result.Position+",距离"+result.Distance); }
Geo Hash 原理:http://www.cnblogs.com/LBSer/p/3310455.html
19、Redis 的批量操作
如果一次性操作很多,会很慢,那么可以使用批量操作,两种方式: 1)几乎所有的操作都支持数组类型,这样就可以一次性操作多条数据:比如
GeoAdd(RedisKey key, GeoEntry[] values)、SortedSetAdd(RedisKey key, SortedSetEntry[] values) 2) 如果一次性的操作不是简单的同类型操作,那么就要使用批量模式:
IBatch batch = db.CreateBatch();
db.GeoAdd("ShopsGeo1", new GeoEntry(116.34039, 39.94218, "1"));
db.StringSet("abc", "123");
batch.Execute();
会把当前连接的 CreateBatch()、Execute()之间的操作一次性提交给服务器。
20、redis 分布式锁
多线程中的 lock 等的作用范围是当前的程序范围内的,如果想跨多台服务器的锁(尽量避免这样搞),就要使用分布式锁。
RedisValue token = Environment.MachineName; //实际项目秒杀此处可换成商品 ID if (db.LockTake("mylock", token, TimeSpan.FromSeconds(10)))//第三个参数为锁超时时间,锁占 用最多 10 秒钟,超过 10 秒钟如果还没有 LockRelease,则也自动释放锁,避免了死锁
{ try { } finally { db.LockRelease("mylock", token); } } else { Console.WriteLine("获得锁失败");
}
Redis 介绍学习的更多相关文章
- Redis 介绍与使用
数据库主要类型有对象数据库,关系数据库,键值数据库等等,对象数据库太超前了,现阶段不提也罢:关系数据库就是平常说的MySQL,PostgreSQL这些熟的不能再熟的东西,至于键值数据库则是本文要着重说 ...
- 基于Python操作redis介绍
(注:本文部分内容摘自互联网,由于作者水平有限,不足之处,还望留言指正.) 毕业前的最后一个学期(2016.03),龙哥结婚了.可是总有些人喜欢嘲笑别人,调侃我.当时我就理直气壮的告诉他们,等龙哥孩子 ...
- 反射实现Model修改前后的内容对比 【API调用】腾讯云短信 Windows操作系统下Redis服务安装图文详解 Redis入门学习
反射实现Model修改前后的内容对比 在开发过程中,我们会遇到这样一个问题,编辑了一个对象之后,我们想要把这个对象修改了哪些内容保存下来,以便将来查看和追责. 首先我们要创建一个User类 1 p ...
- Redis介绍、安装部署、操作
学习连接:http://www.runoob.com/redis/redis-tutorial.html 一.Redis介绍 Redis是NoSql的一种. NoSql,全名:Not Only Sql ...
- Redis入门学习(学习过程记录)
Redis(入门笔记) 学习一个大的技术点,然后顺带着就把这个技术点的面试题给学习了. 学习完一个技术后,如果面试题还不能够解答的话,只能说明学的不精,需要查漏补缺. 下一个学习的方向:Redis-非 ...
- Redis安全学习
Redis安全学习 一直在听SSRF打Redis,那Redis到底是啥,正式的认真学习一下. 1.Redis是什么 REmote DIctionary Server(Redis) 是一个由Salvat ...
- Redis in Action : Redis 实战学习笔记
1 1 1 Redis in Action : Redis 实战学习笔记 1 http://redis.io/ https://github.com/antirez/redis https://ww ...
- memcache/redis 缓存学习笔记
0.redis和memcache的区别 a.redis可以存储除了string之外的对象,如list,hash等 b.服务器宕机以后,redis会把内存的数据持久化到磁盘上,而memcache则不会 ...
- Redis介绍以及安装(Linux)
Redis介绍以及安装(Linux) redis是当前比较热门的NOSQL系统之一,它是一个key-value存储系统.和Memcached类似,但很大程度补偿了memcached的不足,它支持存储的 ...
随机推荐
- Python作业本——第4章 列表
课后习题: 1.[]是一个空列表 2. spam.insert(3, 'hello') 错,应为:spam[2] = 'hello' 3.['d'] 'd' 4.['d'] 'd' 5.[ ...
- 解决go get下载包失败问题
由于某些不可抗力的原因,国内使用go get命令安装包时会经常会出现timeout的问题.本文介绍几个常用的解决办法. 从github克隆 golang在github上建立了一个镜像库,如https: ...
- ConcurrentHashMap 的工作原理及代码实现
ConcurrentHashMap采用了非常精妙的"分段锁"策略,ConcurrentHashMap的主干是个Segment数组.Segment继承了ReentrantLock,所 ...
- dubbo 的 spi 思想是什么?
面试题 dubbo 的 spi 思想是什么? 面试官心理分析 继续深入问呗,前面一些基础性的东西问完了,确定你应该都 ok,了解 dubbo 的一些基本东西,那么问个稍微难一点点的问题,就是 spi, ...
- SpringCloud学习笔记(4):Hystrix容错机制
简介 在微服务架构中,微服务之间的依赖关系错综复杂,难免的某些服务会出现故障,导致服务调用方出现远程调度的线程阻塞.在高负载的场景下,如果不做任何处理,可能会引起级联故障,导致服务调用方的资源耗尽甚至 ...
- HBase的表结构
HBase以表的形式存储数据.表有行和列组成.列划分为若干个列族/列簇(column family). 如上图所示,key1,key2,key3是三条记录的唯一的row key值,column-fa ...
- Android Studio [页面的跳转和传值]
AActivity.java package com.xdw.a122.jump; import android.app.Activity; import android.content.Compon ...
- 【Django】中间件,csrf,缓存,信号
中间件(middleware) 描述:Middlewares 是修改 Django request 或者 response 对象的钩子. 在django中,中间件其实就是一个类,在请求到来和结束后,d ...
- Python学习笔记整理总结【MySQL】
一. 数据库介绍 1.什么是数据库?数据库(Database)是按照数据结构来组织.存储和管理数据的仓库.每个数据库都有一个或多个不同的API用于创建,访问,管理,搜索和复制所保存的数据.我们也可以将 ...
- Spring 梳理 - @Autowired VS @Resource
Autowired @Autowired顾名思义,就是自动装配,其作用是为了消除代码Java代码里面的getter/setter与bean属性中的property.当然,getter看个人需求,如果私 ...