1.组件概况
组件名称:Redis
功能介绍:
Redis是一种面向“键/值”对类型数据的分布式NoSQL数据库系统,特点是高性能,
持久存储,适应高并发的应用场景。
Redis优势:
1). 和其他NoSQL产品相比,Redis的易用性极高,因此对于那些有类似产品使用经验的开发者来说,一两天,
甚至是几个小时之后就可以利用Redis来搭建自己的平台了。
2). 在解决了很多通用性问题的同时,也为一些个性化问题提供了相关的解决方案,
如索引引擎、统计排名、消息队列服务等。
预期读者:需要接入此组件的研发人员
2.Redis组件接入指南
2.1使用提醒
2.1检查环境
本组件是按.NET Framework 4.0 开发的
2.2接入准备
使用公司内部的NuGet安装所需要的类库TCBase.RedisClient
(详细步骤请参考:使用手册.公司内部NuGet)
2.3使用范例
Redis支持的各种数据类型包括string,list ,set ,sorted set 和hash
2.3.1>.Redis hash:
redis的hash类型是一个string类型的field和value的映射表.它的添加,删除操作都是O(1)(平均).
hash特别适合用于存储对象。相较于将对象的每个字段存成单个string类型。将一个对象存储
在hash类型中会占用更少的内存,并且可以更方便的存取整个对象。尽管zipmap的添加,
删除,查找都是O(n),但是由于一般对象的field数量都不太多。所以使用zipmap也是很快的,也就是说添加
删除平均还是O(1)。如果field或者value的大小超出一定限制后,redis会在内部自动将zipmap替换成正常的
hash实现. 这个限制可以在配置文件中指定
下面介绍RedisClient的hash相关方法:
1.设置hash field为指定值,如果key不存在,则先创建
Task<bool> Set(int db, string key, string field, byte[] value, bool queueJump = false);
Task<bool> Set(int db, string key, string field, string value, bool queueJump = false);
2.hmset key filed1 value1 ... filedN valueN 同时设置hash的多个field
Task Set(int db, string key, Dictionary<string, byte[]> values, bool queueJump = false);
3.hget key field 获取指定的hash field
Task<byte[]> Get(int db, string key, string field, bool queueJump = false); Task<byte[][]> Get(int db, string key, string[] fields, bool queueJump = false);
4.hmget key filed1....fieldN 获取全部指定的hash filed
Task<Dictionary<string, byte[]>> GetAll(int db, string key, bool queueJump = false);
5.hincrby key field integer 将指定的hash filed 加上给定值
Task<long> Increment(int db, string key, string field, int value = 1, bool
queueJump = false);
Task<double> Increment(int db, string key, string field, double value, bool
queueJump = false);
6.hexists key field 测试指定field是否存在
Task<bool> Exists(int db, string key, string field, bool queueJump = false);
7.hdel key field 删除指定的hash field
Task<bool> Remove(int db, string key, string field, bool queueJump = false); Task<long> Remove(int db, string key, string[] fields, bool queueJump = false);
8.hlen key 返回指定hash的field数量
Task<long> GetLength(int db, string key, bool queueJump = false);
9.hkeys key 返回hash的所有field
Task<string[]> GetKeys(int db, string key, bool queueJump = false);
10.hvals key 返回hash的所有value
Task<byte[][]> GetValues(int db, string key, bool queueJump = false);
11.hgetall 返回hash的所有filed和value
2.3.2>Redis list:
redis的list类型其实就是一个每个子元素都是string类型的双向链表。所以[lr]push和[lr]pop命令的算法
时间复杂度都是O(1),另外list会记录链表的长度。所以llen操作也是O(1).链表的最大长度是(2的32次方
-1)。我们可以通过push,pop操作从链表的头部或者尾部添加删除元素。这使得list既可以用作栈,也可
以用作队列。有意思的是list的pop操作还有阻塞版本的。当我们[lr]pop一个list对象是,如果list是空,或
者不存在,会立即返回nil。但是阻塞版本的b[lr]pop可以则可以阻塞,当然可以加超时时间,超时后也会
返回nil。为什么要阻塞版本的pop呢,主要是为了避免轮询。举个简单的例子如果我们用list来实现一个工
作队列。执行任务的thread可以调用阻塞版本的pop去获取任务这样就可以避免轮询去检查是否有任务存
在。当任务来时候工作线程可以立即返回,也可以避免轮询带来的延迟。
下面介绍RedisClient的list相关方法:
1.lpush key string 在key对应list的头部添加字符串元素,返回1表示成功,0表示key存在且不是list类型
Task<long> AddFirst(int db, string key, byte[] value, bool createIfMissing = true,
bool queueJump = false);
Task<long> AddFirst(int db, string key, string value, bool createIfMissing = true,
bool queueJump = false);
2.rpush key string 同上,在尾部添加
Task<long> AddLast(int db, string key, byte[] value, bool createIfMissing = true,
bool queueJump = false);
Task<long> AddLast(int db, string key, string value, bool createIfMissing = true,
bool queueJump = false);
3.llen key 返回key对应list的长度,key不存在返回0,如果key对应类型不是list返回错误
Task<long> GetLength(int db, string key, bool queueJump = false);
4.lrange key start end 返回指定区间内的元素,下标从0开始,负值表示从后面计算,
-1表示倒数第一个元素 ,key不存在返回空列表
Task<byte[][]> Range(int db, string key, int start, int stop,
bool queueJump = false);
Task<string[]> RangeString(int db, string key, int start, int stop,
bool queueJump = false);
5.ltrim key start end 截取list,保留指定区间内元素,成功返回1,key不存在返回错误
Task Trim(int db, string key, int count, bool queueJump = false);
Task Trim(int db, string key, int start, int stop, bool queueJump = false);
6.lset key index value 设置list中指定下标的元素值,成功返回1,key或者下标不存在返回错误
Task Set(int db, string key, int index, byte[] value, bool queueJump = false);
Task Set(int db, string key, int index, string value, bool queueJump = false);
7.lrem key count value 从key对应list中删除count个和value相同的元素。count为0时候删除全部
Task<long> Remove(int db, string key, byte[] value, int count = 1, bool queueJump = false);
Task<long> Remove(int db, string key, string value, int count = 1, bool queueJump = false);
8.lpop key 从list的头部删除元素,并返回删除元素。如果key对应list不存在或者是空返回nil,
如果key对应值不是list返回错误
Task<byte[]> RemoveFirst(int db, string key, bool queueJump = false);
Task<string> RemoveFirstString(int db, string key, bool queueJump = false);
9.rpop 同上,但是从尾部删除
Task<byte[]> RemoveLast(int db, string key, bool queueJump = false);
Task<string> RemoveLastString(int db, string key, bool queueJump = false);
10.blpop key1...keyN timeout 从左到右扫描返回对第一个非空list进行lpop操作并返回,
比如blpop list1 list2 list3 0 ,如果list不存在list2,list3都是非空则对list2做lpop并返回
从list2中删除的元素。如果所有的list都是空或不存在,则会阻塞timeout秒,timeout
为0表示一直阻塞。当阻塞时,如果有client对key1...keyN中的任意key进行push操作,
则第一在这个key上被阻塞的client会立即返回。如果超时发生,则返回nil。
Task<Tuple<string, byte[]>> BlockingRemoveFirst(int db, string[] keys, int timeoutSeconds,
bool queueJump = false);
Task<Tuple<string, string>> BlockingRemoveFirstString(int db, string[] keys, int
timeoutSeconds, bool queueJump = false);
11.brpop 同blpop,一个是从头部删除一个是从尾部删除
Task<Tuple<string, byte[]>> BlockingRemoveLast(int db, string[] keys, int timeoutSeconds,
bool queueJump = false);
Task<Tuple<string, string>> BlockingRemoveLastString(int db, string[] keys, int timeoutSeconds,
bool queueJump = false);
12.rpoplpush srckey destkey 从srckey对应list的尾部移除元素并添加到destkey对应list的头部,最后
返回被移除的元素值,整个操作是原子的.如果srckey是空或者不存在返回nil
Task<byte[]> RemoveLastAndAddFirst(int db, string source, string destination,
bool queueJump = false);
Task<string> RemoveLastAndAddFirstString(int db, string source, string destination,
bool queueJump = false);
2.3.3>Redis set
redis的set是string类型的无序集合。set元素最大可以包含(2的32次方-1)个元素。set的是通过hash table实现的,
所以添加,删除,查找的复杂度都是O(1)。hash table会随着添加或者删除自动的调整大小。需要注意的是调整
hash table大小时候需要同步(获取写锁)会阻塞其他读写操作。可能不久后就会改用跳表(skip list)来实现跳
表已经在sorted set中使用了。关于set集合类型除了基本的添加删除操作,其他有用的操作还包含集合的取并集
(union),交集(intersection),差集(difference)。通过这些操作可以很容易的实现sns中的好友推荐和blog的tag功能。
1. 添加一个string元素到,key对应的set集合中,成功返回1,如果元素以及在集合中返回0,
key对应的set不存在返回错误
Task<bool> Add(int db, string key, byte[] value, bool queueJump = false);
Task<long> Add(int db, string key, byte[][] values, bool queueJump = false);
Task<bool> Add(int db, string key, string value, bool queueJump = false);
Task<long> Add(int db, string key, string[] values, bool queueJump = false);
2.srem key member 从key对应set中移除给定元素,成功返回1,如果member在集合中不存在或者key
不存在返回0,如果key对应的不是set类型的值返回错误
Task<bool> Remove(int db, string key, byte[] value, bool queueJump = false);
Task<long> Remove(int db, string key, byte[][] values, bool queueJump = false);
Task<bool> Remove(int db, string key, string value, bool queueJump = false);
Task<long> Remove(int db, string key, string[] values, bool queueJump = false);
3.spop key 删除并返回key对应set中随机的一个元素,如果set是空或者key不存在返回nil
Task<byte[]> RemoveRandom(int db, string key, bool queueJump = false);
Task<string> RemoveRandomString(int db, string key, bool queueJump = false);
4.srandmember key 同spop,随机取set中的一个元素,但是不删除元素
Task<byte[]> GetRandom(int db, string key, bool queueJump = false);
Task<byte[][]> GetRandom(int db, string key, int count, bool queueJump = false);
Task<string> GetRandomString(int db, string key, bool queueJump = false);
Task<string[]> GetRandomString(int db, string key, int count, bool queueJump = false);
5.从srckey对应set中移除member并添加到dstkey对应set中,整个操作是原子的。成功返回1,
如果member在srckey中不存在返回0,如果key不是set类型返回错误scard key 返回set的元素个数,
如果set是空或者key不存在返回0
Task<bool> Move(int db, string source, string destination, byte[] value,
bool queueJump = false);
Task<bool> Move(int db, string source, string destination, string value,
bool queueJump = false);
6.sismember key member 判断member是否在set中,存在返回1,0表示不存在或者key不存在
Task<bool> Contains(int db, string key, byte[] value, bool queueJump = false);
Task<bool> Contains(int db, string key, string value, bool queueJump = false);
7.sinter key1 key2...keyN 返回所有给定key的交集
Task<byte[][]> Intersect(int db, string[] keys, bool queueJump = false);
Task<string[]> IntersectString(int db, string[] keys,
bool queueJump = false);
8.sinterstore dstkey key1...keyN 同sinter,但是会同时将交集存到dstkey下
Task<long> IntersectAndStore(int db, string destination, string[] keys,
bool queueJump = false);
9.sunion key1 key2...keyN 返回所有给定key的并集
Task<byte[][]> Union(int db, string[] keys, bool queueJump = false);
Task<string[]> UnionString(int db, string[] keys, bool queueJump = false);
10.sunionstore dstkey key1...keyN 同sunion,并同时保存并集到dstkey下
Task<long> UnionAndStore(int db, string destination, string[] keys,
bool queueJump = false);
11.sdiff key1 key2...keyN 返回所有给定key的差集
Task<byte[][]> Difference(int db, string[] keys, bool queueJump = false);
Task<string[]> DifferenceString(int db, string[] keys, bool queueJump = false);
12.sdiffstore dstkey key1...keyN 同sdiff,并同时保存差集到dstkey下
Task<long> DifferenceAndStore(int db, string destination, string[] keys,
bool queueJump = false);
13.smembers key 返回key对应set的所有元素,结果是无序的
Task<byte[][]> GetAll(int db, string key, bool queueJump = false);
Task<string[]> GetAllString(int db, string key, bool queueJump = false);
2.3.4>Redis StoredSet:
Redis的StoredSet和set一样也是string类型元素的集合,不同的是每个元素都会关联一个double类型的score
。sorted set的实现是skip list和hash table的混合体当元素被添加到集合中时,一个元素到score的映射被添加
到hash table中,所以给定一个元素获取score的开销是O(1),另一个score到元素的映射被添加到skip list并按照
score排序,所以就可以有序的获取集合中的元素。添加,删除操作开销都是O(log(N))和skip list的开销一致,
redis的skip list实现用的是双向链表,这样就可以逆序从尾部取元素。sorted set最经常的使用方式应该是作为
索引来使用.我们可以把要排序的字段作为score存储,对象的id当元素存储。下面是sorted set相关命令
下面介绍RedisClient的StoredSet相关方法:
1.zadd key score member 添加元素到集合,元素在集合中存在则更新对应score
Task<bool> Add(int db, string key, byte[] value, double score, bool queueJump = false);
Task<bool> Add(int db, string key, string value, double score, bool queueJump = false);
2.zrem key member 删除指定元素,1表示成功,如果元素不存在返回0
Task<bool> Remove(int db, string key, byte[] member, bool queueJump = false);
Task<long> Remove(int db, string key, byte[][] members, bool queueJump = false);
Task<bool> Remove(int db, string key, string member, bool queueJump = false);
Task<long> Remove(int db, string key, string[] members, bool queueJump = false);
3.zincrby key incr member 增加对应member的score值,然后移动元素
并保持skip list保持有序。返回更新后的score值
Task<double> Increment(int db, string key, byte[] member, double delta,
bool queueJump = false);
Task<double>[] Increment(int db, string key, byte[][] members, double delta,
bool queueJump = false);
Task<double> Increment(int db, string key, string member, double delta,
bool queueJump = false);
Task<double>[] Increment(int db, string key, string[] members, double delta,
bool queueJump = false);
4.zrank key member 返回指定元素在集合中的排名(下标),集合中元素是按score从小到大排序的
Task<long?> Rank(int db, string key, byte[] member, bool ascending = true,
bool queueJump = false);
Task<long?> Rank(int db, string key, string member, bool ascending = true,
bool queueJump = false);
5.zrange key start end 类似lrange操作从集合中去指定区间的元素。返回的是有序结果
Task<Collections.Generic.KeyValuePair<byte[], double>[]> Range(int db,string key,
long start, long stop, bool ascending = true, bool queueJump = false);
Task<Collections.Generic.KeyValuePair<byte[], double>[]> Range(int db, string key,
double min = -1.0 / 0.0, double max = 1.0 / 0.0, bool ascending = true, bool minInclusive = true,
bool maxInclusive = true, long offset = 0, long count = 9223372036854775807, bool queueJump = false);
Task<Collections.Generic.KeyValuePair<string, double>[]> RangeString(int db, string key,
long start, long stop, bool ascending = true, bool queueJump = false);
Task<Collections.Generic.KeyValuePair<string, double>[]> RangeString(int db, string key,
double min = -1.0 / 0.0, double max = 1.0 / 0.0, bool asc
6.zcount key min max 返回集合中score在给定区间的数量
Task<long> GetLength(int db, string key, double min, double max, bool queueJump = false);
7.返回集合中元素个数
Task<long> GetLength(int db, string key, bool queueJump = false);
8.zscore key element 返回给定元素对应的score
Task<double?> Score(int db, string key, byte[] member, bool queueJump = false);
Task<double?> Score(int db, string key, string member, bool queueJump = false);
9.zremrangebyscore key min max 删除集合中score在给定区间的元素
Task<long> RemoveRange(int db, string key, long start, long stop, bool queueJump = false);
Task<long> RemoveRange(int db, string key, double min, double max, bool minInclusive = true,
bool maxInclusive = true, bool queueJump = false);
2.3.5>Redis String
string是redis最基本的类型,而且string类型是二进制安全的。意思是redis的string可以
包含任何数据。比如jpg图片或者序列化的对象。从内部实现来看其实string可以看作byte数组
,最大上限是1G字节。下面是string类型的定义。
struct sdshdr {
long len;
long free;
char buf[];
};
buf是个char数组用于存贮实际的字符串内容。其实char和c#中的byte是等价的,都是一个字节
len是buf数组的长度,free是数组中剩余可用字节数。由此可以理解为什么string类型是二进制
安全的了。因为它本质上就是个byte数组.当然可以包含任何数据了。另外string类型可以被部分
命令按int处理.比如incr等命令,下面详细介绍。还有redis的其他类型像list,set,sorted set ,hash
它们包含的元素与都只能是string类型。如果只用string类型,redis就可以被看作加上持久化特性的
memcached.当然redis对string类型的操作比memcached多很多啊。如下:
1.set key value 设置key对应的值为string类型的value,返回1表示成功,0失败
Task Set(int db, string key, byte[] value, bool queueJump = false);
Task Set(int db, string key, long value, bool queueJump = false);
Task Set(int db, string key, string value, bool queueJump = false);
Task Set(int db, string key, byte[] value, long expirySeconds, bool queueJump = false);
2.setnx key value 同上,如果key已经存在,返回0 。nx 是not exist的意思
Task<bool> SetIfNotExists(int db, string key, byte[] value, bool queueJump = false);
Task<bool> SetIfNotExists(int db, string key, string value, bool queueJump = false);
3.mset key1 value1 ... keyN valueN 一次设置多个key的值,成功返回1表示所有的值都设置了,失败返回0表示没有任何值被设置
Task Set(int db, Dictionary<string, byte[]> values, bool queueJump = false);
Task Set(int db, Dictionary<string, string> values, bool queueJump = false);
4.msetnx key1 value1 ... keyN valueN 同上,但是不会覆盖已经存在的key
Task<bool> SetIfNotExists(int db, Dictionary<string, byte[]> values, bool queueJump = false);
Task<bool> SetIfNotExists(int db, Dictionary<string, string> values, bool queueJump = false);
5.get key 获取key对应的string值,如果key不存在返回nil
Task<byte[]> Get(int db, string key, bool queueJump = false);
Task<string> GetString(int db, string key, bool queueJump = false);
6.getset key value 原子的设置key的值,并返回key的旧值。如果key不存在返回空
Task<byte[]> GetSet(int db, string key, byte[] value, bool queueJump = false);
Task<string> GetSet(int db, string key, string value, bool queueJump = false);
5.mget key1 key2 ... keyN 一次获取多个key的值,如果对应key不存在,则对应返回nil。
Task<string[]> GetString(int db, string[] keys, bool queueJump = false);
Task<byte[][]> Get(int db, string[] keys, bool queueJump = false);
7.incr key 对key的值做加加操作,并返回新的值。注意incr一个不是int的value
会返回错误,incr一个不存在的key,则设置key为1
Task<long> Increment(int db, string key, long value = 1, bool queueJump = false);
Task<double> Increment(int db, string key, double value, bool queueJump = false);
8.decr key 同上,但是做的是减减操作,decr一个不存在key,则设置key为-1
Task<long> Decrement(int db, string key, long value = 1, bool queueJump = false);
9.append key value 给指定key的字符串值追加value,返回新字符串值的长度。
Task<long> Append(int db, string key, byte[] value, bool queueJump = false);
Task<long> Append(int db, string key, string value, bool queueJump = false);
10.substr key start end 返回截取过的key的字符串值,注意并不修改key的值。下标是从0开始的,
Task<byte[]> Get(int db, string key, int start, int end, bool queueJump = false);
Task<string> GetString(int db, string key, int start, int end, bool queueJump = false);