Redis学习笔记

发布于:2022-07-26 ⋅ 阅读:(377) ⋅ 点赞:(0)

?redis概述

  • redis介绍

Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用C语言编写、可基于内存亦可持久化的Key-Value数据库。

Redis是一个开源的数据结构存储系统,它可以用作:数据库、缓存和消息中间件。

端口:6379
默认16个数据库,下标从0开始。
Redis是单线程+io多路复用。每秒读11万次,写8万次

  • 为什么使用redis?

从性能和并发两个角度考虑:

性能方面-----我们在碰到需要执行耗时特别久,且结果不频繁变动的SQL,就特别适合将运行结果放入缓存。这样,后面的请求就去缓存中读取,使得请求能够迅速响应

并发方面-----在大并发的情况下,所有的请求直接访问数据库,数据库会出现连接异常。这个时候,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问数据库。

  • redis为什么这么快
  1. Redis 将数据储存在内存里面,读写数据的时候都不会受到硬盘 I/O 速度的限制,所以速度极快。
  2. 数据结构简单,对数据操作也简单。
  3. 采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗CPU,不用去考虑各种锁的问题。

硬盘数据库的工作模式:

内存数据库工作模式:

?redis安装、启动、关闭

(1)先到redis官网(redis.io)下载最新版的redis压缩包到本地

(2)把本地的压缩包上传到 Linux 的 opt / software 目录下

(3)下载安装C语言编译环境,gcc编译器:yum install gcc

(4)解压压缩包:tar -zxvf redis-6.2.1.tar.gz

(5)解压完成后进入redis目录,进行编译:make,编译完成进行安装:make install

(6)安装在 /usr/local/redis 目录下,安装好后bin目录下有六个文件

文件 作用
redis-benchmark 性能测试工具
redis-check-aof 修复有问题的AOF文件
redis-check-dump 修复有问题的dump.rdb文件
redis-sentinel Redis集群使用
redis-server 服务器启动命令
redis-cli 客户端操作入口

(7)把 /opt/redis目录下的redis.conf 复制到 etc 下:cp redis.conf /etc/redis.conf

(8)将 redis.conf 里的 daemonize no 改成 yes(改成后台启动)

(8)启动 redis:redis-server /etc/redis.conf

(9)启动完成通过ps查看进程:ps -ef | grep redis

jaOtZF.png

(10)启动后通过客户端连接redis:redis-cli

jaOcZD.png

(11)单实例关闭:redis-cli shutdown

(12)多实例关闭(指定一个端口):redis-cli -p 6379 shutdown

?数据类型

  • 五大数据类型
类型 说明 用途
String redis中最基本的类型。
value可以包含任何数据,比如jpg图片和序列化的对象
一般做一些复杂的计数功能的缓存。
Hash 键值对集合,适合于对象的存储 在做单点登录的时候,存储用户信息。
List 双向链表。使用List的数据结构,列表用来存储多个有序的字符串 消息队列
Set 堆放的是一堆不重复值的集合。 可以做全局去重的功能。
Zset Zset多了一个权重参数score,集合中的元素能够按score进行排列。 可以做排行榜应用,取TOP N操作。
  • 三种特殊数据类型
类型 说明 用途
Geospatial(Geo) 地理位置 朋友定位,附近的人,两地之间的距离
Hyperloglog 基数统计 网站的访问人数
Bitmaps 位存储,用0和1表示状态 用户签到,用户在线状态

基数统计的概念: 比如数据集 {1, 2, 3, 3, 5, 5,}, 那么这个数据集的基数集为 {1,2,3,5}, 基数(不重复元素)为4。也就是说是不重复元素的个数。

?redis的常用操作

  • 通用操作
  • 切换数据库:select index

jwlMeP.md.png

  • 查看当前数据库key的数量:dbsize

  • 查看当前库中所有的key:keys *

jwGiXd.png

  • 清空当前库:flushdb

  • 清空所有库:flushall

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Av8XQ314-1658825002450)(https://s1.ax1x.com/2022/07/07/jwNF8f.png)]

  • 判断某个key是否存在:exists key

  • 查看key的类型:type key

  • 删除指定的key:del key

jwJ3xe.png

  • 给指定的key设置过期时间(单位:秒):expire key 10

  • 查看还有多少秒过期(-1表示永不过期,-2表示已过期):ttl key

jwYzt0.png

==注意:==设置了过期时间的key过期后则不存在,未设置过期时间的key是永不过期

  • String 操作(key-String)
  • 设置key-value:set stringkey value

  • 通过key拿到value:get stringkey

jw85kV.png

  • 同时添加多个key-value:mset stringkey1 value1 stringkey2 value2……
  • 同时获取多个key的value:mget stringkey1 stringkey2 stringkey3

jwsudS.png

  • 获取指定的key的value范围的值:getrange stringkey sindex eindex
  • 替换指定key某个位置开始的值:setrange stringkey index value

  • 给指定的key的value末尾追加值(key不存在时新增):append stringkey value
  • 获得指定key对应value的长度:strlen stringkey
  • 当key不存在时添加key-value:setnx stringkey value
  • 给指定key中数字值增1/减1(只对数字值操作):incr / decr stringkey
  • 给指定的key中数字自定义步长增减:incrby / decrby stringkey 步长
  • List 操作(Key-List)

==注意:==列表操作命令都是 l 开头

  • 将一个值或多个值插入列表的头部(多个值用空格分隔):lpush listKey v1 [v2 ……]

  • 将一个值或多个值插入列表的尾部:rpush listKey v1 [v2 ……]

  • 获取列表的全部值:lrange listKey 0 -1

  • 获取列表的指定索引的值:lrange listKey sindex eindex

  • 获取列表的指定索引的值:lindex listKey index

  • 查看列表的长度:llen listKey

  • 截取列表的指定索引的值:ltrim listKey sindex eindex

jTQe4x.png

  • 将列表指定索引的值替换为另一个值:lset listKey index value

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2HGH0KAF-1658825002454)(https://s1.ax1x.com/2022/07/19/jTQ1DH.png)]

  • 在指定列表某value前后插入其他value:linset listKey brfore|after value othervalue

jTQ3bd.png

  • Set 操作(Key-Set)
  • 添加一个或多个值到 set(多个值用空格分隔):sadd setKey v1 [v2 ……]

  • 查看 set 的全部值:smembers setKey

  • 查看某个值是否在set中:sismember setKey value

j7m9tf.png

  • 获取 set 中值的个数:scard setKey

  • 移除 set 某个值:srem setKey value

j7mi9S.png

  • 从 set 中随机抽选出 n 个值(n不写默认为一个):srandmember setKey n

  • 从 set 中随机移除 n 个值:spop setKey n

  • Hsah 操作(Key-Map)
  • 添加一个或多个值到 Hash 中(多个kv用空格分隔):hset hashKey k1 v1 [k1 v1 ……]

  • 获取 Hash 中的某个key:hget hashKey key

j7mVns.png

  • 获取 Hash 中所有的kv:hgetall hashKey

  • 移除 Hash 中的一个或多个key:hdel hashKey key

  • 查看 Hash 里面有多少个kv:hlen hashKey

j7ml3F.png

  • 判断Hash中某的key是否存在:hexists hashKey key
  • Zset 操作(key-SortSet)
  • 添加一个或多个值到 zset(n表示排序):zadd zsetKey n1 v1 [n2 v2 ……]

  • 获取指定索引范围内 zset 值(0 -1表示所有值):zrange zsetkey sindex eindex

  • 给 zset 进行排序(+/- inf 正/负无穷):zrangebyscore zsetKey -inf +inf

  • 获取集合中元素个数:zcard zsetKey
  • Geospatial 操作
  • 将指定的地理空间位置(纬度、经度、名称)添加到指定的key中:geoadd key 纬度 经度 地点名

  • 从key里返回指定位置元素的位置(经度和纬度):geopos key 地点名称

  • 返回两个地点之间的距离(如果一个不存在则返回空):geodist key 地点1 地点2 单位

  • 以给定的经纬度为中心, 找出某一半径内的元素:georadius key 纬度 经度 数值范围 单位

  • 找出给定的位置元素指定范围内的元素:georadiusbymember key 地点名 数值范围 单位

  • 删除指定key下指定目标的数据:zrem key 地点
  • Heyperloglog 操作
  • 添加指定元素到 HyperLogLog 中:pfadd key element [element ……]

  • 返回给定 HyperLogLog 的基数估算值:pfcount key

  • Bitmaps 操作
  • 添加一个值到 bitmaps:setbit key offset value

  • 从 bitmaps 中取值:getbit key offset

  • 统计为1的数量(没start和end时默认统计全部):bitcount key [start end]

?redis的配置

本机redis配置文件 redis.conf 拷贝在 /etc 目录下

  • 单位

开头定义了一些基本的度量单位,只支持bytes,不支持bit

  • 网络

(1)默认情况下 bind = 127.0.0.1 只能接受本机的访问请求。

(2)protected-mode yes 表示只能本机访问,不能远程访问。

==注意:==生产环境肯定要写你应用服务器的地址;服务器是需要远程访问的,所以需要将其注释掉。并且将protected-mode改为no

(3)port = 6379 redis的默认端口号

(4)timeout = 0 设置超时时间(客户端维持多少秒会关闭),0为永不超时

(5)tcp-keepalive 300 对访问客户端的一种心跳检测,设置为0则不检测

  • 通用

(1)daemonize = yes 是否后台启动

(2)loglevel notice 指定日志记录级别,有四个级别,默认为notice

(3)databases 16 设置数据库的数目,默认为16

(4)maxclients 10000 设置redis同时可以与多少个客户端进行连接

(5)maxmemory < bytes > redis配置的最大内存容量

?发布和订阅

  • 发布和订阅概述

发布和订阅是一种消息通信模式,发送者(pub)发送消息,订阅者(sub)接收消息。

redis客户端可以订阅任意数量的频道

(1)客户端可以订阅频道

j0oTWq.png

(2)当给这个频道发布消息后,消息就会发送给订阅的客户端

j0oHS0.png

  • 命令行实现

(1)打开一个客户端订阅一个频道channel1:subscribe channel1

j0TIBD.png

(2)打开另一个客户端,给channel1发布消息“hello” :publish channel1 hello

j0ToHe.png

返回的1是订阅者的数量

(3)打开第一个客户端可以看到第二个客户端发送的消息

j0Tjjf.png

?Jedis

Jedis是使用Java来操作redis的中间件。

其API提供了比较全面的Redis命令的支持

(1)创建maven项目,导入jedis依赖

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.3.0</version>
</dependency>

(2)使用Jedis

//生成一个Jedis对象,这个对象负责和指定的redis实例进行通信
Jedis jedis = new Jedis("192.168.229.128",6379);
//Jedis执行set操作(reids所有指令都在这)
jedis.set("name","lidu");
//Jedis执行get操作
String val = jedis.get("name");

==注意:==初始化 Jedis 需要两个参数,redis实例的 ip 和端口,要想通过 ip 访问 redis 必须在 redis.conf 配置文件中修改默认内容:

  • 将 bind = 127.0.0.1 注释掉
  • 将 peotected-mode = yes 改为 peotected-mode = no

同时Linux防火墙要关闭

  • 检查防火墙状态: systemctl status firewalld

jBy7cj.md.png

  • 关闭防火墙:systemctl stop firewalld

jB6GUf.md.png

?redis事务

  • 事务概述

Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。

**作用:**就是串联多个命令防止别的命令插队。

Redis事务和关系型数据库的事务不太一样,它不保证原子性,也没有隔离级别的概念。

  • 事务的执行和错误处理

Multi Exec Discard

  1. 从输入Multi命令开始,输入的命令都会依次进入队列中,但不会执行,直到输入Exec后,redis会将之前队列中的命令依次执行。组队的过程中可以通过Discard来放弃组队

j6w8sA.png

j6wsLn.png

  1. 组队中某个命令出现了错误,将要执行的整个队列都会被取消

j6wRiT.png

  1. 执行阶段某个命令出现了错误,只有报错的命令不会被执行,其他的命令还是会执行

j6woLR.png

?redis持久化

redis提供了两种不同的持久化方式:

RDB(Redis DataBase)

AOF(Append Of File)

RDB默认开启,AOF默认不开启

  • RDB

在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是快照,它恢复时是将快照文件直接读到内存里。

备份是如何执行的?

Redis会单独创建一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个文件替换上次持久化好的文件。

优点:

整个过程中,主进程是不进行任何I0操作的,这就确保了极高的性能。如果需要进行大规模数据的恢复,且对于据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。

缺点:

最后一次持久化后的数据可能丢失。

  • AOF

以日志的形式来记录每个写操作(增量保存),将redis执行过的所有写指令记录下来,读操作不记录;只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件内容将写指令从前到后执行一次,以完成数据的恢复工作。

持久化流程

  1. 客户端的请求写命令会被append追加到AOF缓冲区内;
  2. AOF缓冲区根据AOF持久化策略[always,everysec,no]将操作sync同步到磁盘的AOF文件中;
  3. AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容量;
  4. Redis服务重启时,会重新load加载AOF文件中的写操作达到数据恢复的目的

?主从复制

  • 主从复制概述

主从复制是主机数据更新后根据配置和策略,自动同步到备机的 master / slaver 机制。

master 以写为主,slaver 以读为主,一主多从

作用:

  1. 读写分离(主做写操作,从做读操作),性能扩展
  2. 容灾快速恢复

?redis集群

  • 集群概述

Redis集群实现了对Redis的水平扩容,即启动N个redis节点,将整个数据库分布存储在这N个节点中,每个节点存储总数据的1/N。

Redis集群通过分区来提供一定程度的可用性,即使集群中有一部分节点失效或者无法进行通讯,集群也可以继续处理命令请求。

容量不够,redis如何进行扩容?

并发写操作,redis如何分摊?

之前通过代理主机来解决,redis3.0中提供了无中心化集群配置

代理主机模式:

无中心化集群:

?应用问题解决

  • 缓存穿透

去请求缓存中不存在的数据,导致所有的请求都怼到数据库上,从而导致数据库连接异常。(一般是遇到黑客攻击)

解决方案:

  1. 对空值缓存

如果一个查询返回的数据为空(不管数据是否存在),我们仍然把这个空结果(null)进行缓存,设置很短的过期时间。

  1. 设置白名单

使用bitmaps类型定义一个白名单,里面放可以访问的id,每次访问的时候拿访问的id和bitmaps里面的id比较,如果访问的id不在bitmaps里面,进行拦截。

  • 缓存击穿

redis某个key过期了,大量访问需要使用这个key,数据库访问压力瞬时增加

解决方案:

  1. 加长这些key的过期时间
  2. 监控那些热门数据,实时调整key的过期时长
  • 缓存雪崩

即缓存同一时间大面积的失效,这个时候又来了一波请求,结果请求都怼到数据库上,而导致数据库连接异常。

解决方案:

  1. 添加随机值

给缓存的失效时间加上一个随机值,避免集体失效。

  1. 构建多级缓存架构

Nginx缓存 + Redis缓存 + 其他缓存

?分布式锁

  • 概述

随着业务发展的需要,原单体单机部署的系统被演化成分布式系统后,由于分布式系统多线程、多进程并且分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,为了解决这个问题就需要一种跨JVM的互斥机制来控制共享资源的访问,这就是分布式锁要解决的问题。

分布式锁应该具备的条件:

  1. 在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行
  2. 高可用的获取锁与释放锁
  3. 高性能的获取锁与释放锁
  4. 具备锁失效机制,防止死锁
  5. 具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败

实现方式:

  1. 基于数据库
  2. 基于redis(性能最高)
  3. 基于zookeeper(可靠性最高)
  • 命令实现

nx:表示上锁

ex:表示设置过期时间(单位秒)

==注意:==在过期时间内,key还能使用,过期后key就消失了


网站公告

今日签到

点亮在社区的每一天
去签到