Redis基础知识、应用场景、集群安装

wuchangjian2021-11-04 08:22:56编程学习

Redis基础知识、应用场景、安装

  • 介绍
  • Redis基础知识
    • 基础数据类型
      • string
        • 示例
        • 用途
      • list
        • 用途
        • 示例
      • hash
      • set
      • zset
    • list/set/hash/zset通用规则
    • 失效时间
  • 应用场景
    • 分布式锁
    • 延时队列
    • 位图
    • 布隆过滤器
  • 集群安装
    • 环境
    • 实施步骤

介绍

Redis是Remote Dictionary Service的首字母缩写,也就是“远程字典服务”。

Redis基础知识

基础数据类型

Redis有5种基础数据结构,分别为:string(字符串)、list(列表)、set(集合)、hash(哈希)和zset(有序集合)。
Redis所有的数据结构都是以唯一的key字符串作为名称,然后通过这个唯一key值来获取相应的value数据。不同类型的数据结构的差异就在于value的结构不一样。

string

字符串string是Redis最简单的数据结构。
在这里插入图片描述

Redis 的字符串是动态字符串,是可以修改的字符串,内部结构实现上类似于 Java 的 ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配,如图中所示,内部为当前字符串实际分配的空间 capacity 一般要高于实际字符串长度 len。当字符串长度小于 1M 时,扩容都是加倍现有的空间,如果超过 1M,扩容时一次只会多扩 1M 的空间。需要注意的是字符串最大长度为 512M。

示例

  • 键值对示例:

在这里插入图片描述

  • 批量键值对示例:

在这里插入图片描述
在这里插入图片描述

用途

  • 缓存用户信息,将用户信息结构体使用JSON序列化成字符串,然后进行缓存。

  • 计数,value整数的范围是signed long的最大最小值。使用incr命令。

list

Redis列表相当于Java语言里面的LinkedList,注意它是链表而不是数组。这意味着list的插入和删除操作非常快,时间复杂度为O(1),但是索引定位很慢,时间复杂度为O(n)。
当列表弹出了最后一个元素之后,该数据结构自动被删除,内存被回收。
Redis的列表结构常用来做异步队列使用。将需要延后处理的任务结构体序列化成字符串塞进Redis的列表,另一个线程从这个列表中轮询数据进行处理。

用途

  • 常用来做异步队列使用,将需要延后处理的任务结构体序列化成字符串塞进Redis的列表,另一个线程从这个列表中轮询数据进行处理。

示例

  • 右进左出:队列

在这里插入图片描述

  • 右进右出:栈

在这里插入图片描述

  • 慢操作

lindex相当于Java链表的get(int index)方法,它需要对链表进行遍历,性能随着参数index增大而变差。
ltrim和字面上的含义不太一样,ltrim的两个参数start_index和end_index定义了一个区间,在这个区间内的值,ltrim要保留,区间外都砍掉。我们可以通过ltrim实现一个定长的链表。
index可以为负数,index=-1表示倒数第一个元素,同样index=-2表示倒数第二个元素。

127.0.0.1:6379> rpush books python java golang
(integer) 3
127.0.0.1:6379> lindex books 1
"java"
127.0.0.1:6379> lrange books 0 -1 #获取所有元素,0(n)慎用
1) "python"
2) "java"
3) "golang"
127.0.0.1:6379> ltrim books 1 -1
OK
127.0.0.1:6379> lrange books 0 -1
1) "java"
2) "golang"
127.0.0.1:6379> ltrim books 1 0 #这其实是清空了整个列表,因为区间范围长度为负
OK
127.0.0.1:6379> llen books
(integer) 0

hash

Redis的字典相当于Java语言里面的HashMap,它是无序字典。内部实现结构上同Java的HashMap也是一致的,同样的数组+链表二维结构。第一维hash的数组位置碰撞时,就会将碰撞的元素使用链表串接起来。

不同的是,Redis的字典的值只能是字符串,另外它们rehash的方式不一样,因为Java的HashMap在字典很大时,rehash是个耗时的操作,需要一次性全部rehash。Redis为了高性能,不能堵塞服务,所以采用了渐进式rehash策略。

渐进式rehash会在rehash的同时,保留新旧两个hash结构,查询时会同时查询两个hash结构,然后在后续的定时任务中以及hash操作指令中,循序渐进地将旧hash的内容一点点迁移到新的hash结构中。当搬迁完成了,就会使用新的hash结构取而代之。

当hash移除了最后一个元素之后,该数据结构自动被删除,内存被回收。

hash结构也可以用来存储用户信息,不同于字符串一次性需要全部序列化整个对象,hash可以对用户结构中的每个字段单独存储。这样当我们需要获取用户信息时可以进行部分获取。而以整个字符串的形式去保存用户信息的话就只能一次性全部读取,这样就会比较浪费网络流量。

127.0.0.1:6379> hset books java "think in java"
(integer) 1
127.0.0.1:6379> hset books golang "concurrency in go"
(integer) 1
127.0.0.1:6379> hset books python "python cookbook"
(integer) 1
127.0.0.1:6379> hgetall books
1) "java"
2) "think in java"
3) "golang"
4) "concurrency in go"
5) "python"
6) "python cookbook"
127.0.0.1:6379> hlen books
(integer) 3
127.0.0.1:6379> hget books java
"think in java"
127.0.0.1:6379> hget books golang
"concurrency in go"
127.0.0.1:6379> hset books golang "learning go programming"
(integer) 0
127.0.0.1:6379> hget books golang
"learning go programming"

set

Redis的集合相当于Java语言里面的HashSet,它内部的键值对是无序的惟一的。它的内部实现相当于一个特殊的字典,字典中所有的value都是一个值NULL。

当集合中最后一个元素移除之后,数据结构自动删除,内存被回收。

set结构可以用来存储活动中奖的用户ID,因为有去重功能,可以保证同一个用户不会中奖两次。

127.0.0.1:6379> sadd users lzx1
(integer) 1
127.0.0.1:6379> sadd users lzx1
(integer) 0
127.0.0.1:6379> sadd users fl1 zmx1
(integer) 2
127.0.0.1:6379> smembers users
1) "lzx1"
2) "fl1"
3) "zmx1"
127.0.0.1:6379> sismember users lzx1
(integer) 1
127.0.0.1:6379> sismember users zlm1
(integer) 0
127.0.0.1:6379> scard users
(integer) 3
127.0.0.1:6379> spop users
"lzx"
127.0.0.1:6379>

zset

zset可能是Redis提供的最为特色的数据结构。它类似于Java的SortedSet和HashMap的结合体,一方面它是一个set,保证了内部value的唯一性,另一方面它可以给每个value赋予一个score,代表这个value的排序权重。它的内部实现用的是一种叫做[跳跃列表]的数据结构。

zset中最后一个value被移除后,数据结构自动删除,内存被回收。

zset可以用来存粉丝列表,value值是粉丝的用户ID,score是关注时间。我们可以对粉丝列表按关注时间进行排序。

zset可以用来存储学生的成绩,value值是学生的ID,score是他的考试成绩。我们可以对成绩按分数进行排序就可以得到他的名次。

127.0.0.1:6379> zadd students 89 lzx1
(integer) 1
127.0.0.1:6379> zadd students 91 zlm1
(integer) 1
127.0.0.1:6379> zadd students 94 tyr1
(integer) 1
127.0.0.1:6379> zadd students 98 zyb1
(integer) 1
127.0.0.1:6379> zrange students 0 -1
1) "lzx1"
2) "zlm1"
3) "tyr1"
4) "zyb1"
127.0.0.1:6379> zrevrange students 0 -1
1) "zyb1"
2) "tyr1"
3) "zlm1"
4) "lzx1"
127.0.0.1:6379> zscore students lzx1
"89"
127.0.0.1:6379> zrank students zlm1
(integer) 1
127.0.0.1:6379> zrank students tyr1
(integer) 2
127.0.0.1:6379> zrank students lzx1
(integer) 0
127.0.0.1:6379> zrangebyscore students 0 95
1) "lzx1"
2) "zlm1"
3) "tyr1"
127.0.0.1:6379> zrangebyscore students -inf 95 withscores
1) "lzx1"
2) "89"
3) "zlm1"
4) "91"
5) "tyr1"
6) "94"
127.0.0.1:6379> zrem students "lzx1"
(integer) 1
127.0.0.1:6379> zrange students 0 -1
1) "zlm1"
2) "tyr1"
3) "zyb1"

list/set/hash/zset通用规则

  • create if not exists

如果容器不存在,那就创建一个,再进行操作。比如rpush操作刚开始是没有列表的,Redis就会自动创建一个,然后再rpush进去新元素。

  • drop if no elements

如果容器里元素没有了,那么立即删除元素,释放内存。这意味着lpop操作到最后一个元素,列表就消失了。

失效时间

Redis所有的数据结构都可以设置过期时间,时间到了,Redis会自动删除相应的对象。需要注意的是过期是以对象为单位,比如一个hash结构的过期是整个hash对象的过期,而不是其中的某个子key。
特别注意的一个地方,如果一个字符串已经设置了过期时间,然后你调用了set方法修改了它,它的过期时间会消失。

应用场景

分布式锁

通常单应用进行单进程部署时,我们可以通过同步锁的机制来处理并发带来的同步问题。随着应用系统越来越复杂,传统的单应用单进程部署已经变成了分布式多应用多进程部署了,随之而来的数据同步问题就得需要分布式锁来实现了。

分布式锁本质上要实现的目标就是在Redis里面占一个“茅坑”,当别的进程也要来占时,发现已经有人蹲在那里了,就只好放弃或者稍后再试。
Redis2.8版本中作者加入了set指令的扩展参数,使得setnx和expire指令可以一起执行。

延时队列

  • 异步消息对列:先进先出

Redis的list数据结构常用来作为异步消息队列使用,使用rpush/lpush入队列,使用lpop和rpop出队列。

127.0.0.1:6379> rpush notify-queue apple banana pear
(integer) 3
127.0.0.1:6379> llen notify-queue
(integer) 3
127.0.0.1:6379> lpop notify-queue
"apple"
127.0.0.1:6379> lpop notify-queue
"banana"
127.0.0.1:6379> lpop notify-queue
"pear"
127.0.0.1:6379> llen notify-queue
(integer) 0
127.0.0.1:6379> lpop notify-queue
(nil)

位图

位图不是特殊的数据结构,它的内容其实就是普通的字符串,也就是 byte 数组。我们可以使用普通的 get/set 直接获取和设置整个位图的内容,也可以使用位图操作 getbit/setbit 等将 byte 数组看成「位数组」来处理。

布隆过滤器

应用场景:新闻客户端推荐系统实现推送去重功能。
布隆过滤器(Bloom Filter)专门用来解决这类去重问题,它在起到去重的同时,在空间上还能节省90%以上,只是会稍微有那么点不精确,有一定的误判概率。

集群安装

环境

操作系统:centos6.5
redis:3.2.8
服务器:192.168.0.112和192.168.0.214,每台服务器三个节点

实施步骤

1、解压

[root@localhost src]# tar –zxvf redis-3.2.8.tar.gz

2、编译、安装

[root@localhost src]# cd redis-3.2.8
[root@localhost src]# make && make install

3、复制redis-trib.rb到/usr/local/bin

[root@localhost src]# cd src
[root@localhost src]# cp redis-trib.rb /usr/local/bin/

4、创建redis节点
在/usr/local/redis-3.2.8下创建redis_cluster目录;

[root@localhost src]# cd ..
[root@localhost redis-3.2.8]# mkdir redis_cluster

在redis_cluster目录下,创建名为7000、7001、7002的目录,并将redis.conf拷贝到这三个目录中;

[root@localhost redis-3.2.8]# cd redis_cluster/
[root@localhost redis_cluster]# mkdir 7000 7001 7002
[root@localhost redis-3.2.8]# cp redis.conf redis_cluster/7000
[root@localhost redis-3.2.8]# cp redis.conf redis_cluster/7001
[root@localhost redis-3.2.8]# cp redis.conf redis_cluster/7002

分别修改这三个配置文件,修改如下内容

port 7000  //端口7000,7002,7003
bind 192.168.0.112  //默认127.0.0.1
daemonize yes  //redis后台运行
pidfile /var/run/redis_7000.pid  //pid文件
appendonly yes  //aof日志开启,每次写操作都记录一条日志
cluster-enabled yes  //开启集群
cluster-config-file nodes-7000.conf //集群的配置,首次启动生成7000,……
cluster-node-timeout 15000 //请求超时,默认15秒,可修改

5、启动各节点

# 192.168.0.112 服务器
[root@localhost redis-3.2.8]# redis-server redis_cluster/7000/redis.conf 
[root@localhost redis-3.2.8]# redis-server redis_cluster/7001/redis.conf 
[root@localhost redis-3.2.8]# redis-server redis_cluster/7002/redis.conf
# 192.168.0.214 服务器
[root@localhost redis-3.2.8]# redis-server redis_cluster/7003/redis.conf 
[root@localhost redis-3.2.8]# redis-server redis_cluster/7004/redis.conf 
[root@localhost redis-3.2.8]# redis-server redis_cluster/7005/redis.conf

相关文章

17~19日湖南“烧烤”模式延续,局地最高气温可达40℃以上

2022-08-17 18:52:48 预计未来三天(8月17日至19...

ndk-build.cmd‘‘ finished with non-zero exit value 2

具体错误: Execution failed for task '...

走进县城看发展 | 常宁:聚焦品牌建设,走出高质量发展之路

走进县城看发展 | 常宁:聚焦品牌建设,走出高质量发展之路

2022-08-16 15:07:48 如果给城市贴上“标签”,位于湖...

用AVE和GAN生成图像

AVE相当于把图片压缩在解压的感觉。 自编码器       x ——编码器——z——解...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。