Redis

Redis 简介

Redis:REmote DIctionary Server(远程字典服务器)

​ 是完全开源免费的,用C语言编写的,遵守BSD协议,是一个高性能的(Key/Value)分布式内存数据库,基于内存运行,

并支持持久化的NoSQL数据库,是当前最热门的NoSQL数据库之一,也被人们称为数据结构服务器。

  • Redis支持数据的持久化(RDB,AOF),可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。
  • Redis不仅仅支持简单的 key-value 类型的数据,同时还提供list、set、zset、hash等数据结构的存储。
  • Redis支持数据的备份,即master-slave模式的数据备份。

Redis 用途

  • 效率高,可用于高速缓存
  • 发布订阅系统
  • 地图信息分析
  • 计时器,计数器

Redis安装

windows下安装(下载解压即可)
  • 下载地址 https://github.com/dmajkic/redis/downloads
  • 双击 redis-server.exe 启动即可
  • 双击redis-cli.exe启动客户端
Linux下安装
  • 下载地址 http://download.redis.io/releases/redis-5.0.7.tar.gz

  • tar -zxvf redis-5.0.7.tar.gz

  • 安装gcc(已安装的需要升级gcc) yum install gcc-c++

  • 执行make命令

    • make
    • make install
  • Redis默认安装路径 /usr/local/bin

  • 修改配置让其能后台启动

    • vim redis.conf
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pXthEegw-1611885165833)(C:\Users\Jy\AppData\Roaming\Typora\typora-user-images\image-20210128102253860.png)]
    • redis.conf配置文件中daemonize守护线程,默认是NO
    • daemonize是用来指定redis是否要用守护线程的方式启动,改为yes
  • 启动服务及客户端

    • cd /usr/local/bin
    • redis-server
    • redis-cli -p 6379
  • 退出服务 shutdown

redis压力测试工具-----Redis-benchmark

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NBelrRjj-1611885165836)(C:\Users\Jy\AppData\Roaming\Typora\typora-user-images\image-20210128103740880.png)]

# 测试一:100个并发连接,100000个请求,检测host为localhost 端口为6379的redis服务器性能
redis-benchmark -h localhost -p 6379 -c 100 -n 100000
# 测试出来的所有命令只举例一个!
====== SET ====== 100000 requests completed in 1.88 seconds # 对集合写入测试100 parallel clients # 每次请求有100个并发客户端 3 bytes payload # 每次写入3个字节的数据,有效载荷 keep alive: 1 # 保持一个连接,一台服务器来处理这些请求 17.05% <= 1 milliseconds 97.35% <= 2 milliseconds 99.97% <= 3 milliseconds 100.00% <= 3 milliseconds # 所有请求在 3 毫秒内完成 53248.14 requests per second # 每秒处理 53248.14 次请求

redis 基础知识

  • 默认16个数据库,类似数组下标从零开始,初始默认使用零号库
# Select命令切换数据库
127.0.0.1:6379> select 7
OK
127.0.0.1:6379[7]>
# 不同的库可以存不同的数据# Dbsize查看当前数据库的key的数量
127.0.0.1:6379[7]> DBSIZE
(integer) 0
127.0.0.1:6379[7]> select 0
OK
127.0.0.1:6379> DBSIZE
(integer) 5
127.0.0.1:6379> keys * # 查看具体的key
1) "counter:__rand_int__"
2) "mylist"
3) "k1"
4) "myset:__rand_int__"
5) "key:__rand_int__"# Flushdb:清空当前库
# Flushall:清空全部的库
127.0.0.1:6379> DBSIZE
(integer) 5
127.0.0.1:6379> FLUSHDB
OK
127.0.0.1:6379> DBSIZE
(integer) 0

为什么redis是单线程

我们首先要明白,Redis很快!官方表示,因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了
Redis采用的是基于内存的采用的是单进程单线程模型的 KV 数据库,由C语言编写,官方提供的数据是可以达到100000+的QPS(每秒内查询次数)。这个数据不比采用单进程多线程的同样基于内存的 KV数据库Memcached差

Redis为什么这么快

1)以前一直有个误区以为:高性能服务器 一定是多线程来实现的
原因很简单:多线程一定比单线程效率高,其实不然!
2)redis核心:如果数据全都在内存里,单线程的去操作效率才是最高的,为什么呢?
因为多线程的本质就是CPU模拟出来多个线程的情况,这种模拟出来的情况就有一个代价,就是上下文的切换,对于一个内存的系统来说,它没有上下文的切换就是效率最高的。redis用单个CPU绑定一块内存的数据,然后针对这块内存的数据进行多次读写的时候,都是在一个CPU上完成的,所以它是单线程处理这个事。在内存的情况下,这个方案就是最佳方案。
因为一次CPU上下文的切换大概在 1500ns 左右。从内存中读取 1MB 的连续数据,耗时大约为 250us,假设1MB的数据由多个线程读取了1000次,那么就有1000次时间上下文的切换,那么就有1500ns *1000 = 1500us ,我单线程的读完1MB数据才250us ,你光时间上下文的切换就用了1500us了,我还不算你每次读一点数据的时间。

redis 五大数据类型

  • String (字符串类型)

    • String是redis最基本的类型,可以理解成Memcached一模一样的类型,一个key对应一个value。
    • String类型是二进制安全的,意思是redis的string可以包含任何数据,比如jpg图片或者序列化的对象。
    • String类型是redis最基本的数据类型,一个redis中字符串value最多可以是512M。
  • Hash(哈希,类似 Java里的Map)

    • Redis hash 是一个键值对集合。
    • Redis hash 是一个String类型的fifield和value的映射表,hash特别适合用于存储对象。
    • 类似Java里面的Map<String,Object>
  • List(列表)

    • Redis列表是简单的字符串列表,按照插入顺序排序,可以添加一个元素到列表的头部(左边)或者尾部(右边)。它的底层实际是个链表 !
  • Set(集合)

    • Redis的Set是String类型的无序集合,它是通过HashTable实现的 !
  • Zset(sorted set:有序集合)

    • Redis zset 和 set 一样,也是String类型元素的集合,且不允许重复的成员。
    • 不同的是每个元素都会关联一个double类型的分数。
    • Redis正是通过分数来为集合中的成员进行从小到大的排序,zset的成员是唯一的,但是分数(Score)却可以重复。

操作命令

  • String字符串命令(单值单Value)

    • # set、get、del、append、strlen #
      127.0.0.1:6379> set key1 value1 # 设置值
      OK
      127.0.0.1:6379> get key1 # 获得key
      "value1"
      127.0.0.1:6379> del key1 # 删除key
      (integer) 1
      127.0.0.1:6379> keys * # 查看全部的key
      (empty list or set)
      127.0.0.1:6379> exists key1 # 确保 key1 不存在
      (integer) 0
      127.0.0.1:6379> append key1 "hello" # 对不存在的 key 进行 APPEND ,等同于 SET key1 "hello"
      (integer) 5 # 字符长度
      127.0.0.1:6379> APPEND key1 "-2333" # 对已存在的字符串进行 APPEND
      (integer) 10 # 长度从 5 个字符增加到 10 个字符
      127.0.0.1:6379> get key1
      "hello-2333"
      127.0.0.1:6379> STRLEN key1 # 获取字符串的长度
      (integer) 10
      # incr、decr 一定要是数字才能进行加减,+1 和 -1。incrby、decrby 命令将 key 中储存的数字加上指定的增量值。
      127.0.0.1:6379> set views 0 # 设置浏览量为0
      OK
      127.0.0.1:6379> incr views # 浏览 + 1
      (integer) 1
      127.0.0.1:6379> incr views # 浏览 + 1
      (integer) 2
      127.0.0.1:6379> decr views # 浏览 - 1
      (integer) 1
      127.0.0.1:6379> incrby views 10 # +10
      (integer) 11
      127.0.0.1:6379> decrby views 10 # -10
      (integer) 1 # range [范围] # getrange 获取指定区间范围内的值,类似between...and的关系,从零到负一表示全部
      127.0.0.1:6379> set key2 abcd123456 # 设置key2的值
      OK
      127.0.0.1:6379> getrange key2 0 -1 # 获得全部的值
      "abcd123456"
      127.0.0.1:6379> getrange key2 0 2 # 截取部分字符串
      "abc"
      # setrange 设置指定区间范围内的值,格式是setrange key值 具体值
      127.0.0.1:6379> get key2
      "abcd123456"
      127.0.0.1:6379> SETRANGE key2 1 xx # 替换值
      (integer) 10
      127.0.0.1:6379> get key2
      "axxd123456"
      #setex(set with expire 设置过期时间)
      127.0.0.1:6379> setex key3 60 expire #  键秒值
      OK
      127.0.0.1:6379> ttl key3 # 查看剩余的时间
      (integer) 55
      # setnx(set if not exist 如果不存在就set)
      127.0.0.1:6379> setnx mykey "redis" # 如果不存在就设置,成功返回1
      (integer) 1
      127.0.0.1:6379> setnx mykey "mongodb"# 如果存在设置,失败返回0
      (integer) 0
      127.0.0.1:6379> get mykey "redis"
      # Mset 命令用于同时设置一个或多个 key-value 对。
      127.0.0.1:6379> mset k10 v10 k11 v11 k12 v12
      OK
      127.0.0.1:6379> keys *
      1) "k12"
      2) "k11"
      3) "k10"
      #Mget 命令返回所有(一个或多个)给定 key 的值。
      127.0.0.1:6379> mget k10 k11 k12 k13
      1) "v10"
      2) "v11"
      3) "v12"
      4) (nil)
      127.0.0.1:6379> msetnx k10 v10 k15 v15 # 原子性操作!
      (integer) 0
      127.0.0.1:6379> get key15
      (nil)
      # 缓存对象
      127.0.0.1:6379> mset user:1:name zhangsan user:1:age 2
      127.0.0.1:6379> mget user:1:name user:1:age
      127.0.0.1:6379> getset db mongodb # getset(先get再set)没有旧值,返回 nil
      (nil)
      127.0.0.1:6379> get db
      "mongodb"
      127.0.0.1:6379> getset db redis # 返回旧值 mongodb "mongodb"
      127.0.0.1:6379> get db"redis"
      
  • List操作命令(单值多value)

    • # Lpush:将一个或多个值插入到列表头部。(左)
      # rpush:将一个或多个值插入到列表尾部。(右)
      # lrange:返回列表中指定区间内的元素,区间以偏移量 START 和 END 指定。
      # 其中 0 表示列表的第一个元素, 1 表示列表的第二个元素,以此类推。
      # 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此 类推。
      127.0.0.1:6379> LPUSH list "one"
      (integer) 1
      127.0.0.1:6379> LPUSH list "two"
      (integer) 2
      127.0.0.1:6379> RPUSH list "right"
      (integer) 3
      127.0.0.1:6379> Lrange list 0 -1
      1) "two"
      2) "one"
      3) "right"
      127.0.0.1:6379> Lrange list 0 1
      1) "two"
      2) "one"
      # lpop 命令用于移除并返回列表的第一个元素。当列表 key 不存在时,返回 nil 。
      # rpop 移除列表的最后一个元素,返回值为移除的元素。
      127.0.0.1:6379> Lpop list "two"
      127.0.0.1:6379> Rpop list "right"
      127.0.0.1:6379> Lrange list 0 -1
      1) "one"
      # Lindex,按照索引下标获得元素(-1代表最后一个,0代表是第一个)
      127.0.0.1:6379> Lindex list 1
      (nil)
      127.0.0.1:6379> Lindex list 0
      "one"
      127.0.0.1:6379> Lindex list -1
      "one"
      # llen 用于返回列表的长度。
      127.0.0.1:6379> flushdb
      OK
      127.0.0.1:6379> Lpush list "one"
      (integer) 1
      127.0.0.1:6379> Lpush list "two"
      (integer) 2
      127.0.0.1:6379> Lpush list "three"
      (integer) 3
      127.0.0.1:6379> Llen list # 返回列表的长度
      (integer) 3
      # lrem key 根据参数 COUNT 的值,移除列表中与参数 VALUE 相等的元素。
      127.0.0.1:6379> lrem list 1 "two"
      (integer) 1
      127.0.0.1:6379> Lrange list 0 -1
      1) "three"
      2) "one"
      # Ltrim key 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。
      127.0.0.1:6379> RPUSH mylist "hello"
      (integer) 1
      127.0.0.1:6379> RPUSH mylist "hello"
      (integer) 2
      127.0.0.1:6379> RPUSH mylist "hello2"
      (integer) 3
      127.0.0.1:6379> RPUSH mylist "hello3"
      (integer) 4
      127.0.0.1:6379> ltrim mylist 1 2
      OK
      127.0.0.1:6379> lrange mylist 0 -1
      1) "hello"
      2) "hello2"
      # rpoplpush 移除列表的最后一个元素,并将该元素添加到另一个列表并返回。
      127.0.0.1:6379> rpush mylist "hello"
      (integer) 1
      127.0.0.1:6379> rpush mylist "foo"
      (integer) 2
      127.0.0.1:6379> rpush mylist "bar"
      (integer) 3
      127.0.0.1:6379> rpoplpush mylist myotherlist "bar"
      127.0.0.1:6379> lrange mylist 0 -1
      1) "hello"
      2) "foo"
      127.0.0.1:6379> lrange myotherlist 0 -1
      1) "bar"
      # lset key index value 将列表 key 下标为 index 的元素的值设置为 value。
      127.0.0.1:6379> exists list # 对空列表(key 不存在)进行 LSET
      (integer) 0
      127.0.0.1:6379> lset list 0 item # 报错
      (error) ERR no such key
      127.0.0.1:6379> lpush list "value1" # 对非空列表进行 LSET
      (integer) 1
      127.0.0.1:6379> lrange list 0 0
      1) "value1"
      127.0.0.1:6379> lset list 0 "new" # 更新值
      OK
      127.0.0.1:6379> lrange list 0 0
      1) "new"
      127.0.0.1:6379> lset list 1 "new" # index 超出范围报错
      (error) ERR index out of range
      # linsert key before/after pivot value 用于在列表的元素前或者后插入元素。
      # 将值 value 插入到列表 key 当中,位于值 pivot 之前或之后。
      redis> RPUSH mylist "Hello"
      (integer) 1
      redis> RPUSH mylist "World"
      (integer) 2
      redis> LINSERT mylist BEFORE "World" "There"
      (integer) 3
      redis> LRANGE mylist 0 -1
      1) "Hello"
      2) "There"
      3) "World"
      # 总结#它是一个字符串链表,left,right 都可以插入添加#如果键不存在,创建新的链表#如果键已存在,新增内容#如果值全移除,对应的键也就消失了#链表的操作无论是头和尾效率都极高,但假如是对中间元素进行操作,效率就很惨淡了。#list就是链表,略有数据结构知识的人都应该能理解其结构。使用Lists结构,我们可以轻松地实现最新消息排行等功能。#List的另一个应用就是消息队列,可以利用List的PUSH操作,将任务存在List中,然后工作线程再用POP操作将任务取出进行执行。#Redis还提供了操作List中某一段的api,你可以直接查询,删除List中某一段的元素。#Redis的list是每个子元素都是String类型的双向链表,可以通过push和pop操作从列表的头部或者尾部添加或者删除元素,这样List即可以作为栈,也可以作为队列。
      
  • 集合Set(单值多value)

    • # sadd 将一个或多个成员元素加入到集合中,不能重复
      # smembers 返回集合中的所有的成员。
      # sismember 命令判断成员元素是否是集合的成员。
      127.0.0.1:6379> sadd myset "hello"
      (integer) 1
      127.0.0.1:6379> sadd myset "kuangshen"
      (integer) 1
      127.0.0.1:6379> sadd myset "kuangshen"
      (integer) 0
      127.0.0.1:6379> SMEMBERS myset
      1) "kuangshen"
      2) "hello"
      127.0.0.1:6379> SISMEMBER myset "hello"
      (integer) 1
      127.0.0.1:6379> SISMEMBER myset "world"
      (integer) 0
      # scard,获取集合里面的元素个数
      127.0.0.1:6379> scard myset
      (integer) 2
      # srem key value 用于移除集合中的一个或多个成员元素
      127.0.0.1:6379> srem myset "kuangshen"
      (integer) 1
      127.0.0.1:6379> SMEMBERS myset
      1) "hello"
      # srandmember key 命令用于返回集合中的一个随机元素。
      127.0.0.1:6379> SMEMBERS myset
      1) "kuangshen"
      2) "world"
      3) "hello"
      127.0.0.1:6379> SRANDMEMBER myset
      "hello"
      127.0.0.1:6379> SRANDMEMBER myset 2
      1) "world"
      2) "kuangshen"
      127.0.0.1:6379> SRANDMEMBER myset 2
      1) "kuangshen"
      2) "hello"
      # spop key 用于移除集合中的指定 key 的一个或多个随机元素
      127.0.0.1:6379> SMEMBERS myset
      1) "kuangshen"
      2) "world"
      3) "hello"
      127.0.0.1:6379> spop myset
      "world"
      127.0.0.1:6379> spop myset
      "kuangshen"
      127.0.0.1:6379> spop myset
      "hello"
      # smove SOURCE DESTINATION MEMBER
      # 将指定成员 member 元素从 source 集合移动到 destination 集合。
      127.0.0.1:6379> sadd myset "hello"
      (integer) 1
      127.0.0.1:6379> sadd myset "world"
      (integer) 1
      127.0.0.1:6379> sadd myset "kuangshen"
      (integer) 1
      127.0.0.1:6379> sadd myset2 "set2"
      (integer) 1
      127.0.0.1:6379> smove myset myset2 "kuangshen"
      (integer) 1
      127.0.0.1:6379> SMEMBERS myset
      1) "world"
      2) "hello"
      127.0.0.1:6379> SMEMBERS myset2
      1) "kuangshen"
      2) "set2"
      #数字集合类 #差集: sdiff #交集: sinter#并集: sunion
      127.0.0.1:6379> sadd key1 "a"
      (integer) 1
      127.0.0.1:6379> sadd key1 "b"
      (integer) 1
      127.0.0.1:6379> sadd key1 "c"
      (integer) 1
      127.0.0.1:6379> sadd key2 "c"
      (integer) 1
      127.0.0.1:6379> sadd key2 "d"
      (integer) 1
      127.0.0.1:6379> sadd key2 "e"
      (integer) 1
      127.0.0.1:6379> SDIFF key1 key2 # 差集
      1) "a"
      2) "b"
      127.0.0.1:6379> SINTER key1 key2 # 交集
      1) "c"
      127.0.0.1:6379> SUNION key1 key2 # 并集
      1) "a"
      2) "b"
      3) "c"
      4) "e"
      5) "d"
      #在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。Redis还为集合提供了求交集、并集、差集等操作,可以非常方便的实现如共同关注、共同喜好、二度好友等功能,对上面的所有集合操作,你还可以使用不同的命令选择将结果返回给客户端还是存集到一个新的集合中。
      
  • 哈希Hash**(**kv模式不变,但V是一个键值对)

    • # hset、hget 命令用于为哈希表中的字段赋值 。
      # hmset、hmget 同时将多个field-value对设置到哈希表中。会覆盖哈希表中已存在的字段。
      # hgetall 用于返回哈希表中,所有的字段和值。
      # hdel 用于删除哈希表 key 中的一个或多个指定字段
      127.0.0.1:6379> hset myhash field1 "kuangshen"
      (integer) 1
      127.0.0.1:6379> hget myhash field1
      "kuangshen"
      127.0.0.1:6379> HMSET myhash field1 "Hello" field2 "World"
      OK
      127.0.0.1:6379> HGET myhash field1
      "Hello"
      127.0.0.1:6379> HGET myhash field2
      "World"
      127.0.0.1:6379> hgetall myhash
      1) "field1"
      2) "Hello"
      3) "field2"
      4) "World"
      127.0.0.1:6379> HDEL myhash field1
      (integer) 1
      127.0.0.1:6379> hgetall myhash
      1) "field2"
      2) "World"
      # hlen 获取哈希表中字段的数量。
      127.0.0.1:6379> hlen myhash
      (integer) 1
      127.0.0.1:6379> HMSET myhash field1 "Hello" field2 "World"
      OK
      127.0.0.1:6379> hlen myhash
      (integer) 2
      # hexists 查看哈希表的指定字段是否存在。
      127.0.0.1:6379> hexists myhash field1
      (integer) 1
      127.0.0.1:6379> hexists myhash field3
      (integer) 0
      # hkeys 获取哈希表中的所有域(field)。
      # hvals 返回哈希表所有域(field)的值。
      127.0.0.1:6379> HKEYS myhash
      1) "field2"
      2) "field1"
      127.0.0.1:6379> HVALS myhash
      1) "World"
      2) "Hello"
      # hincrby 为哈希表中的字段值加上指定增量值。
      127.0.0.1:6379> hset myhash field 5
      (integer) 1
      127.0.0.1:6379> HINCRBY myhash field 1
      (integer) 6
      127.0.0.1:6379> HINCRBY myhash field -1
      (integer) 5
      127.0.0.1:6379> HINCRBY myhash field -10
      (integer) -5
      # hsetnx 为哈希表中不存在的的字段赋值。
      127.0.0.1:6379> HSETNX myhash field1 "hello"
      (integer) 1 # 设置成功,返回 1。
      127.0.0.1:6379> HSETNX myhash field1 "world"
      (integer) 0 # 如果给定字段已经存在,返回 0 。
      127.0.0.1:6379> HGET myhash field1
      "hello"
      #Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。存储部分变更的数据,如用户信息等。
      
  • 有序集合Zset

    • 在set基础上,加一个score值。之前set是k1 v1 v2 v3,现在zset是 k1 score1 v1 score2 v2

    • # zadd 将一个或多个成员元素及其分数值加入到有序集当中。
      # zrange 返回有序集中,指定区间内的成员
      127.0.0.1:6379> zadd myset 1 "one"
      (integer) 1
      127.0.0.1:6379> zadd myset 2 "two" 3 "three"
      (integer) 2
      127.0.0.1:6379> ZRANGE myset 0 -1
      1) "one"
      2) "two"
      3) "three"
      # zrangebyscore 返回有序集合中指定分数区间的成员列表。有序集成员按分数值递增(从小到大) 次序排列。
      127.0.0.1:6379> zadd salary 2500 xiaoming
      (integer) 1
      127.0.0.1:6379> zadd salary 5000 xiaohong
      (integer) 1
      127.0.0.1:6379> zadd salary 500 kuangshen
      (integer) 1
      # Inf无穷大量+∞,同样地,-∞可以表示为-Inf。
      127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf# 显示整个有序集
      1) "kuangshen"
      2) "xiaoming"
      3) "xiaohong"
      127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf withscores # 递增排列
      1) "kuangshen"
      2) "500"
      3) "xiaoming"
      4) "2500"
      5) "xiaohong"
      6) "5000"
      127.0.0.1:6379> ZREVRANGE salary 0 -1 WITHSCORES # 递减排列
      1) "xiaohong"
      2) "5000"
      3) "xiaoming"
      4) "2500"
      5) "kuangshen"
      6) "500"
      127.0.0.1:6379> ZRANGEBYSCORE salary -inf 2500 WITHSCORES # 显示工资 <=2500 的所有成员
      1) "kuangshen"
      2) "500"
      3) "xiaoming"
      4) "2500"
      # zrem 移除有序集中的一个或多个成员
      127.0.0.1:6379> ZRANGE salary 0 -1
      1) "kuangshen"
      2) "xiaoming"
      3) "xiaohong"
      127.0.0.1:6379> zrem salary kuangshen
      (integer) 1
      127.0.0.1:6379> ZRANGE salary 0 -1
      1) "xiaoming"
      2) "xiaohong"
      # zcard 命令用于计算集合中元素的数量。
      127.0.0.1:6379> zcard salary
      (integer) 2
      OK
      # zcount 计算有序集合中指定分数区间的成员数量。
      127.0.0.1:6379> zadd myset 1 "hello"
      (integer) 1
      127.0.0.1:6379> zadd myset 2 "world" 3 "kuangshen"
      (integer) 2
      127.0.0.1:6379> ZCOUNT myset 1 3
      (integer) 3
      127.0.0.1:6379> ZCOUNT myset 1 2
      (integer) 2
      # zrank 返回有序集中指定成员的排名。其中有序集成员按分数值递增(从小到大)顺序排列。
      127.0.0.1:6379> zadd salary 2500 xiaoming
      (integer) 1
      127.0.0.1:6379> zadd salary 5000 xiaohong
      (integer) 1
      127.0.0.1:6379> zadd salary 500 kuangshen
      (integer) 1
      127.0.0.1:6379> ZRANGE salary 0 -1 WITHSCORES # 显示所有成员及其 score 值
      1) "kuangshen"
      2) "500"
      3) "xiaoming"
      4) "2500"
      5) "xiaohong"
      6) "5000"
      127.0.0.1:6379> zrank salary kuangshen # 显示 kuangshen 的薪水排名,最少
      (integer) 0
      127.0.0.1:6379> zrank salary xiaohong # 显示 xiaohong 的薪水排名,第三
      (integer) 2
      # zrevrank 返回有序集中成员的排名。其中有序集成员按分数值递减(从大到小)排序。
      127.0.0.1:6379> ZREVRANK salary kuangshen # 狂神第三
      (integer) 2
      127.0.0.1:6379> ZREVRANK salary xiaohong # 小红第一
      (integer) 0
      #和set相比,sorted set增加了一个权重参数score,使得集合中的元素能够按score进行有序排列,比如一个存储全班同学成绩的sorted set,其集合value可以是同学的学号,而score就可以是其考试得分,这样在数据插入集合的时候,就已经进行了天然的排序。可以用sorted set来做带权重的队列,比如普通消息的score为1,重要消息的score为2,然后工作线程可以选择按score的倒序来获取工作任务。让重要的任务优先执行。排行榜应用,取TOP N操作 !
      

三种特殊数据类型

  • GEO地理位置

    • #Redis 的 GEO 特性在 Redis 3.2 版本中推出, 这个功能可以将用户给定的地理位置信息储存起来, 并对这些信息进行操作。来实现诸如附近位置、摇一摇这类依赖于地理位置信息的功能。geo的数据类型为zset。
      #GEO 的数据结构总共有六个常用命令:geoadd、geopos、geodist、georadius、georadiusbymember、gethash
      #官方文档:https://www.redis.net.cn/order/3685.html
      # 语法 geoadd key longitude latitude member ...
      # 将给定的空间元素(纬度、经度、名字)添加到指定的键里面。
      # 这些数据会以有序集he的形式被储存在键里面,从而使得georadius和georadiusbymember这样的命令可以在之后通过位置查询取得这些元素。
      # geoadd命令以标准的x,y格式接受参数,所以用户必须先输入经度,然后再输入纬度。
      # geoadd能够记录的坐标是有限的:非常接近两极的区域无法被索引。
      # 有效的经度介于-180-180度之间,有效的纬度介于-85.05112878 度至 85.05112878 度之间。当用户尝试输入一个超出范围的经度或者纬度时,geoadd命令将返回一个错误。
      127.0.0.1:6379> geoadd china:city 116.23 40.22 北京
      (integer) 1
      127.0.0.1:6379> geoadd china:city 121.48 31.40 上海 113.88 22.55 深圳 120.21 30.20 杭州
      (integer) 3
      127.0.0.1:6379> geoadd china:city 106.54 29.40 重庆 108.93 34.23 西安 114.02 30.58 武汉
      (integer) 3
      # 语法 geopos key member [member...]
      #从key里返回所有给定位置元素的位置(经度和纬度)
      127.0.0.1:6379> geopos china:city 北京
      1) 1) "116.23000055551528931" 2) "40.2200010338739844"
      127.0.0.1:6379> geopos china:city 上海 重庆
      1) 1) "121.48000091314315796" 2) "31.40000025319353938"2) 1) "106.54000014066696167"2) "29.39999880018641676"
      127.0.0.1:6379> geopos china:city 新疆 1) (nil)
      # 语法 geodist key member1 member2 [unit]
      # 返回两个给定位置之间的距离,如果两个位置之间的其中一个不存在,那么命令返回空值。
      # 指定单位的参数unit必须是以下单位的其中一个:
      # m表示单位为米 # km表示单位为千米 # mi表示单位为英里 # ft表示单位为英尺
      # 如果用户没有显式地指定单位参数,那么geodist默认使用米作为单位。
      #geodist命令在计算距离时会假设地球为完美的球形,在极限情况下,这一假设最大会造成0.5%的误差。
      127.0.0.1:6379> geodist china:city 北京 上海
      "1088785.4302"
      127.0.0.1:6379> geodist china:city 北京 上海 km
      "1088.7854"
      127.0.0.1:6379> geodist china:city 重庆 北京 km
      "1491.6716"
      # 语法
      # georadius key longitude latitude radius m|km|ft|mi [withcoord][withdist] [withhash][asc|desc][count count]
      # 以给定的经纬度为中心, 找出某一半径内的元素
      ####测试:重新连接 redis-cli,增加参数 --raw ,可以强制输出中文,不然会乱码
      [root@kuangshen bin]# redis-cli --raw -p 6379
      # 在 china:city 中寻找坐标 100 30 半径为 1000km 的城市
      127.0.0.1:6379> georadius china:city 100 30 1000 km
      重庆
      西安
      # withdist 返回位置名称和中心距离
      127.0.0.1:6379> georadius china:city 100 30 1000 km withdist
      重庆
      635.2850
      西安
      963.3171
      # withcoord 返回位置名称和经纬度
      127.0.0.1:6379> georadius china:city 100 30 1000 km withcoord
      重庆
      106.54000014066696167
      29.39999880018641676
      西安
      108.92999857664108276
      34.23000121926852302
      # withdist withcoord 返回位置名称 距离 和经纬度 count 限定寻找个数
      127.0.0.1:6379> georadius china:city 100 30 1000 km withcoord withdist count 1
      重庆
      635.2850
      106.54000014066696167
      29.39999880018641676
      127.0.0.1:6379> georadius china:city 100 30 1000 km withcoord withdist count 2
      重庆
      635.2850
      106.54000014066696167
      29.39999880018641676
      西安
      963.3171
      108.92999857664108276
      34.23000121926852302
      # 语法
      # georadiusbymember key member radius m|km|ft|mi [withcoord][withdist] [withhash][asc|desc][count count]
      # 找出位于指定范围内的元素,中心点是由给定的位置元素决定
      127.0.0.1:6379> GEORADIUSBYMEMBER china:city 北京 1000 km
      北京
      西安
      127.0.0.1:6379> GEORADIUSBYMEMBER china:city 上海 400 km
      杭州
      上海
      # 语法
      # geohash key member [member...]
      # Redis使用geohash将二维经纬度转换为一维字符串,字符串越长表示位置更精确,两个字符串越相似 表示距离越近。
      127.0.0.1:6379> geohash china:city 北京 重庆
      wx4sucu47r0
      wm5z22h53v0
      127.0.0.1:6379> geohash china:city 北京 上海
      wx4sucu47r0
      wtw6sk5n300
      #GEO没有提供删除成员的命令,但是因为GEO的底层实现是zset,所以可以借用zrem命令实现对地理位置信息的删除.
      127.0.0.1:6379> geoadd china:city 116.23 40.22 beijin
      1
      127.0.0.1:6379> zrange china:city 0 -1 # 查看全部的元素
      重庆
      西安
      深圳
      武汉
      杭州
      上海
      beijin
      北京
      127.0.0.1:6379> zrem china:city beijin # 移除元素
      1
      127.0.0.1:6379> zrem china:city 北京 # 移除元素
      1
      127.0.0.1:6379> zrange china:city 0 -1
      重庆
      西安
      深圳
      武汉
      杭州
      上海
      
  • HyperLogLog

    • 简介
      Redis在2.8.9版本添加了HyperLogLog结构。
      Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。
      在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。HyperLogLog则是一种算法,它提供了不精确的去重计数方案。
      举个栗子:
      假如我要统计网页的UV(浏览用户数量,一天内同一个用户多次访问只能算一次),传统的解决方案是使用Set来保存用户id,然后统计Set中的元素数量来获取页面UV。但这种方案只能承载少量用户,一旦用户数量大起来就需要消耗大量的空间来存储用户id。我的目的是统计用户数量而不是保存用户,这简直是个吃力不讨好的方案!而使用Redis的HyperLogLog最多需要12k就可以统计大量的用户数,尽管它大概有0.81%的错误率,但对于统计UV这种不需要很精确的数据是可以忽略不计的。
      什么是基数?
      比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素)为5。基数估计就是在误差可接受的范围内,快速计算基数。
      基本命令
      命令 描述
      [PFADD key element [element ...] 添加指定元素到 HyperLogLog 中。
      [PFCOUNT key [key ...] 返回给定 HyperLogLog 的基数估算值。
      [PFMERGE destkey sourcekey [sourcekey ...]将多个 HyperLogLog 合并为一个 HyperLogLog,并集计算
      
    • 127.0.0.1:6379> PFADD mykey a b c d e f g h i j
      1
      127.0.0.1:6379> PFCOUNT mykey
      10
      127.0.0.1:6379> PFADD mykey2 i j z x c v b n m
      1
      127.0.0.1:6379> PFMERGE mykey3 mykey mykey2
      OK
      127.0.0.1:6379> PFCOUNT mykey3 15
      
  • BitMap

    • 简介
      在开发中,可能会遇到这种情况:需要统计用户的某些信息,如活跃或不活跃,登录或者不登录;又如需要记录用户一年的打卡情况,打卡了是1, 没有打卡是0,如果使用普通的 key/value存储,则要记录365条记录,如果用户量很大,需要的空间也会很大,所以 Redis 提供了 Bitmap 位图这中数据结构,Bitmap 就是通过操作二进制位来进行记录,即为 0 和 1;如果要记录 365 天的打卡情况,使用 Bitmap表示的形式大概如下0101000111000111...........................,这样有什么好处呢?当然就是节约内存了,365 天相当于 365 bit,又 1 字节 = 8 bit , 所以相当于使用 46 个字节即可。BitMap 就是通过一个 bit 位来表示某个元素对应的值或者状态, 其中的 key 就是对应元素本身,实际上底层也是通过对字符串的操作来实现。Redis 从 2.2 版本之后新增了setbit, getbit, bitcount 等几个bitmap相关命令。
      
    • #setbit 设置操作
      #SETBIT key offset value : 设置 key 的第 offset 位为value (1或0)
      # 使用 bitmap 来记录上述事例中一周的打卡记录如下所示: # 周一:1,周二:0,周三:0,周四:1,周五:1,周六:0,周天:0 (1 为打卡,0 为不打卡)
      127.0.0.1:6379> setbit sign 0 1
      0
      127.0.0.1:6379> setbit sign 1 0
      0
      127.0.0.1:6379> setbit sign 2 0
      0
      127.0.0.1:6379> setbit sign 3 1
      0
      127.0.0.1:6379> setbit sign 4 1
      0
      127.0.0.1:6379> setbit sign 5 0
      0
      127.0.0.1:6379> setbit sign 6 0
      0
      #getbit 获取操作
      #GETBIT key offset 获取offset设置的值,未设置过默认返回0
      127.0.0.1:6379> getbit sign 3 # 查看周四是否打卡
      1
      127.0.0.1:6379> getbit sign 6 # 查看周日是否打卡
      0
      #bitcount 统计操作
      #bitcount key [start, end] 统计 key 上位为1的个数
      # 统计这周打卡的记录,可以看到只有3天是打卡的状态:
      127.0.0.1:6379> bitcount sign
      3
      

----狂神视频学习笔记

Redis(上)基础及8种数据类型相关推荐

  1. RedisUtil - Redis功能介绍,五种数据类型的使用,Spring和Redis的集成

    RedisUtil 介绍  最全的Java操作Redis的工具类,封装了对Redis五种基本类型的各种操作,力求符合Redis的原生操作,使用StringRedisTemplate实现! 快速导航: ...

  2. Redis的6种数据类型

    Redis 是一种基于内存的数据库,并且提供一定的持久化功能,它是一种键值(key-value)数据库,使用 key 作为索引找到当前缓存的数据,并且返回给程序调用者. 当前的 Redis 支持 6 ...

  3. Redis5种数据类型使用场景梳理

    Redis在我们日常工作中使用的非常频繁,但是很多同学只会使用string类型,那么今天笔者梳理下redis中常用的5种数据类型,分别适用于哪些业务场景和基本操作,让大家以后能够在合适的缓存场景使用合 ...

  4. Redis笔记基础篇:6分钟看完Redis的八种数据类型

    目录 一.常识补充 二.安装 三.启动redis 四.常用基础命令 五.Redis五大基本数据类型 5.1.String 5.2.Hash 5.3.List 5.4.Set 5.5.Zset 六.三大 ...

  5. Redis的数据类型以及每种数据类型的使用场景

    人就是很奇怪的动物,很简单的问题往往大家都容易忽略,当我们在使用分布式缓存Redis的时候,一个最简单的问题往往被人忽略,Redis的数据类型以及每种数据类型的使用场景是什么? 是不是觉得这个问题很基 ...

  6. (转) 淘淘商城系列——Redis五种数据类型介绍

    http://blog.csdn.net/yerenyuan_pku/article/details/72855562 Redis支持五种数据类型:string(字符串),hash(哈希),list( ...

  7. android平台上持久化存储3种手段_深入学习Redis :持久化

    前言 在上一篇文章中,介绍了Redis的内存模型,从这篇文章开始,将依次介绍Redis高可用相关的知识--持久化.复制(及读写分离).哨兵.以及集群. 本文将先说明上述几种技术分别解决了Redis高可 ...

  8. Redis五种数据类型介绍

    概述 Redis的键值可以使用物种数据类型:字符串,散列表,列表,集合,有序集合.本文详细介绍这五种数据类型的使用方法.本文命令介绍部分只是列举了基本的命令,至于具体的使用示例,可以参考Redis官方 ...

  9. Redis常用的五种数据类型

    转载 [Redis]五种数据类型及其使用场景 https://blog.csdn.net/zzu_seu/article/details/106323114?spm=1001.2101.3001.66 ...

最新文章

  1. WhatsApp用户数突破10亿 每天发送消息420亿条
  2. (已解决)linux如何删除-开头的文件或者目录
  3. 【✈️️️排序算法,一文讲尽!Top 10 Sort Algorithms✈️️️】C/C++ 实现经典十大排序算法
  4. IOS开发基础之单例模式
  5. C# lock 语法糖实现原理--《.NET Core 底层入门》之自旋锁,互斥锁,混合锁,读写锁...
  6. Python处理csv文件
  7. nginx 电子书_13本免费的电子书,拿走,不谢
  8. 一颗接一颗的飞鸽传书
  9. 计算机网络之物理层:2、码元、速率、带宽、波特
  10. unslider.js 实现移动web轮播
  11. 电子海图信息系统 (ECDIS)的发展及应用
  12. win32项目--获取、修改计算机屏幕分辨率
  13. 2017江苏高职计算机分数线,2017年江苏高考分数线公布
  14. 《Constrained Convolutional Neural Networks for Weakly Supervised Segmentation》翻译
  15. 上海交大ACM班俞勇团队出新书了!
  16. NAB展会BOSMA博冠8K全系8K摄像机产品惊艳亮相
  17. Excel制作四分位图
  18. Java简单的记账本项目
  19. 什么是EJB?EJB是基于哪些技术实现的?
  20. Qt使用三点坐标画圆弧

热门文章

  1. SASE , sdp等
  2. 51单片机(四).C51编程语言
  3. Mac平台配置OpenGL(glut,glew)
  4. 嵌入式系统基本概念(硬件篇)
  5. Canvas和SVG的区别
  6. Linux——挂载硬盘
  7. outlook导出邮件(.msg)读取和解析
  8. 电路基础知识之什么是共模电感/共模信号/差分信号?
  9. 可控硅失效现象_晶闸管常见损坏原因分析(全)
  10. java计算机毕业设计Web网上购书后台管理系统(附源码、数据库)