本博客为尚硅谷课程笔记,课程来源:【尚硅谷】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

尚硅谷Redis6从入门到精通相关推荐

  1. 尚硅谷Redis6基础教程-秒杀案例中库存遗留问题

    尚硅谷redis6基础教程中视频24-27的秒杀案例,使用Redis乐观锁解决了超卖问题,但是也产生了库存遗留问题.引入Lua脚本,解决了超卖和库存遗留.Lua脚本为什么解决了库存遗留问题???

  2. 《尚硅谷30天入门Java》学习笔记1

    第0天–准备工作 1.工具之印象笔记 浏览器插件.Android.Windows客户端.chrome印象笔记插件可以实现减藏页面,做笔记! 一个浏览器插件的网站 之前拖插件到拓展程序这里,显示crx_ ...

  3. 尚硅谷Redis6视频课程

    NoSQL数据库简介 技术发展 技术的分类 解决功能性的问题:Java.Jsp.RDBMS.Tomcat.HTML.Linux.JDBC.SVN 解决扩展性的问题:Struts.Spring.Spri ...

  4. 尚硅谷redis6的笔记

    文章目录 笔记,资料下载 建议先补一下数据结构 2. redis介绍 3. 常用的五大基本数据类型 1. 对key的基本操作 Redis字符串(String) Redis列表(List) Redis集 ...

  5. 尚硅谷_Redis6笔记

    该博客参考尚硅谷Redis6视频资料完成,仅用于学习使用,如有侵权,请联系删除 1.NoSQL数据库简介 1.NoSQL数据库 1.NoSQL数据库概述 NoSQL(NoSQL = Not Only ...

  6. 尚硅谷Redis尚硅谷学习汇总_事务_持久化_主从复制_集群_穿透_雪崩_击穿

    前言 该文章是我在学习Redis过程中写的学习汇总,包括了基本使用和常用命令.RDB和AOF.配置文件.事务.击穿.穿透.雪崩.集群等,都记录了详细过程,不管是新手学习还是有基础的同学拿来回顾都是可以 ...

  7. 【Vue学习笔记】尚硅谷Vue2.0+Vue3.0全套教程丨vue.js从入门到精通

    尚硅谷Vue2.0+Vue3.0全套教程丨vue.js从入门到精通 1.Vue核心部分 1.1 Vue简介 1.1.1 Vue是什么? Vue是一套用于构建用户界面的渐进式JavaScript框架. ...

  8. [Vue]学习笔记目录 【Vue2与Vue3完结】 (尚硅谷Vue2.0+Vue3.0全套教程丨vuejs从入门到精通)

    文章目录 前言 遇见的问题及其解决方案 之前笔记 Vue2 Vue3 前言 本笔记根据如下笔记和视频进行整理 老师的课件笔记,不含视频 https://www.aliyundrive.com/s/B8 ...

  9. JVM从入门到精通(尚硅谷宋红康)

    不动笔墨不读书,先把书读厚,再把书读薄是我学习方式. 所以等理解了再整理一次笔记,目前笔记和视频一一对应. 笔记连载中 <尚硅谷2020最新版宋红康JVM> 第1章:JVM与Java体系结 ...

最新文章

  1. ASP.NET MVC中你必须知道的13个扩展点
  2. python stm32-实现Python与STM32通信方式
  3. 从.NET和Java之争谈IT这个行业
  4. kl散度定义_Kullback-Leibler(KL)散度介绍
  5. whea uncorrectable error蓝屏_Windows 10再出“不可选”更新:蓝屏、死机比较烦
  6. 想让AI在企业落地?微软最新Azure AI不容错过!
  7. 通过mysql show processlist 命令检查mysql锁的方法
  8. sqlserver 判断字段是否为空字符串或者null
  9. 最短路径BFS算法matlab,迷宫的最短路径 bfs算法
  10. 昆仑通态如何连接sqlserver数据库_三菱FX5U 与昆仑通态触摸屏的连接操作步骤
  11. MSDTC不可用解决办法
  12. macd java 源代码_改良智能MACD指标公式及源代码
  13. 棋牌app开发需要多少钱
  14. 一本通 3.1 例 1」黑暗城堡
  15. module ‘sklearn.utils._openmp_helpers‘ has no attribute ‘__pyx_capi__‘
  16. oracle ora 604,ORA-01092:ORACLE实例终止,强制断开连接 ORA 00704 00604 00942
  17. 一文带你看懂小程序朋友圈广告是什么
  18. PRA是个啥?老板表示很满意!
  19. (三)Qlabel显示图片
  20. 代码显示return的用法(c语言和java的比较和整合)

热门文章

  1. 配置树莓派中文环境 及解决 no write since last change
  2. LVS 的 Tunneling 模式
  3. 全球重力异常值和磁场异常值提取
  4. ProtonMail邮箱
  5. Linux丢包问题排查思路
  6. MA1 轻轻松松学统计分析(下)
  7. 鲲鹏服务器gpu型号,GPU服务器服务
  8. 作为 Gopher, 你知道 Go 的注释即文档应该怎么写吗
  9. Office 2019离线安装ISO镜像
  10. Android音频可视化