赞
踩
目录
Redis 是一个 key-value 的数据库,key 是一般的 String,不过 value 却是多种多样的:
- 127.0.0.1:6379> select 0
- OK
- 127.0.0.1:6379> set k1 v1
- OK
- 127.0.0.1:6379> get k1
- "v1"
- 127.0.0.1:6379> exists k1
- (integer) 1
- 127.0.0.1:6379> exists k2
- (integer) 0
- 127.0.0.1:6379> expire k1 10
- (integer) 1
- 127.0.0.1:6379> ttl k1
- (integer) 7
- 127.0.0.1:6379> persist k1
- (integer) 1
- 127.0.0.1:6379> ttl k1
- (integer) -1
- 127.0.0.1:6379> type k1
- string
String 类型是 Redis 基本类型,一个键最大能存储 512MB 且是二进制安全的。意思是 redis 的 String 类型可以存储任何数据,如数字,字符串,jpg 图片或者序列化的对象。
redis 中的 String 是动态字符串,内部结构类似 ArrayList。采用预分配冗余空间的方式减少内存的频繁分配
内部为字符串分配的实际空间一般高于字符串长度,当字符串长度 <1MB 时,扩容方式是加倍 也就是原来的两倍。当字符串长度> 1MB 时,一次扩容 1MB,直到最大 512MB.
redis 的列表是一个字符链表,内部结构类似 LinkedList。left,right 都可以添加。如果键不在,则创建新链表,如果已存在则新填内容。如果当前链表没有值,则该链表也会自动删除。redis 的列表最多可存储 2^32-1 个元素(4294967295,每个列表可以存储 40 多亿个元素)
底层是一个快速链表(quickList)的结构,在列表元素较少时,使用内存存储压缩列表 ziplist。当元素数量较多时,改成 quickList,也就是将多个 zipList 串起来使用,以减少内存的碎片化。
命令执行:
- lpush key value : 从头部(左边)压进(新增)一个新元素
- 127.0.0.1:6379> lpush list1 v1 v2 v3 v4 v5
- (integer) 5
-
- rpush key value : 从尾部(右边)压进(新增)一个新元素
- rpush list1 v6
- (integer) 6
-
- lpop key value : 从头部(左边)弹出(删除)一个元素并返回
- 127.0.0.1:6379> lpop list1
- "v5"
-
- rpop key value : 从尾部(右边)弹出(删除)一个元素并返回
- 127.0.0.1:6379> rpop list1
- "v1"
-
- lset key index value : 修改索引号为index的元素的值为value
- 127.0.0.1:6379> lset list1 4 v7
- OK
-
- lrem key count value : 删除count个元素值为value
- 127.0.0.1:6379> lrem list1 0 v0
- (integer) 1
-
- linsert key before/after old_value new_value : 在某一个旧元素值的前边或后边插入一个新的值
- 127.0.0.1:6379> linsert list1 before v7 v6
- (integer) 6
-
- lindex key index : 查询当前list中索引为index的值
- 127.0.0.1:6379> lindex list1 5
- "v6"
-
- lrange key start end : 遍历list的所有元素并显示
- 127.0.0.1:6379> lrange list1 0 -1
- 1) "v3"
- 2) "v4"
- 3) "v5"
- 4) "v6"
- 5) "v7"
-
- ltrim key start end : 截取list从stater到end位置的值并保留
- 127.0.0.1:6379> ltrim list1 2 6
- OK
-
- llen key : 返回一个list的元素个数
- 127.0.0.1:6379> llen list1
- (integer) 5
实战场景:
redis 的集合是 String 类型的无序不重复的元素集,同时提供交集、并集、差集等操作,集合中最大的成员数为 2^32-1(40 多亿)。Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O (1)。
类似 HashSet, 也是通过哈希表实现的,相当于所有的 value 都为空。通过计算 hash 的方式来快速排重,也是 set 能提供判断一个成员是否在集合内的原因。
命令执行:
- sadd key member [member...] : 添加set集合的member
- 127.0.0.1:6379> sadd set1 value1 value2 value3
- (integer) 3
-
- srem key member [member...] : 删除set集合中的member
- 127.0.0.1:6379> srem set1 value1
- (integer) 1
-
- spop key [count] : 随机弹出count个member
- 127.0.0.1:6379> spop set1 1
- 1) "menber2"
-
- scard key : 获取set的成员个数
- 127.0.0.1:6379> scard set2
- (integer) 2
-
- smembers key : 获取set的所有成员
- 127.0.0.1:6379> smembers set2
- 1) "value3"
- 2) "member1"
-
- sismember key member : 判断member是否是set中的成员
- 127.0.0.1:6379> sismember set1 member1
- (integer) 1
-
- srandmember key count : 随机返回count个成员
- 127.0.0.1:6379> srandmember set1 1
- (integer) 1
-
- smove sourse destination member : 移动source中的成员member到destination中
- 127.0.0.1:6379> smove set1 set2 member1
- (integer) 1
-
- sdiff key1 key2 [key3...] : 返回key1与key2的差集
- 127.0.0.1:6379> sdiff set2 set1
- 1) "value3"
-
- sinter key1 key2 [key3...] : 返回key1与key2的交集
- 127.0.0.1:6379> sinter set1 set2
- 1) "member1"
-
- sunion key1 key2 [key3...] : 返回key1与key2的交集
- 127.0.0.1:6379> sunion set2 set1
- 1) "value3"
- 2) "value1"
- 3) "menber3"
- 4) "member1"
- 5) "member2"
redis 中的无序字典是一个 String 类型的 field 和 value 的映射表,内部结构类似 HashMap,每个 hash 可以存储 2^32-1 个键值对(40 多亿)
底层的实现结构,与 HashMap 一样,是 “数组 + 链表” 的二维结构,第一维 hash 的数据位置碰撞时,将碰撞元素用链表串接起来,不同的是,redis 字典的值只能是字符串,而且两者的 rehash 方式不同。java 的 hashmap 是一次全部 rehash,耗时较高,redis 为了提高性能,采用渐进式 rehash 策略。具体方式为,同时保留新旧两个 hash 结构,然后逐步搬迁,最后取代
命令执行:
- hset key field value : 给hash设置field和value
- 127.0.0.1:6379> hset hash1 k1 v1
- (integer) 1
-
- hget key field : 获取hash中健值为field的值
- 127.0.0.1:6379> hget hash1 k1
- "v1"
-
- hmset key field value [field value...] : 同时给hash设置多个field和value
- 127.0.0.1:6379> hmset hash1 k2 v2 k3 v3 k4 v4
- OK
-
- hmget key field [field...] : 同时获取hash中多个健值为field的值
- 127.0.0.1:6379> hmget hash1 k1 k2 k3 k4
- 1) "v1"
- 2) "v2"
- 3) "v3"
- 4) "v4"
-
- hsetnx key field value : 判断hash中是否存在 该field值,不存在则添加
- 127.0.0.1:6379> hsetnx hash1 k5 v5
- (integer) 1
-
- hgetall key : 获取hash中所有的field和value的值
- 127.0.0.1:6379> hgetall hash1
- 1) "k3"
- 2) "v3"
- 3) "k4"
- 4) "v4"
- 5) "k5"
- 6) "v5"
- 7) "k1"
- 8) "3"
- 9) "k2"
- 10) "81.83635"
-
- hkeys key : 获取hash中所有的field的值
- 127.0.0.1:6379> hkeys hash1
- 1) "k3"
- 2) "k4"
- 3) "k5"
-
- hvals key : 获取hash中所有value的值
- 127.0.0.1:6379> hvals hash1
- 1) "v3"
- 2) "v4"
- 3) "v5"
-
- hexists key field : 判断hash中是否存在field值
- 127.0.0.1:6379> hexists hash1 k1
- (integer) 1
-
- hlen key : 获取hash中键值对的个数
- 127.0.0.1:6379> hlen hash1
- (integer) 5
-
- hincrby key field increment : 设置hash中field属性自增,前提是整数,自增步长为increment
- 127.0.0.1:6379> hincrby hash1 k2 10
- (integer) 10
-
- hincrbyfloat key field increment : 设置hash中field属性自增 ,可以是小数,自增步长为increment
- 127.0.0.1:6379> hincrbyfloat hash1 k2 10.1
- "40.1"
Redis 有序集合和集合一样也是 string 类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。zset 的成员是唯一的,但分数是可以重复的。
压缩列表 (ziplist): ziplist 是为了提高存储效率而设计的一种特殊编码的双向链表。它可以存储字符串或者整数,存储整数时是采用整数的二进制而不是字符串形式存储。它能在 O (1) 的时间复杂度下完成 list 两端的 push 和 pop 操作。但是因为每次操作都需要重新分配 ziplist 的内存,所以实际复杂度和 ziplist 的内存使用量相关
跳跃表(zSkiplist): 跳跃表的性能可以保证在查找,删除,添加等操作的时候在对数期望时间内完成,这个性能是可以和平衡树来相比较的,而且在实现方面比平衡树要优雅,这是采用跳跃表的主要原因。跳跃表的复杂度是 O (log (n))。
命令执行:
- zadd key score member [score member...]:添加zset集合新的成员分数和成员。
- 127.0.0.1:6379> zadd k1 10 c1 20 c2 30 c3 40 c4 50 c5 60 c6 70 c7 80 c8 90 c9
- (integer) 9
-
- zrem key member [member...]:删除zset中的成员member
- 127.0.0.1:6379> zrem zset key1
- (integer) 1
-
- zrange key start stop [withscores]:遍历zset,获取所有成员 ,若加上withscores,则分数被同时返回
- 127.0.0.1:6379> zrange k1 0 -1
- 1) "c1"
- 2) "c2"
- 3) "c3"
- 4) "c4"
- 5) "c5"
- 6) "c6"
- 7) "c7"
- 8) "c8"
- 9) "c9"
-
- zrangebyscore key min max [withscores] [limit offset count] : 获取指定范围内分数的所有成员 (升序) withscores表示带上分数,limit表示分页
- 127.0.0.1:6379> zrevrangebyscore k1 50 (10
- 1) "c5"
- 2) "c4"
- 3) "c3"
- 4) "c2"
-
- zcard key:获取zset成员个数
- 127.0.0.1:6379>zcard k1
- (integer)8
- zcount key min max :获取zset在指定分数范围内的成员个数,“(”左括号表示闭区间
- 127.0.0.1:6379> zcount k1 0 (60
- (integer) 5
-
- zrank key member : 获取zset中成员member的排名(升序)
- 127.0.0.1:6379> zvrank k1 c9
- (integer) 8
-
- zrevrank key member:获取zset中成员member的排名(降序)
- 127.0.0.1:6379> zrevrank k1 c9
- (integer) 0
-
- zrevrange key [withscores]: 获取zset中所有的成员(降序)
- 127.0.0.1:6379> zrevrange k1 0 -1
- 1) "c9"
- 2) "c8"
- 3) "c7"
- 4) "c6"
- 5) "c5"
- 6) "c4"
- 7) "c3"
- 8) "c2"
- 9) "c1"
-
- zrevrangebyscore key max min [withscores] [limit offset count] :获取指定范围内分数的所有成员 (降序) withscores表示带上分数,limit表示分页
举个例子,A = {1, 2, 3, 4, 5}, B = {3, 5, 6, 7, 9};那么基数(不重复的元素)= 1, 2, 4, 6, 7, 9; (允许容错,即可以接受一定误差)
这个结构可以非常省内存的去统计各种计数,比如注册 IP 数、每日访问 IP 数、页面实时 UV、在线用户数,共同好友数等。
一个大型的网站,每天 IP 比如有 100 万,粗算一个 IP 消耗 15 字节,那么 100 万个 IP 就是 15M。而 HyperLogLog 在 Redis 中每个键占用的内容都是 12K,理论存储近似接近 2^64 个值,不管存储的内容是什么,它一个基于基数估算的算法,只能比较准确的估算出基数,可以使用少量固定的内存去存储并识别集合中的唯一元素。而且这个估算的基数并不一定准确,是一个带有 0.81% 标准错误的近似值(对于可以接受一定容错的业务场景,比如 IP 数统计,UV 等,是可以忽略不计的)
- 127.0.0.1:6379> pfadd key1 a b c d e f g h i # 创建第一组元素
- (integer) 1
- 127.0.0.1:6379> pfcount key1 # 统计元素的基数数量
- (integer) 9
- 127.0.0.1:6379> pfadd key2 c j k l m e g a # 创建第二组元素
- (integer) 1
- 127.0.0.1:6379> pfcount key2
- (integer) 8
- 127.0.0.1:6379> pfmerge key3 key1 key2 # 合并两组:key1 key2 -> key3 并集
- OK
- 127.0.0.1:6379> pfcount key3
- (integer) 13
Bitmap 即位图数据结构,都是操作二进制位来进行记录,只有 0 和 1 两个状态。
比如:统计用户信息,活跃,不活跃! 登录,未登录! 打卡,不打卡! 两个状态的,都可以使用 Bitmaps!
如果存储一年的打卡状态需要多少内存呢? 365 天 = 365 bit 1 字节 = 8bit 46 个字节左右!
使用 bitmap 来记录 周一到周日的打卡! 周一:1 周二:0 周三:0 周四:1 ……
- 127.0.0.1:6379> setbit sign 0 1
- (integer) 0
- 127.0.0.1:6379> setbit sign 1 1
- (integer) 0
- 127.0.0.1:6379> setbit sign 2 0
- (integer) 0
- 127.0.0.1:6379> setbit sign 3 1
- (integer) 0
- 127.0.0.1:6379> setbit sign 4 0
- (integer) 0
- 127.0.0.1:6379> setbit sign 5 0
- (integer) 0
- 127.0.0.1:6379> setbit sign 6 1
- (integer) 0
查看某一天是否有打卡!
- 127.0.0.1:6379> getbit sign 3
- (integer) 1
- 127.0.0.1:6379> getbit sign 5
- (integer) 0
统计操作,统计 打卡的天数!
- 127.0.0.1:6379> bitcount sign # 统计这周的打卡记录,就可以看到是否有全勤!
- (integer) 3
- 127.0.0.1:6379> geoadd china:city 118.76 32.04 manjing 112.55 37.86 taiyuan 123.43 41.80 shenyang
- (integer) 3
- 127.0.0.1:6379> geoadd china:city 144.05 22.52 shengzhen 120.16 30.24 hangzhou 108.96 34.26 xian
- (integer) 3
规则:
两级无法直接添加,我们一般会下载城市数据 (这个网址可以查询 GEO: http://www.jsons.cn/lngcode)!
- # 当坐标位置超出上述指定范围时,该命令将会返回一个错误。
- 127.0.0.1:6379> geoadd china:city 39.90 116.40 beijin
- (error) ERR invalid longitude,latitude pair 39.900000,116.400000
- 127.0.0.1:6379> geopos china:city taiyuan manjing
- 1) 1) "112.54999905824661255"
- 1) "37.86000073876942196"
- 2) 1) "118.75999957323074341"
- 1) "32.03999960287850968"
获得当前定位,一定是一个坐标值!
单位如下:
- 127.0.0.1:6379> geodist china:city taiyuan shenyang m
- "1026439.1070"
- 127.0.0.1:6379> geodist china:city taiyuan shenyang km
- "1026.4391"
附近的人 ==> 获得所有附近的人的地址,定位,通过半径来查询
获得指定数量的人
- 127.0.0.1:6379> georadius china:city 110 30 1000 km 以 100,30 这个坐标为中心, 寻找半径为1000km的城市
- 1) "xian"
- 2) "hangzhou"
- 3) "manjing"
- 4) "taiyuan"
- 127.0.0.1:6379> georadius china:city 110 30 500 km
- 1) "xian"
- 127.0.0.1:6379> georadius china:city 110 30 500 km withdist
- 1) 1) "xian"
- 2) "483.8340"
- 127.0.0.1:6379> georadius china:city 110 30 1000 km withcoord withdist count 2
- 1) 1) "xian"
- 2) "483.8340"
- 3) 1) "108.96000176668167114"
- 2) "34.25999964418929977"
- 2) 1) "manjing"
- 2) "864.9816"
- 3) 1) "118.75999957323074341"
- 2) "32.03999960287850968"
参数 key 经度 纬度 半径 单位 [显示结果的经度和纬度] [显示结果的距离] [显示的结果的数量]
显示与指定成员一定半径范围内的其他成员
- 127.0.0.1:6379> georadiusbymember china:city taiyuan 1000 km
- 1) "manjing"
- 2) "taiyuan"
- 3) "xian"
- 127.0.0.1:6379> georadiusbymember china:city taiyuan 1000 km withcoord withdist count 2
- 1) 1) "taiyuan"
- 2) "0.0000"
- 3) 1) "112.54999905824661255"
- 2) "37.86000073876942196"
- 2) 1) "xian"
- 2) "514.2264"
- 3) 1) "108.96000176668167114"
- 2) "34.25999964418929977"
该命令返回 11 个字符的 hash 字符串
- 127.0.0.1:6379> geohash china:city taiyuan shenyang
- 1) "ww8p3hhqmp0"
- 2) "wxrvb9qyxk0"
geo 底层的实现原理实际上就是 Zset, 我们可以通过 Zset 命令来操作 geo
127.0.0.1:6379> type china:city
zset
查看全部元素 删除指定的元素
- 127.0.0.1:6379> zrange china:city 0 -1 withscores
- 1) "xian"
- 2) "4040115445396757"
- 3) "hangzhou"
- 4) "4054133997236782"
- 5) "manjing"
- 6) "4066006694128997"
- 7) "taiyuan"
- 8) "4068216047500484"
- 9) "shenyang"
- 1) "4072519231994779"
- 2) "shengzhen"
- 3) "4154606886655324"
- 127.0.0.1:6379> zrem china:city manjing
- (integer) 1
- 127.0.0.1:6379> zrange china:city 0 -1
- 1) "xian"
- 2) "hangzhou"
- 3) "taiyuan"
- 4) "shenyang"
- 5) "shengzhen"
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。