尚硅谷Redis6从入门到精通

article/2025/10/24 12:07:10

本博客为尚硅谷课程笔记,课程来源:【尚硅谷】Redis 6 入门到精通 超详细 教程_哔哩哔哩_bilibili

本博客参考内容:
https://blog.csdn.net/weixin_47872288/article/details/118410080
https://zhangc233.github.io/2021/05/02/Redis/#HyperLogLog

在这里插入图片描述

1. NoSQL数据库简介

Not Only SQL,非关系型数据库

NoSQL有什么用:

  1. 解决CPU和内存压力
  2. 解决IO压力

NoSQL数据库特点:

  1. 非关系型数据库,不依赖业务逻辑数据库存储,以key-value存储,因此大大增加了数据库的扩展能力
  2. 不遵守SQL标准
  3. 不支持ACID(原子性、隔离性、一致性、持久性)
  4. 远超于SQL的性能

适用于:

  1. 高并发读写
  2. 海量数据读写
  3. 数据可扩展

不适用于场景:

  1. 需要事务支持
  2. 需要基于SQL结构化查询存储

NoSQL优点:

  1. 缓存数据库,完全在内存中,速度快,数据结构简单
  2. 减少io操作,数据库和表拆分,虽然破坏业务逻辑,即外加一个缓存数据库,提高数据库速度,也可以用专门的存储方式,以及针对不同的数据结构存储

常见的NoSQL数据库

  1. Memcache:不支持持久化
  2. Redis:支持持久化
  3. MongoDB:文档数据库
    在这里插入图片描述


2. Redis安装与配置

0. Redis概述

redis特性:

  • Redis是一个开源的key-value存储系统
  • 支持string,list,set,zset,hash类型
  • 这些数据类型都支持push/pop,add/remove,取交集并集等,这些操作都是原子性的
  • 支持不同方式的排序
  • 数据都是缓存在内存中
  • 实现了主从同步

1. 下载与安装

下载网址:Redis,只支持Linux版本,下载后在Ubuntu下解压,切入到对应文件夹下

首先需要gcc运行环境

sudo apt install gcc
gcc --version    //查看gcc版本

安装Redis:

make 
sudo make install

判断是否安装成功:

在这里插入图片描述


安装目录:/usr/local/bin

查看默认安装目录:

  • redis-benchmark:性能测试工具

  • redis-check-aof:修复有问题的 aof文件

  • redis-check-dump:修复有问题的dump.rdb文件

  • redis-sentinel:Redis集群使用

  • redis-server:Redis服务器启动命令

  • redis-cli:客户端,操作入口

2. 运行

a. 前台启动方式

(不推荐)

打开了就不问关闭该终端

cd /usr/local/bin
redis-server

在这里插入图片描述

b. 后台启动方式

把终端断掉了后台还在运行redis

cd redis-6.2.6   //切入Redis的文件夹
cp redis.conf etc/redis.conf  //拷贝一份redis.conf
cd /etc/
gedit redis.conf
//查找daemo  修改后面的no->yes
redis-server /etc/redis.conf  //后台启动redis服务器端

在这里插入图片描述


查看是否在运行:

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

退出方法

exit或关闭后台redis-cli shutdown或关闭进程号 kill -9 进程号


总结:以后这样登录redis:/usr/local/bin/redis-cli

在这里插入图片描述

3. set插入数据报错解决方法

参考博客:

https://blog.csdn.net/Sophia_0331/article/details/107779165

https://blog.csdn.net/zdyueguanyun/article/details/83449912

在这里插入图片描述

解决方法:

config set stop-writes-on-bgsave-error no

3. 常用五大数据类型

0. Redis相关知识

  • 登录redis:/usr/local/bin/redis-cli

  • Redis端口:6379

  • Redis默认0号数据库

  • Redis是单线程+多路IO复用

在这里插入图片描述

1. key

数据的操作:

  • 插入数据:set key value
  • 查看当前库的所有key:keys *
  • 是否存在当前键:exists key,存在返回1,否则返回0
  • 删除键值对:del key
  • 删除键值对:unlink key ,选择非阻塞删除
  • 查看键对应的值的类型:type key
  • 给键设置过期时间:expire key time,time以秒为单位
  • 查看键多长时间过期:ttl key,-1表示永不过期,-2表示已过期
zdb@zdb-virtual-machine:~$ /usr/local/bin/redis-cli
127.0.0.1:6379> keys *
(empty array)//插入数据
127.0.0.1:6379> set k1 lucy
OK
127.0.0.1:6379> set k2 mary
OK
127.0.0.1:6379> set k3 jack
OK//查询数据
127.0.0.1:6379> keys *
1) "k3"
2) "k1"
3) "k2"
127.0.0.1:6379> exists k1
(integer) 1
127.0.0.1:6379> exists k4
(integer) 0
127.0.0.1:6379> type k1
string//删除数据    
127.0.0.1:6379> del k3
(integer) 1
127.0.0.1:6379> unlink k2
(integer) 1//设置定时器    
127.0.0.1:6379> expire k1 10
(integer) 1
127.0.0.1:6379> ttl k1
(integer) 4
127.0.0.1:6379> ttl k1
(integer) -2

库的操作:

  • 选择库:select 库号,默认库为0号

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

  • 清空当前库:flushdb

  • 清空所有库:flushall

127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> select 0
OK
127.0.0.1:6379> dbsize
(integer) 0
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> flushdb
OK

2. string

关于string的介绍:

  • 一个key对应一个value
  • 二进制安全的,string可包含任何数据,比如jpg图片转换成string存储
  • value最多可以是512M
  • 动态的字符串,会扩容

常用命令:

  • 获取值:get key

  • 在值尾部追加元素:append key add_value

  • 获取值的长度:strlen key

  • 当key不存在,才存入key-value对:setnx key value

  • value增1:incr key

  • value减1:decr key

  • value增一个常数:incrby key 步长

  • value减一个常数:decr key 步长

127.0.0.1:6379> set k1 v100
OK
127.0.0.1:6379> set k2 v200
OK
127.0.0.1:6379> keys *
1) "k1"
2) "k2"
127.0.0.1:6379> get k1
"v100"
127.0.0.1:6379> set k1 v1100
OK
127.0.0.1:6379> get k1
"v1100"
127.0.0.1:6379> append k1 bac
(integer) 8
127.0.0.1:6379> get k1
"v1100bac"
127.0.0.1:6379> strlen k1
(integer) 8
127.0.0.1:6379> setnx k1 v300
(integer) 0
127.0.0.1:6379> setnx k3 v300
(integer) 1
127.0.0.1:6379> set k4 500
OK
127.0.0.1:6379> incr k4
(integer) 501
127.0.0.1:6379> get k4
"501"
127.0.0.1:6379> decr k4
(integer) 500
127.0.0.1:6379> incrby k4 10
(integer) 510
127.0.0.1:6379> decrby k4 20
(integer) 490

Redis的incr是原子性操作,java中不是原子性操作

在这里插入图片描述


其他命令:

  • 设置多个键值对:mset k1 v1 k2 v2...
  • 获取多个value:mget k1 k2 ...
  • msetnx k1 v1 k2 v2 k3 v3:原子操作,要么全部成功,要么全部失败
  • getrange key start_index end_index:get范围内的值,索引从0开始
  • setrange key startindex val:将startindex位置上的值用val替代
  • setex key time value:设置过期时间,同时设置值
  • getset key value:返回旧值,同时设置新值
127.0.0.1:6379> flushdb
OK127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 
OK
127.0.0.1:6379> keys *
1) "k3"
2) "k1"
3) "k2"
127.0.0.1:6379> mget k1 k2 k3
1) "v1"
2) "v2"
3) "v3"//msetnx要么全部成功,要么全部失败
127.0.0.1:6379> msetnx k11 v11 k12 v12 k1 v11
(integer) 0
127.0.0.1:6379> msetnx k11 v11 k12 v12 k13 v13
(integer) 1
127.0.0.1:6379> keys *
1) "k1"
2) "k3"
3) "k12"
4) "k13"
5) "k2"
6) "k11"127.0.0.1:6379> set name lucymary
OK
127.0.0.1:6379> getrange name 0 3
"lucy"
127.0.0.1:6379> setrange name 3 abc
(integer) 8
127.0.0.1:6379> get name
"lucabcry"//设置定时器    
127.0.0.1:6379> setex age 10 value30
OK
127.0.0.1:6379> ttl age
(integer) 4
127.0.0.1:6379> ttl age
(integer) -2//给key设置新值    
127.0.0.1:6379> getset name jack
"lucabcry"
127.0.0.1:6379> get name
"jack"

string的数据结构是简单的动态字符串

在这里插入图片描述

3. list

单键多值

多个value存储为list,底层为双向链表

常用命令:

  • lpush/rpush key value value...:从左或者右插入一个或者多个值(头插与尾插)

  • lpop/rpop key :从左或者右吐出一个或者多个值(值在键在,值都没,键都没)

  • rpoplpush key1 key2: 从key1列表右边吐出一个值,插入到key2的左边

  • lrange key start stop 按照索引下标获取元素(从左到右)

  • lrange key 0 -1: 获取所有值

  • lindex key index 按照索引下标获得元素

  • llen key 获取列表长度

  • linsert key before/after value newvalue 在value的前面插入一个新值

  • lrem key n value 从左边删除n个value值

  • lset key index value 在列表key中的下标index中修改值value

127.0.0.1:6379> lpush k1 v1 v2 v3
(integer) 3
127.0.0.1:6379> lrange k1 0 -1
1) "v3"
2) "v2"
3) "v1"127.0.0.1:6379> rpush k2 v1 v2 v3
(integer) 3
127.0.0.1:6379> lrange k2 0 -1
1) "v1"
2) "v2"
3) "v3"127.0.0.1:6379> lpop k1
"v3"
127.0.0.1:6379> lpush k1 v1 v2 v3
(integer) 3
127.0.0.1:6379> rpush k2 v11 v12 v13
(integer) 3
127.0.0.1:6379> rpoplpush k1 k2
"v1"
127.0.0.1:6379> lrange k2 0 -1
1) "v1"
2) "v11"
3) "v12"
4) "v13"//索引取值
127.0.0.1:6379> lindex k2
(error) ERR wrong number of arguments for 'lindex' command
127.0.0.1:6379> lindex k2 0
"v1"
127.0.0.1:6379> lindex k2 2
"v12"//获取长度    
127.0.0.1:6379> llen k2
(integer) 4//指定位置插入值    
127.0.0.1:6379> linsert k2 before "v11" "newv11"
(integer) 5
127.0.0.1:6379> lrange k2 0 -1
1) "v1"
2) "newv11"
3) "v11"
4) "v12"
5) "v13"
127.0.0.1:6379> linsert k2 before "v12" "newv11"
(integer) 6
127.0.0.1:6379> lrange k2 0 -1
1) "v1"
2) "newv11"
3) "v11"
4) "newv11"
5) "v12"
6) "v13"
127.0.0.1:6379> linsert k2 before "v13" "newv11"
(integer) 7
127.0.0.1:6379> lrange k2 0 -1
1) "v1"
2) "newv11"
3) "v11"
4) "newv11"
5) "v12"
6) "newv11"
7) "v13"//删除指定值,且可以指定个数    
127.0.0.1:6379> lrem k2 2 "newv11"
(integer) 2
127.0.0.1:6379> lrange k2 0 -1
1) "v1"
2) "v11"
3) "v12"
4) "newv11"
5) "v13"//指定位置替换值    
127.0.0.1:6379> lset k2 1 newnew
OK
127.0.0.1:6379> lrange k2 0 -1
1) "v1"
2) "newnew"
3) "v12"
4) "newv11"
5) "v13"

在这里插入图片描述

4. set

底层是字典,通过哈希表实现
自动排重且为无序的

常用命令:

  • sadd key value value... 将一个或者多个member元素加入集合key中,已经存在的member元素被忽略
  • smembers key 取出该集合的所有值
  • sismember key value 判断该集合key是否含有改值
  • scard key 返回该集合的元素个数
  • srem key value value 删除集合中的某个元素
  • spop key 随机从集合中取出一个元素
  • srandmember key n 随即从该集合中取出n个值,不会从集合中删除
  • smove <一个集合a><一个集合b>value 将一个集合a的某个value移动到另一个集合b
  • sinter key1 key2 返回两个集合的交集元素
  • sunion key1 key2 返回两个集合的并集元素
  • sdiff key1 key2 返回两个集合的差集元素(key1有的,key2没有)
127.0.0.1:6379> sadd k1 v1 v2 v3
(integer) 3
127.0.0.1:6379> smembers k1
1) "v2"
2) "v3"
3) "v1"//判断set中是否有值
127.0.0.1:6379> sismember k1 v1
(integer) 1
127.0.0.1:6379> sismember k1 v4
(integer) 0//返回集合中元素个数
127.0.0.1:6379> scard k1
(integer) 3//删除元素
127.0.0.1:6379> srem k1 v1 v2
(integer) 2
127.0.0.1:6379> smembers k1
1) "v3"
127.0.0.1:6379> sadd k2 v1 v2 v3 v4
(integer) 4
//随机删除元素
127.0.0.1:6379> spop k2
"v1"
127.0.0.1:6379> spop k2
"v4"
127.0.0.1:6379> spop k2
"v3"
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> sadd k2 v1 v2 v3 v4
(integer) 4
127.0.0.1:6379> srandmember k2 2    //随机取值
1) "v2"
2) "v3"
127.0.0.1:6379> srandmember k2 2
1) "v1"
2) "v3"
127.0.0.1:6379> sadd k1 v1 v2 v3
(integer) 3
127.0.0.1:6379> sadd k2 v3 v4 v5
(integer) 3//将k1中的v3移入到k2中    
127.0.0.1:6379> smove k1 k2 v3
(integer) 1
127.0.0.1:6379> smembers k1
1) "v2"
2) "v1"
127.0.0.1:6379> smembers k2
1) "v5"
2) "v3"
3) "v4"127.0.0.1:6379>  sadd k3 v3 v4 v5 v7
(integer) 4
127.0.0.1:6379> sinter k2 k3   //交集
1) "v5"
2) "v3"
3) "v4"
127.0.0.1:6379> sunion k2 k3  //并集
1) "v7"
2) "v3"
3) "v4"
4) "v5"
127.0.0.1:6379> sdiff k3 k2  //差集
1) "v7"

5. hash

hash是键值对集合,是一个string类型的field和value的映射表,hash特别适合用于存储对象。

常用命令:

  • hset key field value: 给key集合中的filed键赋值value
  • hget key1 field :集合field取出value
  • hmset key1 field1 value1 field2 value2 :批量设置hash的值
  • hexists key1 field: 查看哈希表key中,给定域field是否存在
  • hkeys key :列出该hash集合的所有field
  • hvals key :列出该hash集合的所有value
  • hincrby key field increment: 为哈希表key中的域field的值加上增量1 -1
  • hsetnx key field value :将哈希表key中的域field的值设置为value,当且仅当域field不存在

在这里插入图片描述

127.0.0.1:6379> hset user:1001 id 1   //插入数据:键 域 值
(integer) 1
127.0.0.1:6379> hset user:1001 name zhangsan
(integer) 1
127.0.0.1:6379> hget user:1001 id
"1"
127.0.0.1:6379> hget user:1001 name
"zhangsan"//一次性插入    
127.0.0.1:6379> hmset user:1002 id 2 name lisi age 30
OK//判断是否存在域    
127.0.0.1:6379> hexists user:1002 id
(integer) 1
127.0.0.1:6379> hexists user:1002 gender
(integer) 0//获取所有域    
127.0.0.1:6379> hkeys user:1002
1) "id"
2) "name"
3) "age"//获取所有值    
127.0.0.1:6379> hvals user:1002
1) "2"
2) "lisi"
3) "30"127.0.0.1:6379> hincrby user:1002 age 2
(integer) 32
127.0.0.1:6379> hsetnx user:1002 age 40
(integer) 0
127.0.0.1:6379> hsetnx user:1002 gender 1
(integer) 1

hash类型对应的数据结构是两种:ziplist(压缩列表),hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable。

6. zset

有序集合zset与普通集合set非常相似,是一个没有重复元素的字符串集合

常用命令:

  • zadd key score1 value1 score2 value2 :将一个或多个member元素及其score值加入到有序key中
  • zrange key start stop (withscores) :返回有序集key,下标在start与stop之间的元素,带withscores,可以让分数一起和值返回到结果集。
  • zrangebyscore key min max(withscores): 返回有序集key,所有score值介于min和max之间(包括等于min或max)的成员。有序集成员按score的值递增次序排列
  • zrevrangebyscore key max min (withscores):同上,改为从大到小排列
  • zincrby key increment value :为元素的score加上增量
  • zrem key value :删除该集合下,指定值的元素
  • zcount key min max :统计该集合,分数区间内的元素个数
  • zrank key value :返回该值在集合中的排名,从0开始
127.0.0.1:6379> zadd topn 200 java 300 c++ 400 mysql 500 php
(integer) 4
127.0.0.1:6379> zrange topn 0 -1
1) "java"
2) "c++"
3) "mysql"
4) "php"
127.0.0.1:6379> zrange topn 0 -1 withscores
1) "java"
2) "200"
3) "c++"
4) "300"
5) "mysql"
6) "400"
7) "php"
8) "500"127.0.0.1:6379> zrangebyscore topn 300 500
1) "c++"
2) "mysql"
3) "php"
127.0.0.1:6379> zrangebyscore topn 300 500 withscores
1) "c++"
2) "300"
3) "mysql"
4) "400"
5) "php"
6) "500"127.0.0.1:6379> zrevrangebyscore topn 500 300
1) "php"
2) "mysql"
3) "c++"127.0.0.1:6379> zincrby topn 50 java
"250"127.0.0.1:6379> zcount topn 200 300
(integer) 2127.0.0.1:6379> zrank topn java
(integer) 0
127.0.0.1:6379> zrank topn mysql
(integer) 2
127.0.0.1:6379> zrange topn 0 -1 withscores
1) "java"
2) "250"
3) "c++"
4) "300"
5) "mysql"
6) "400"
7) "php"
8) "500"

zset底层使用了两个数据结构:

  1. hash,hash的作用就是关联元素value和权重score,保障元素value的唯一性,可以通过元素value找到相应的score值。
  2. 跳跃表,跳跃表的目的在于给元素value排序,根据score的范围获取元素列表。



4. 配置文件

先打开配置文件:sudo gedit /etc/redis.conf

在这里插入图片描述

//1. 注释掉这一行
#bind 127.0.0.1 -::1//2. 保护模式改成no
protected-mode no//3. 后台启动改成yes
daemonize yes

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

添加密码:

在这里插入图片描述



5. 发布和订阅

什么是发布订阅:

发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
在这里插入图片描述


在这里插入图片描述


在这里插入图片描述



6. Redis6新数据类型

1. Bitmaps

  1. 合理使用操作位可以有效地提高内存使用率和开发使用率
  2. 本身是一个字符串,不是数据类型,数组的每个单元只能存放0和1,数组的下标在Bitmaps叫做偏移量
  3. 节省空间,一般存储活跃用户比较多

在这里插入图片描述

127.0.0.1:6379> setbit users:20210101 1 1
(integer) 0
127.0.0.1:6379> setbit users:20210101 6 1
(integer) 0
127.0.0.1:6379> setbit users:20210101 11 1
(integer) 0
127.0.0.1:6379> setbit users:20210101 15 1
(integer) 0
127.0.0.1:6379> setbit users:20210101 19 1
(integer) 0127.0.0.1:6379> getbit users:20210101 0
(integer) 0
127.0.0.1:6379> getbit users:20210101 1
(integer) 1127.0.0.1:6379> bitcount users:20210101
(integer) 5

取交集(按位与):

2020-11-04日访问网站的userid=1,2,5,9

2020-11-03日访问网站的userid=0.1.4.9

127.0.0.1:6379> setbit unique:users:20201104 1 1
(integer) 0
127.0.0.1:6379> setbit unique:users:20201104 2 1
(integer) 0
127.0.0.1:6379> setbit unique:users:20201104 5 1
(integer) 0
127.0.0.1:6379> setbit unique:users:20201104 9 1
(integer) 0
127.0.0.1:6379> setbit unique:users:20201103 0 1
(integer) 0
127.0.0.1:6379> setbit unique:users:20201103 1 1
(integer) 0
127.0.0.1:6379> setbit unique:users:20201103 4 1
(integer) 0
127.0.0.1:6379> setbit unique:users:20201103 9 1
(integer) 0127.0.0.1:6379> bitop and unqiue:users:and:20201104_03 setbit unique:users:20201103 setbit unique:users:20201104
(integer) 2

2. HyperLogLog

  1. 统计网页中页面访问量
  2. 只会根据输入元素来计算基数,而不会储存输入元素本身,不能像集合那样,返回输入的各个元素
  3. 基数估计是在误差可接受的范围内,快速计算(不重复元素的结算)
127.0.0.1:6379> pfadd program "java"
(integer) 1
127.0.0.1:6379> pfadd program "php"
(integer) 1
127.0.0.1:6379> pfadd program "java"   //重复元素不添加
(integer) 0
127.0.0.1:6379> pfadd program "java" "c++" "mysql"
(integer) 1
127.0.0.1:6379> pfcount program
(integer) 4
127.0.0.1:6379> pfadd k1 "a" "b"
(integer) 1
127.0.0.1:6379> pfcount k1
(integer) 2127.0.0.1:6379> pfadd k2 "1" "11" "111"
(integer) 1
127.0.0.1:6379> pfcount k2 
(integer) 3//合并
127.0.0.1:6379> pfmerge kres k1 k2
OK
127.0.0.1:6379> pfcount kres
(integer) 5

3. Geospatial

提供经纬度设置,查询范围,距离查询等

两极无法直接添加,有效的经度从-180到180度;有效的纬度从-85.05112878到85.05112878度

//插入数据
127.0.0.1:6379> geoadd china:city 141.47 31.23 shanghai
(integer) 1
127.0.0.1:6379> geoadd china:city 103.50 29.63 chongqing 114.05 22.52 shenzhen 116.38 39.90 beijing
(integer) 3127.0.0.1:6379> geopos china:city shanghai
1) 1) "141.47000044584274292"2) "31.22999903975783553"//获取两城市之间的距离   
127.0.0.1:6379> geodist china:city beijing shanghai km
"2455.6228"
127.0.0.1:6379> geodist china:city beijing chongqing km
"1636.7270"//获取指定经纬度一定范围内的城市
127.0.0.1:6379> georadius china:city 110 30 1000 km
1) "chongqing"
2) "shenzhen"

10. Redis事务_锁机制

Redis事务

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

Redis事务的主要作用就是串联多个命令防止别的命令插队。

mUlti,exec,discard

在这里插入图片描述

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set key1 value1
QUEUED
127.0.0.1:6379(TX)> set key2 value2
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) OK127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set a1 v1
QUEUED
127.0.0.1:6379(TX)> set a2 v2
QUEUED
127.0.0.1:6379(TX)> discard
OK

情况一:组队的时候有一个命令出错,执行时整个的所有队列都会被取消

在这里插入图片描述

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set b1 v1
QUEUED
127.0.0.1:6379(TX)> set b2 v2
QUEUED
127.0.0.1:6379(TX)> set b3
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors.

情况二:组队的时候没有失败,执行的时候有一个命令失败,其他的命令都会执行,不会回滚。

在这里插入图片描述

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set c1 v1
QUEUED
127.0.0.1:6379(TX)> incr c1
QUEUED
127.0.0.1:6379(TX)> set c2 v2
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) (error) ERR value is not an integer or out of range
3) OK

事务的冲突问题

悲观锁

在这里插入图片描述

乐观锁

每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis就是利用这种check-and-set机制实现事务的。

抢票就是典型的乐观锁场景。

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

Redis事务三特性

单独的隔离操作

  • 事务中的所有命令都会序列化,按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。

没有隔离级别的概念

  • 队列中的命令没有提交之前不会实际被执行,因为事务提交前任何指令都不会被实际执行

不保证原子性

  • 事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚。


12. Redis持久化之RDB

Redis提供了2个不同形式的持久化方式

  • RDB(Redis DataBase)
  • AOF(Append Of File)

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

备份是如何执行的?

  • Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能,如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。
  • RDB的缺点是最后一次持久化的数据可能丢失。

读时共享,写时复制。

在这里插入图片描述


在这里插入图片描述



13. Redis持久化之AOF

AOF是什么?

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

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

  • appendonly no改为yes开启

  • 如果同时开启AOF和RDB,系统默认取AOF的数据。

  • redis-check-aof --fix appendonly.aof可以修复aof文件

同步频率设置:

  • appendfsync always:始终同步,每次redis的写入都会立刻记入日志;性能较差但数据完整性比较好

  • annendfsync everysec:每秒同步,每秒写入日志一次,如果宕机,本秒的数据可能丢失。

  • appendfsync np:redis不主动进行同步,把同步时机交给操作系统

rewrite压缩

什么时候重写:

Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发

重写虽然可以节约大量磁盘空间,减少恢复时间。但是每次重写还是有一定的负担的,因此设定Redis要满足一定条件才会进行重写。

auto-aof-rewrite-percentage:设置重写的基准值,文件达到100%时开始重写(文件是原来重写后文件的2倍时触发)
auto-aof-rewrite-min-size:设置重写的基准值,最小文件64MB。达到这个值开始重写

AOF持久化流程:

  1. 客户端的请求写命令会被append追加到AOF缓冲区中

  2. AOF缓冲区根据AOF持久化策略[always, everysec, no]将操作sync同步到磁盘的AOF文件中

  3. AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容器

  4. Redis服务重启时,会重新load加载AOF文件的写操作达到数据恢复的目的。

优点:

  • 备份机制更稳健,丢失数据概率更低
  • 可读的日志文本,通过操作AOF稳健,可以处理误操作

缺点:

  • 比起RDB占用更多的磁盘空间。
  • 恢复备份速度要慢。
  • 每次读写都同步的话,有一定的性能压力。
  • 存在个别Bug,造成恢复不能

在这里插入图片描述

哪个好?

官方推荐两个都启动。如果对数据不敏感,可以单独选RDB;不建议单独用AOF,因为可能会出现bug。如果只是做纯内存缓存,可以都不用。



14. Redis主从复制

一般是一主多从

是什么?

  • 主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主

能干什么?

  • 读写分离;容灾的快速恢复

在这里插入图片描述

怎么搭建一主多从?

【尚硅谷】Redis 6 入门到精通 超详细 教程_哔哩哔哩_bilibili

一主二仆

info replication可以看信息

slaveof IP 端口9可以设置从服务器

redis-server redis.conf启动服务器端

redis-cli -p 端口 启动客户端

ps -ef | grep redis:查看redis进程

在这里插入图片描述

主机能读能写,从机只能读
在这里插入图片描述

从服务器挂掉后,重启变成了主服务器

该重新设置为从服务器,能看到挂掉那段时间主服务器添加的数据

主服务器挂掉后,从服务器还是从服务器,也知道主服务器挂掉了

主服务器重新启动后,还是主服务器,数据不丢失

  1. 当从服务器连接上主服务器之后,从服务器向主服务器发送进行数据同步的消息。

  2. 主服务器接到从服务器发送过来的同步消息,把主服务器数据进行持久化,rdb文件,把rdb文件发送给从服务器,从服务器拿到rdb进行读取。

  3. 每次主服务器进行写操作之后,和从服务器进行数据同步。(主服务器主动做的)

全量复制/增量复制

薪火相传

在这里插入图片描述

反客为主

salveof no one将从机变为主机

非自动

哨兵模式(sentinel)

反客为主的自动版

在这里插入图片描述

主要是为了监控主机宕机之后,从机可以立马变为主机,就和上面的反客为主一样,但不用手动设置
能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库。



15 Redis集群

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

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

在这里插入图片描述


在这里插入图片描述

什么是集群?

  • redis集群实现了对Redis的水平扩容,即启动N个redis节点,将整个数据库分布存储在这N个节点中,每个节点存储总数据的1/N。
  • redis集群通过分区(partition)来提供一定程度的可用性(availability):即使集群中有一部分节点失效或者无法进行通讯,集群也可以继续处理命令请求。

创建redis集群:【尚硅谷】Redis 6 入门到精通 超详细 教程_哔哩哔哩_bilibili

在这里插入图片描述



16. 应用问题

1. 缓存穿透

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

2. 缓存击穿

key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮

也就是一个key过期,一直访问数据库

在这里插入图片描述

解决方案:
key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑一个问题:缓存被“击穿”的问题。

(1)预先设置热门数据:在redis高峰访问之前,把一些热门数据提前存入到redis里面,加大这些热门数据key的时长
(2)实时调整:现场监控哪些数据热门,实时调整key的过期时长
(3)使用锁:先判断值是否为空再让他进来与否

总结如下:

  • 设置热门的key,加大时长过期
  • 实时监控调整

3. 缓存雪崩

在这里插入图片描述

解决方案:
(1)构建多级缓存架构:nginx缓存 + redis缓存 +其他缓存(ehcache等)
(2)使用锁或队列:用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。不适用高并发情况
(3)设置过期标志更新缓存:记录缓存数据是否过期(设置提前量),如果过期会触发通知另外的线程在后台去更新实际key的缓存。
(4)将缓存失效时间分散开:比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

总结如下:

  • 设置多个级别的缓存架构,时间来得及缓冲
  • 使用锁的机制
  • 设置一个过期时间标志来通知
  • 将过期时间分散,比如5分钟、5.01分钟等

4. 分布式锁

由于分布式系统多线程、多进程并且分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,单纯的Java API并不能提供分布式锁的能力。为了解决这个问题就需要一种跨JVM的互斥机制来控制共享资源的访问

也就是在这个机器上了锁,另外一个机器也要可以识别到这个锁,也就是共享锁,都是同一把锁

解决方案如下:

  • 基于数据库实现分布式锁
  • 基于缓存(Redis等)
  • 基于Zookeeper

设置锁:setnx

释放锁:del

设置key的过期时间自动释放:exprie

zdb@zdb-virtual-machine:~$ redis-server /etc/redis.conf 
zdb@zdb-virtual-machine:~$ /usr/local/bin/redis-cli127.0.0.1:6379> setnx users 10
(integer) 1
127.0.0.1:6379> setnx users 20
(integer) 0
127.0.0.1:6379> del users
(integer) 1127.0.0.1:6379> setnx users 10
(integer) 1
127.0.0.1:6379> expire users 10
(integer) 1
127.0.0.1:6379> ttl users
(integer) 4
127.0.0.1:6379> ttl users
(integer) -2//即上锁又设置过期时间
127.0.0.1:6379> set users 10 nx ex 12
OK
127.0.0.1:6379> ttl users
(integer) 3
127.0.0.1:6379> ttl users
(integer) -2

UUID防止误删

在这里插入图片描述

lua脚本保证原子性

在这里插入图片描述


在这里插入图片描述



17. Redis6.0新功能

1. ACL

在这里插入图片描述

权限控制

  • acl list命令展现用户权限列表
  • acl cat,查看添加权限指令类别
  • acl whoami命令查看当前用户
  • acl set user命令创建和编辑用户ACL
127.0.0.1:6379> acl list
1) "user default on nopass ~* &* +@all"127.0.0.1:6379> acl cat1) "keyspace"2) "read"3) "write"4) "set"5) "sortedset"6) "list"7) "hash"8) "string"9) "bitmap"
10) "hyperloglog"
11) "geo"
12) "stream"
13) "pubsub"
14) "admin"
15) "fast"
16) "slow"
17) "blocking"
18) "dangerous"
19) "connection"
20) "transaction"
21) "scripting"127.0.0.1:6379> acl whoami
"default"

2. IO多线程

单线程+IO多路复用

redis是单线程

在这里插入图片描述

多线程IO默认是不开启的,需要在配置文件中设置

io-threads-do-reads yes

io-therads 4


http://chatgpt.dhexx.cn/article/895avtEI.shtml

相关文章

Maven从入门到精通

文章目录 企业级架构框架图 Maven 项目构建工具概述为何需要maven&#xff1f; 四大特征仓库 repository依赖 dependency坐标 coordinate命令 mvn cmd小结 安装官网安装 配置 settings.xml配置文件设置镜像仓库改变仓库位置 eclipse 集成 maven配置 eclipse创建Maven项目创建ma…

PS从入门到精通第4节——祖传抠图技法

本结内容&#xff1a; 文末有本节内容总结 练习作业&#xff1a;素材包已上传&#xff0c;可免费下载&#xff0c;文末有练习的具体做法 背景素材直接打开为背景 本章知识重点在于对PS不同抠图工具的学习和使用选择合适的抠图工具去进行作业的制作抠图物体边缘无黑边排版比例大…

Docker从入门到精通

目录 一、初识 Docker 1、Docker概念 2、安装Docker&#xff08;CentOS系统&#xff09; 3、Docker的架构 4、阿里云镜像加速 5、Docker容器虚拟化 与 传统虚拟机比较 二、Docker 服务相关命令 1、启动docker 服务&#xff1a; 2、停止docker 服务&#xff1a; 3、重…

Midjourney从入门到精通

前言 什么是AI绘画 AI 绘画&#xff0c;顾名思义就是利用人工智能进行绘画&#xff0c;是人工智能生成内容&#xff08;AIGC&#xff09;的一个应用场景。其主要原理就是收集大量已有作品数据&#xff0c;通过算法对它们进行解析&#xff0c;最后再生成新作品&#xff0c;而算…

Jenkins从入门到精通

Jenkins从入门到精通 Jenkins简介Jenkins的特征Jenkins安装和持续集成环境配置Gitlab代码托管服务器安装Gitlab安装Gitlab添加组、创建用户、创建项目持续集成环境(1)-Jenkins安装持续集成环境(2)-Jenkins插件管理持续集成环境(3)-Jenkins用户权限管理持续集成环境(4)-Jenkins凭…

PS从入门到精通第2节——揭开PS的神秘面纱

本节内容 博客底部有内容小结&#xff08;本届内容快捷键&#xff09; 课后练习&#xff1a;&#xff08;素材包已上传&#xff0c;可免费下载&#xff09; 下面开始今天的课程 新建画布后拖拽素材进入 1. 勾选自动选择后可随意选择画布中的素材拖动 2. CTRLT调出定界框 …

PS从入门到精通

系列教程分为三个阶段 A功能精通阶段目录 红色是比较重要的课程&#xff0c;除了1和14节没有练习素材&#xff0c;其他部分都上传了案例相关的素材和高清笔记 第1节 用双手成就你的梦想 本节内容 关于版本 软件安装包可以搜索以下微信公众号或者官网下载&#xff0c;附件 …

UI自动化中断言的使用

在自动化编写脚本时&#xff0c;需要通过断言的方法来判断测试用例是否执行成功。检查点有两个&#xff0c;第一个是页面级别的检查&#xff0c;包括网页的标题和网址&#xff0c;第二个是页面元素级别的检查&#xff0c;包括元素的文本和元素的某个属性。 例子&#xff0c;下面…

UI自动化

UI自动化 本地搭建Javall商城项目maven环境搭建Maven项目管理Maven仓库 TestNG 单元测试框架安装testNG插件 八大定位方式知识点隐式等待&#xff1a;显式等待&#xff1a;iframe切换&#xff1a;window切换&#xff1a;Select下拉框Radio Button&#xff08;单选按钮&#xff…

UI自动化平台(一)

前言&#xff1a;最近萌生了做UI自动化平台的想法&#xff0c;以前做UI自动化都是直接脚本化的&#xff0c;也一直觉得UI改动一般都是很频繁&#xff0c;所以慢慢的脚本化的工作都放弃了&#xff0c;但是目前在公司&#xff0c;发现还是有点用的&#xff0c;公司的前辈也一直在…

ui自动化设计思路

小伙伴让我周末做技术分享&#xff0c;想着这是一件有意义的事情&#xff0c;便答应了下来&#xff0c;那就给大家讲讲ui自动化吧。这里会结合具体的代码给大家讲ui自动化一些理念&#xff0c;方案设计。 本文将探讨ui自动化设计思路&#xff0c;主要围绕以下方面展开讲解&…

使用UI Automation库用于UI自动化测试

&#x1f4cc; 博客主页&#xff1a; 程序员二黑 &#x1f4cc; 专注于软件测试领域相关技术实践和思考&#xff0c;持续分享自动化软件测试开发干货知识&#xff01; &#x1f4cc; 公号同名&#xff0c;欢迎加入我的测试交流群&#xff0c;我们一起交流学习&#xff01; UI A…

你知道什么叫三目表达式吗

目录 什么是三目表达式&#xff1f; 运用 1.单个使用 2.嵌套使用 什么是三目表达式&#xff1f; 1.三目表达式是一种编程中常见的表达式,它能够有效地帮助我们解决一些问题。 2.三目表达式由三个部分组成,分别是:条件表达式、结果表达式 听不懂么&#xff0c;那我们就来举个…

使用UI Automation实现自动化测试 --工具使用

当前项目进行三个多月了&#xff0c;好久也没有写日志了&#xff1b;空下点时间&#xff0c;补写下N久没写的日志 介绍下两个工具 我本人正常使用的UISpy.exe工具和inspect.exe工具 这是UISPY工具使用的图&#xff0c;正常使用到的几个属性 这里重点说一下微软件的UI Autom…

自动化测试平台(十):UI自动化元素页面的管理功能实现

一、前言 上一章我们完成了列表组件公共化封装和项目管理功能的实现,这一章将实现UI元素及元素页面的管理功能,换句话说就是对selenium执行定位操作的元素进行管理。 完整教程地址:《从0搭建自动化测试平台》 项目在线演示地址:http://121.43.43.59/ (帐号:admin 密码…

Android自动化测试入门(二)UI Automator

UI Automator是一个界面测试框架&#xff0c;支持跨进程&#xff0c;几乎可以模拟所有的人工操作。需要运行在4.3或者更高的系统版本上。它的测试代码的编写不依赖于目标应用的内部实现细节&#xff0c;非常适用编写黑盒自动化测试。 UI Automator 测试框架的主要功能包括&…

03-vue基础-插值表达式

文章目录 vue插值表达式vue通过data提供数据通过插值表达式显示数据安装vue开发者工具总结 vue插值表达式 本文要讲解的内容如下&#xff1a; 通过data提供数据通过插值表达式显示数据vue开发者工具的安装与使用 vue通过data提供数据 vue中通过template可以提供模板&#xf…

接口自动化和UI自动化:定义、区别及示例代码

目录 1.接口自动化 2.UI自动化 3.接口自动化和UI自动化的区别 4.结论 5.总结 在软件测试领域中&#xff0c;接口自动化和UI自动化是两个常见的测试类型&#xff0c;它们分别用于测试应用程序的不同层面。本文将介绍接口自动化和UI自动化的基本定义、区别以及示例代码。 1…

autojs,ui,界面学习,以及定时脚本页面的构建

注释掉ui或者ui的报错 再来就是认识几个单词&#xff0c;gravity 重力 简单来说就是你所创造的东西你想要它所处的位置在什么地方&#xff1a; left 靠左right 靠右top 靠顶部bottom 靠底部center 居中center_vertical 垂直居中center_horizontal 水平居中 text的一些属性&…

UI自动化测试03

一、警告框处理 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>警告窗口操作</title><script type"text/javascript">// JavaScript一些函数// 定义了一个函数function alterbutton(){alert("…