.Net Core使用分布式缓存Redis:数据结构
一、前言
本篇主要使用StackExchangeRedis在.Net Core中使用Redis,使用基础见:点击此处。
二、五种基础数据结构
1.字符串类型String
字符串类型是Redis中最基本的数据类型,它能存储任何形式的字符串,包括二进制数据。你可以用其存储用户的邮箱、JSON化的对象甚至是一张图片。一个字符串类型键允许存储地得数据的最大容量是512MB。
字符串类型是其他4种数据类型的基础,其他数据类型和字符串类型的差别从某种角度来说只是组织字符串的形式不同。例如,列表类型是以列表的形式组织字符串,二集合类型是以集合的形式组织字符串。
以下为StackExchangeRedis中字符串常用方法及其命令:
(1)赋值与取值
- //方法
- redisConnection.GetDatabase().StringSetAsync(key, value);
- redisConnection.GetDatabase().StringGetAsync(key);
- //命令
- 127.0.0.1:> set stringKey stringValue
- OK
- 127.0.0.1:> get stringKey
- "stringValue"
(2)返回 key 中字符串值的子字符
- //方法
- redisConnection.GetDatabase().StringGetRangeAsync(key, start, end);
- //命令
- 127.0.0.1:> getrange stringKey
- "Value"
(3)将给定 key 的值设为 value ,并返回 key 的旧值(old value)
- //方法
- var oldvalue = await redisConnection.GetDatabase().StringGetSetAsync(key, oldkey);
- //命令
- 127.0.0.1:> getset stringKey newValue
- "stringValue"
(4)如果 key 已经存在并且是一个字符串, APPEND 命令将指定的 value 追加到该 key 原来值(value)的末尾
- //方法
- redisConnection.GetDatabase().StringAppendAsync(key, appendValue);
- //命令
- 127.0.0.1:> append stringKey append
- (integer)
2.散列类型Hash
Redis是采用字典结构以键值对的形式存储数据的,而Hash的键值也是一种字典结构,其存储了字段(field)和字段值的映射,但字段值只能是字符串,不支持其他数据类型,不能嵌套其他数据类型(其他数据类型同理)。
散列类型适合存储对象:使用对象类别和ID构成键名,使用字段表示对象的属性,而字段值则存储属性值。例如要存储ID为2的汽车对象,可以分别使用名为color、name和price的三个字段来存储该辆汽车的颜色、名称和价格。
以下为StackExchangeRedis中散列类型常用方法及其命令:
(1)赋值
- //方法
- HashEntry[] hashEntry = new HashEntry[] {
- new HashEntry("id",),
- new HashEntry("color","red"),
- new HashEntry("price",),
- };
- redisConnection.GetDatabase().HashSetAsync("youCar", hashEntry);
- //命令
- 127.0.0.1:> hset myCar price
- (integer)
- 127.0.0.1:> hset mCar color blue
- (integer)
- 127.0.0.1:> hset mCar name tractor
- (integer)
(2)取值
- //方法
- redisConnection.GetDatabase().HashGetAsync("youCar", "color");
- redisConnection.GetDatabase().HashGetAllAsync("youCar");
- //命令
- 127.0.0.1:> hget youCar color
- "red"
- 127.0.0.1:> hgetall youCar
- ) "id"
- ) ""
- ) "color"
- ) "red"
- ) "price"
- ) ""
(3)获取所有散列类型中的字段
- //方法
- var keys = redisConnection.GetDatabase().HashKeys("youCar");
- //命令
- 127.0.0.1:> hkeys youCar
- ) "id"
- ) "color"
- ) "price"
3.列表List
列表类型(List)可以存储一个有序的字符串列表,常用的操作是向列表两端添加元素,或者获得列表的一个片段。
列表类型内部是使用双向链表(double linked list)实现的,所以向列表两段添加元素的时间复杂都为O(1),获取越接近两端的元素速度就越快。这意味着即使是一个由几千万个元素的列表,获取头部或者尾部的10条记录也是极快的。
不过使用链表的代价是通过索引访问元素比较慢。于是,列表类型很适合于如社交网站的新鲜事、记录日志、消息队列等,类似获取最前几条的数据、从列表尾部插入等场景。
以下为StackExchangeRedis中列表类型常用方法及其命令:
(1)向列表两端增加元素
- //方法
- redisConnection.GetDatabase().ListLeftPushAsync("myList","head1");
- redisConnection.GetDatabase().ListRightPush("myList","bottom1");
- //命令
- 127.0.0.1:> lpush myList head1
- (integer) 127.0.0.1:> rpush myList bottom1
- (integer)
(2)从列表两端移除并获取一个元素
- //方法
- var value = redisConnection.GetDatabase().ListLeftPopAsync("myList");
- var value = redisConnection.GetDatabase().ListRightPopAsync("myList");
- //命令
- 127.0.0.1:> lpop myList
- "head1"
- 127.0.0.1:> rpop myList
- "bottom1"
- 127.0.0.1:> rpop myList
- (nil)
(3)获取列表中的元素片段(不删除只获取)
- //方法
- var value = redisConnection.GetDatabase().ListRangeAsync("myList",,);
- //命令
- 127.0.0.1:> lrange myList
- ) ""
- ) ""
- ) ""
4.集合Set
Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。常用的操作是向集合加入或者删除元素、判断某个元素是否存在等,由于Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
最方便的是多个集合类型键之间还可以进行并集、交集和差集运算。
可以运用在共同好友、喜好和好友推荐(交集超过阈值)等可以运用交差并集操作的场景。
以下为StackExchangeRedis中集合类型常用方法及其命令:
(1)增加/删除元素(可多个,相同元素自动忽略)
- //方法
- redisConnection.GetDatabase().SetAddAsync("mySet", new RedisValue[] { "a", "b" });
- redisConnection.GetDatabase().SetRemoveAsync("mySet", "a");
- //命令
- 127.0.0.1:> sadd mySet a
- (integer)
- 127.0.0.1:> sadd mySet a b c
- (integer)
- 127.0.0.1:> srem mySet c
- (integer)
- 127.0.0.1:> srem mySet b a
- (integer)
(2)获取交集
- //方法
- var value = redisConnection.GetDatabase().SetCombine(SetOperation.Intersect, "mySet1", "mySet2");
- //命令
- 127.0.0.1:> sadd mySet1 a b c
- (integer)
- 127.0.0.1:> sadd mySet2 b c d
- (integer)
- 127.0.0.1:> sinter mySet1 mySet2
- ) "c"
- ) "b"
5.有序集合Sort Set
从有序集合的名字就可以看出它和集合的区别就是”有序“二字。
在集合类型的基础尚有序集合类型为集合中的每个元素都关联了一个分数,按分数大小进行从小到大的排序,这使得我们不仅可以完成插入、删除和判断元素是否在等集合类型支持的操作,还能够获得分数最高(或最低)的前N个元素、获得指定分数范围内的元素等与分数有关的操作。虽然集合中每个元素都是不同的,但是它们的分数却可以相同。
有序集合类型在某方面和列表类型有些相似
二者都是有序。
二者都可以获取某一范围的元素
但是二者由这很大的区别,这使得他们的应用场景有所不同。
列表是通过链表实现的,获取靠近两端的数据速度极快,而当元素增多后,访问中间元素的速度会较慢,所以它更加适合实现如“新鲜事”或“日志”这样很少访问中间元素的应用。
有序集合是使用散列表和跳表(skip list)实现的,所以即使读取文娱中间部分的数据速度也快(时间复杂度是O(log(N)))。
列表中不能简单地调整元素的位置,但有序集合可以(通过更改元素的分数),所以可以用于排行榜、权重应用(有权重的消息队列)。
有序集合要比类别更耗内存。
以下为StackExchangeRedis中有序集合类型常用方法及其命令:
(1)增加元素
- //方法
- SortedSetEntry[] sortedSetEntry = new SortedSetEntry[] {
- new SortedSetEntry("tom",),
- new SortedSetEntry("peter",),
- new SortedSetEntry("david",),
- };
- redisConnection.GetDatabase().SortedSetAddAsync("mySs", sortedSetEntry);
- //命令
- 127.0.0.1:> zadd mySs tom peter david
- (integer)
(2)获取排名在某个分数范围的元素列表
- //方法
- var value = redisConnection.GetDatabase().SortedSetRemoveRangeByScoreAsync("mySs", , );
- //命令
- 127.0.0.1:> zrangebyscore mySs
- ) "tom"
- ) "peter"
(3)增加某个元素的分数
- //方法
- var sorce = redisConnection.GetDatabase().SortedSetIncrementAsync("mySs", "top", );
- //命令
- 127.0.0.1:> zincrby mySs tom
- ""
6.小结
上面各类型所举得例子有限,基本所有的Redis命令在StackExchangeRedis中都有相应的异步和同步的方法,大家可以参考https://redis.io/commands。
三、其他数据结构
1.HyperLogLog
Redis 在 2.8.9 版本添加了 HyperLogLog 结构(其本身也是一种算法)。
Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。
在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。
但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。
所以主要应用于:
统计访问IP数量;
统计搜索关键词数量;
统计用户在线数;
等等大数量统计。
以下为StackExchangeRedis中常用方法及其命令:
(1)添加指定元素到 HyperLogLog 中
- //方法
- RedisValue[] redisValue = new RedisValue[] {
- ,,,
- };
- redisConnection.GetDatabase().HyperLogLogAddAsync("key", redisValue);
- //命令
- 127.0.0.1:> pfadd hyperlogKy
- (integer)
(2)返回给定 HyperLogLog 的基数估算值。
- //方法
- var count = redisConnection.GetDatabase().HyperLogLogLength("key");
- //命令
- 127.0.0.1:> pfcount hyperlogKy
- (integer)
2.geo
Redis在3.2版本之后新增了一个geo(地理位置),其数据结构为有序集合sort set。
geo可以将地理位置信息(经纬度)储存起来,并计算两个地理坐标之间的位置、返回以指定位置为圆心指定半径内的所有地理位置信息等。
像是我们平时的打车、租房地图等功能中就可以用到。
既然前面说到geo是有序集合那它的score怎么来?是我们自己输入嘛?其实是通过我们存储的经纬度通过geohash计算后的base32编码字符串。geohash原理点击此处。
以下为StackExchangeRedis中常用方法及其命令:
(1)添加地理位置
- //方法
- GeoEntry[] geoEntry = new GeoEntry[] {
- new GeoEntry(120.20000, 30.26667, "hangzhou"),
- new GeoEntry(116.41667, 39.91667, "beijing"),
- new GeoEntry(121.47, 31.23, "shanghai"),
- };
- redisConnection.GetDatabase().GeoAdd("city", geoEntry);
- //命令
- 127.0.0.1:> geoadd city 120.20000 30.26667 hangzhou 116.41667 39.91667 beijing 121.47 31.23 shanghai
- (integer)
(2)获取geohash
- //方法
- var geohash = redisConnection.GetDatabase().GeoHash("city", "hanghzou");
- //命令
- 127.0.0.1:> geohash city hangzhou
- ) "wtmkpjyuph0"
(3)获取指定元素范围的地理信息位置集合
- //方法
- var geo = redisConnection.GetDatabase().GeoRadius("city", "hanghzou", , GeoUnit.Kilometers, , Order.Ascending, GeoRadiusOptions.WithGeoHash);
- //命令
- 127.0.0.1:> georadiusbymember city hangzhou km withcoord withdist withhash asc count
- ) ) "hangzhou"
- ) "0.0000"
- ) (integer)
- ) ) "120.20000249147415"
- ) "30.266670658987586"
- ) ) "shanghai"
- ) "161.9183"
- ) (integer)
- ) ) "121.47000163793564"
- ) "31.229999039757836"
在给定以下可选项时, 命令会返回额外的信息:
WITHDIST : 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。
WITHCOORD : 将位置元素的经度和维度也一并返回。
WITHHASH : 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。
ASC : 根据中心的位置, 按照从近到远的方式返回位置元素。DESC : 根据中心的位置, 按照从远到近的方式返回位置元素。
它还有个类似的georadius命令,区别是由给定的经纬度为圆心。
(4)计算两个位置之间的距离
- //方法
- var geo = redisConnection.GetDatabase().GeoDistance("city", "hanghzou","beijing");
- //命令
- 127.0.0.1:> geodist city hangzhou beijing km
- "1126.8937"
3.发布订阅pub/sub
"发布/订阅"模式中包含两种角色,分别是发布者和订阅者。订阅者可以订阅一个或者若干个频道(channel),而发布者可以向指定的频道发送消息,所有订阅此频道的订阅者都会收到此消息。
发布者通过publish命令发送消息:
- //命令
- 127.0.0.1:> publish channel_1 hi
- (integer)
- //方法
- var count = redisConnection.GetSubscriber().Publish("channel_1", "hi");
消息是发送出去了,publish命令的返回值表示接收到这条消息的订阅者数量。因为当前没有订阅这订阅这个频道,所以返回0。
注意,发送出去的消息是不会持久化的,订阅者只能收到订阅之后发布者发送的消息。
订阅者通过subscribe命令订阅一个或者多个频道:
- //命令
- 127.0.0.1:> subscribe channel_1 channel_2
- Reading messages... (press Ctrl-C to quit)
- ) "subscribe"
- ) "channel_1"
- ) (integer)
- ) "subscribe"
- ) "channel_2"
- ) (integer)
- ) "message"
- ) "channel_1"
- ) "hi"
- //方法
- while (true)
- {
- redisConnection.GetSubscriber().Subscribe("channel_1", (channel, message) =>
- {
- var msg = message;//收到的消息
- var chan = channel;//频道名称
- });
- }
执行subscribe命令之后进入订阅状态,可能收到三种类型的回复。每种类型的回复都包含三个值,第一个值是消息的类型,根据消息类型的不同,第二、三个值得含义也不同。消息类型可能得取值有以下三个:
subscribe:表示订阅成功得反馈信息。第二个值是订阅成功得频道名称,第三个值是当前客户端订阅得频道数量。
message:这个类型得回复是我们最关心得,它表示接收到得消息。第二个值表示禅师消息的频道名称,第三个值是消息的内容。
unsubscribe:表示成功取消订阅某个频道。第二个值是对应频道的名称,第三个值是当前客户端订阅的频道数量。
StackExchangeRedis中用到message和unsubscribe这两种。
除了通过频道名之外,还可以使用psubscribe命令通过规则订阅频道。如约定规则为channel_?*则可以匹配channel_为开头的频道,如channel_1、channel_2等。
- //命令
- 127.0.0.1:> psubscribe cahnnel_?*
- Reading messages... (press Ctrl-C to quit)
- (integer)
- ) "psubscribe"
- ) "cahnnel_?*"
- ) (integer)
- //方法
- while (true)
- {
- redisConnection.GetSubscriber().Subscribe("channel_?*", (channel, message) =>
- {
- var msg = message;//收到的消息
- var chan = channel;//频道名称
- });
- }
解除订阅通过命令unsubscribe,如果不指定频道则取消全部订阅。在StackExchangeRedis中分别时方法Unsubscribe()和UnsubscribeAll()。
.Net Core使用分布式缓存Redis:数据结构的更多相关文章
- ASP.Net Core使用分布式缓存Redis从入门到实战演练
一.课程介绍 人生苦短,我用.NET Core!缓存在很多情况下需要用到,合理利用缓存可以一方面可以提高程序的响应速度,同时可以减少对特定资源访问的压力. 所以经常要用到且不会频繁改变且被用户共享的 ...
- .Net Core使用分布式缓存Redis:基础
一.前言 Redis的介绍网上很多不再赘述.本次环境为net core 2.2,使用的StackExchange.Redis来操作Redis. 二.引用Microsoft.Extensions.Cac ...
- .Net Core使用分布式缓存Redis:Lua脚本
一.前言 运行环境window,redis版本3.2.1.此处暂不对Lua进行详细讲解,只从Redis的方面讲解. 二.Redis的Lua脚本 在Redis的2.6版本推出了脚本功能,允许开发者使用L ...
- 一个技术汪的开源梦 —— 公共组件缓存之分布式缓存 Redis 实现篇
Redis 安装 & 配置 本测试环境将在 CentOS 7 x64 上安装最新版本的 Redis. 1. 运行以下命令安装 Redis $ wget http://download.redi ...
- 企业项目开发--分布式缓存Redis
第九章 企业项目开发--分布式缓存Redis(1) 注意:本章代码将会建立在上一章的代码基础上,上一章链接<第八章 企业项目开发--分布式缓存memcached> 1.为什么用Redis ...
- .NET分布式缓存Redis从入门到实战
一.课程介绍 今天阿笨给大家带来一堂NOSQL的课程,本期的主角是Redis.希望大家学完本次分享课程后对redis有一个基本的了解和认识,并且熟悉和掌握 Redis在.NET中的使用. 本次分享课程 ...
- 第十章 企业项目开发--分布式缓存Redis(2)
注意:本章代码是在上一章的基础上进行添加修改,上一章链接<第九章 企业项目开发--分布式缓存Redis(1)> 上一章说了ShardedJedisPool的创建过程,以及redis五种数据 ...
- 【开源项目系列】如何基于 Spring Cache 实现多级缓存(同时整合本地缓存 Ehcache 和分布式缓存 Redis)
一.缓存 当系统的并发量上来了,如果我们频繁地去访问数据库,那么会使数据库的压力不断增大,在高峰时甚至可以出现数据库崩溃的现象.所以一般我们会使用缓存来解决这个数据库并发访问问题,用户访问进来,会先从 ...
- 三点须知:当我们在开发过程中需要用到分布式缓存Redis的时候
当我们在开发过程中需要用到分布式缓存Redis的时候,我们首先要明白缓存在系统中用来做什么? 1. 少量数据存储,高速读写访问.通过数据全部in-momery 的方式来保证高速访问,同时提供数据落地的 ...
随机推荐
- springcloud微服务基于redis集群的单点登录
springcloud微服务基于redis集群的单点登录 yls 2019-9-23 简介 本文介绍微服务架构中如何实现单点登录功能 创建三个服务: 操作redis集群的服务,用于多个服务之间共享数据 ...
- thinkphp两表,多表联合查询及分页的连贯操作写法
ThinkPHP中关联查询(即多表联合查询)可以使用 table() 方法或和join方法,具体使用如下例所示: 1.原生查询示例: 代码如下: $Model = new Model(); $sql ...
- mysql中int、bigint、smallint、tinyint 长度
mysql中int.bigint.smallint.tinyint 长度 bigint -2^63 (-9223372036854775808) 到 2^63-1 (92233720368547758 ...
- Easy 2048 Again(状压dp)
题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3802 题意: 从数列A中, 删除若干个数(可以0个), 是删除 ...
- Pashmak and Buses(构造)
题目链接:http://codeforces.com/problemset/problem/459/C 题意:n个人, k辆车, d天,每天将所有 任意人安排到k辆车, 问怎样安排, 可时不存在 2人 ...
- 利用Python学习线性代数 -- 1.1 线性方程组
利用Python学习线性代数 -- 1.1 线性方程组 本节实现的主要功能函数,在源码文件linear_system中,后续章节将作为基本功能调用. 线性方程 线性方程组由一个或多个线性方程组成,如 ...
- fastjson 1.2.24反序列化导致任意命令执行漏洞分析记录
环境搭建: 漏洞影响版本: fastjson在1.2.24以及之前版本存在远程代码执行高危安全漏洞 环境地址: https://github.com/vulhub/vulhub/tree/master ...
- 理解Redis持久化
本文首发于:https://mp.weixin.qq.com/s/WVUGWuNrGoyY_7aDf7NNmA 微信公众号:后端技术指南针 0.前言 通俗讲持久化就是将内存中的数据写入非易失介质中,比 ...
- python容器类型元组的操作
元组:使用小括号进行表示一组元素,其元素与元素之间使用逗号隔开:注意:元组的的值是不可修改的: 1.元组值得增加:元组是不可以直接增加值的,但是可以通过+进行拼接 # 声明一个元组: tuple1 = ...
- Alibaba Nacos 学习(二):Spring Cloud Nacos Config
Alibaba Nacos 学习(一):Nacos介绍与安装 Alibaba Nacos 学习(二):Spring Cloud Nacos Config Alibaba Nacos 学习(三):Spr ...