Redis学习笔记

工具:

  GUI客户端管理工具 redis-desktop-manager

  用StackExchange.Redis二次封装的组件:依赖组减少,更接近原生redis操作。

  Install-Package StackExchange.Redis

简介

  Redis是一个支持数据结构更多的键值对数据库。不仅支持字符串等基本类型还支持类对象,更可以是Set、List、计数器等高级的数据结构

  Memcached也可以保存类似于Set、List这样结构的数据,但如果要向List中添加元素,则需要把数据全部拿出来,添加数据,保存回去,不仅效率低,而且有并发访问的问题。

  Redis内置的Set、List等可以直接支持添加、删除元素的操作,效率很高,操作是原子性的。

  Memcached是将数据保存在内存中,重启就会消失;Redis会把数据持久化到硬盘中,Redis重启后数据还在。

对比:

 

Redis的优点:

 

    1. 支持 string、list、set、geo 等复杂的数据结构。
    2. 高命中的数据运行时是在内存中,数据最终还是可以保存到磁盘中,这样服务器重启之后数据还在。
    3. 服务器是单线程的,来自所有客户端的所有命令都是串行执行的,因此不用担心并发修改(串行操作当然还是有并发问题)的问题,编程模型简单;
    4. 支持消息订阅/通知机制,可以用作消息队列;
    5.  Key、Value 最大长度允许 512M;

Redis缺点:

    1. Redis 是单线程的,因此单个 Redis 实例只能使用一个 CPU 核,不能充分发挥服务器的性能。可以在一台服务器上运行多个 Redis 实例,不同实例监听不同端口,再互相组成集群
    2. 做缓存性能不如 Memcached

  Memcached的优点:

    1. 多线程,可以充分利用CPU多核的性能。
    2. 做缓存性能最高。

  Memcached的缺点:

    1. .只能保存键值对数据,键值对只能是字符串,如果有对象数据只能自己序列化成 json字符串;
    2. 数据保存在内存中,重启后会丢失;
    3. Key 最大长度 255 个字符,Value 最长 1M。

总结:

  memcached只能当缓存服务器用也最适合。Redis不仅能可以做缓存还可以保存业务数据

.net操作Redis

  Install-Package StackExchange.Redis

  

 1 using StackExchange.Redis;
 2 
 3 private async void button1_Click(object sender, EventArgs e)
 4         {
 5             using (ConnectionMultiplexer redis= ConnectionMultiplexer.Connect("localhost:6379"))
 6             {
 7                 IDatabase db= redis.GetDatabase();
 8                 db.StringSet("name", "cjl");
 9                 await db.StringSetAsync("age", "30");
10             }
11             MessageBox.Show("写入成功");
12         }
13 
14 //支持设置过期时间:db.StringSet("name", "rupeng.com", TimeSpan.FromSeconds(10))
15 //获取数据:string s = db.StringGet("Name")如果查不到则返回 null
View Code

  Redis中所有方法几乎都支持异步

  key-value的参数类型是:RedisKey、RedisValue,这是对string类型进行了重载可以在string和byte[]间的隐式转换

Key操作

  Key 操作:因为 Redis 里所有数据类型都是用 KeyValue 保存,因此 Key 操作针对所有数据类型。

    •   KeyDelete(RedisKey key):根据 Key 删除;
    •   KeyExists(RedisKey key)判断 Key 是否存在,尽量不要用,因为会有并发问题;
    •   KeyExpire(RedisKey key, TimeSpan? expiry)
    •   KeyExpire(RedisKey key, DateTime? expiry)设置过期时间;

数据类型

  Redis 支持的数据结构:string、list、set、sortedset、hash、geo(redis 3.2 以上版本)。

  对应的 Redis 客户端里的方法都是 StringXXX、HashXXX、GeoXXX 等方法。不同数据类型的操作方法不能混用

  比如不能用 ListXXX 写入的值用 StringXXX 去读取或者写入等操作。

string类型  

可以用 StringGet、StringSet 来读写键值对,是基础操作

StringAppend(RedisKey key, RedisValue value):向 Key 的 Value 中附加内容,不存在则新建;

计数器:db.StringIncrement("count", 2.5);给 count 这个计数器增加一个值,如果不存在则从 0 开始加;db.StringDecrement("count",1)计数器减值

获取还是用 StringGet()获取字符串类型的值。

比如:可以用这个来计算新闻点击量、点赞量,效率非常高。

 1 public async Task<ActionResult> Index(int id)
 2         {
 3 //id用于区分不同新闻
 4             using (ConnectionMultiplexer redis=await ConnectionMultiplexer.ConnectAsync("localhost:6379"))
 5             {
 6                 IDatabase db=redis.GetDatabase();
 7 //如果做防恶意点击需要获取用户的IP地址即可
 8                 await db.StringIncrementAsync("News_cc" + id, 1);
 9                 RedisValue cCount= await db.StringGetAsync("News_cc" + id);
10                 NewsModel model = new NewsModel();
11                 model.ClickCount = Convert.ToInt32(cCount);
12                 return View(model);
13             }
14             
15         }
View Code

List类型

Redis 中用 List 保存字符串集合。
比如可以把聊天记录保存到 List 中;商品的物流信息记录。也可以当成双向队列或者双向栈用,list 长度是无限。不用担心左右侧同时使用不够长的问题

1 ListLeftPush(RedisKey key, RedisValue value)//从左侧压栈;
2 RedisValue ListLeftPop(RedisKey key)//从左侧弹出;
3 ListRightPush(RedisKey key, RedisValue value )// 从右侧压栈;RedisValue ListRightPop(RedisKey key) //从右侧弹出;
4 RedisValue ListGetByIndex(RedisKey key, long index)//获取Key为key的List中第index个元素的值;
5 long ListLength(RedisKey key)// 获取 Key 为 key 的 List 中元素个数;尽量不要用 ListGetByIndex、ListLength 因为会有并发问题。
6 //如果是读取而不 Pop,则使用:
7 RedisValue[] ListRange(RedisKey key, long start = 0, long stop = -1)。
8 //不传 start、end 表示获取所有数据。指定之后则获取某个范围。

可以把 Redis 的 list 当成消息队列使用,
比如向注册用户发送欢迎邮件的工作,可以在注册的流程中把要发送邮件的邮箱放到 list 中,另一个程序从 list 中 pop 获取邮件来发送。
生产者、消费者模式。把生产过程和消费过程隔离

网站注册成功发送邮件流程为实例:用户注册成功后,需要向用户发送一个邮件确认注册信息,这个过程中当用户注册成功则向redis中的List存入用户信息,

此时redis所在服务器有另外一个程序在监听(定时任务,windows服务)List中是否有数据,有则pop数据,也就是向用户发送注册信息的过程

Set及SortedSet数据类型

  Set是一种元素不重复的集合

  注意 set 不是按照插入顺序遍历的,而是按照自己的一个存储方式来遍历,因为没有保存插入的顺序。

1 SetAdd(RedisKey key, RedisValue value)//向 set 中增加元素
2 bool SetContains(RedisKey key, RedisValue value)// 判断 set 中是否存在某个元素;
3 long SetLength(RedisKey key) //获得 set 中元素的个数;
4 SetRemove(RedisKey key, RedisValue value)//从 set 中删除元素;
5 RedisValue[] SetMembers(RedisKey key)//获取集合中的元素;
6 //如果使用 set 保存封禁用 id 等,就不用做重复性判断了。

  应用场景:  用户拉黑

SortedSet

  如果对于数据遍历顺序有要求,可以使用 sortedset,他会按照打分来进行遍历。

1 SortedSetAdd(RedisKey key, RedisValue member, double score) //在 key 这个 sortedset 中增加member,并且给这个 member 打分,如果 member 已经存在,则覆盖之前的打分;
2 double SortedSetIncrement(RedisKey key, RedisValue member, double value) //给 key中 member 这一项增加 value 分;
3 double SortedSetDecrement(RedisKey key, RedisValue member, double value)://给 key 中 member 这一项减 value 分;
4 SortedSetEntry[] SortedSetRangeByRankWithScores(RedisKey key, long start = 0, long stop = -1, Order order = Order.Ascending)
// 根据排序返回 sortedset 中的元素以及元素的打分,start、stop 用来分页查询、order 用来指定排序规则。
RedisValue[] SortedSetRangeByRank(RedisKey key, long start = 0, long stop = -1, Order order = Order.Ascending) //根据打分排序返回值,可以根据序号查询其中一部分;
RedisValue[] SortedSetRangeByScore(RedisKey key, double start = double.NegativeInfinity,
   double stop = double.PositiveInfinity, Exclude exclude = Exclude.None, Order order = Order.Ascending, long skip = 0, long take = -1)
// 根据打分排序返回值,可以只返回 start- stop 这个范围的打分;

  sortedSet的应用场景:

用户每搜一次一个关键词,就给这个关键词加一分,展示热搜的时候就把前 N 个获取出来就行了
高积分用户排行榜;
热门商品
给宝宝投票

Hash

  相当于value又是一个键值对集合,或者value是另一个Dictionary

Geo类型

  Geo 是 Redis 3.2 版本后新增的数据类型,用来保存兴趣点(POI,point of interest)的坐标信息。

  可以实现计算两 POI 之间的距离、获取一个点周边指定距离的 POI

//下面添加兴趣点数据,”1”、”2”是点的主键,点的名称、地址、电话等存到其他表中
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); }

Redis的批量操作

如果一次性操作很多,会很慢,那么可以使用批量操作。

① 几乎所有的操作都支持 数组类型,这样就可以一次性操作多条数据: 

  GeoAdd(RedisKey key, GeoEntry[] values);

  SortedSetAdd(RedisKey key, SortedSetEntry[] values);

② 如果一次性的操作不是简单的同类型操作,那么就要使用批量模式:

1 IBatch batch = db.CreateBatch();
2     db.GeoAdd("ShopsGeo1", new GeoEntry(116.34039, 39.94218, "1"));
3     db.StringSet("abc", "123");
4     batch.Execute();

会把当前连接的 CreateBatch()、Execute()之间的操作一次性提交给服务器。

Redis中的分布式锁

类似于sql中的乐观锁;
多线程中的 lock 等的作用范围是当前的程序范围内的,如果想跨多台服务器的锁(尽量避免这样搞),就要使用分布式锁。

 

posted @ 2017-11-08 18:30  大胖儿在努力  阅读(563)  评论(0)    收藏  举报