【最全面的redis入門到高級教程】

Redis高级

Nosql概述

1.为什么要用nosql

1.单机mysql年代

image-20210527210526516

90年代,网页的访问量都不大

随着发展会有一些问题

1.数据库访问量变大、一个机器放不下

2.数据的索引、一个机器放不下

3.访问量一个机器承受不了

这时候需要升级了

2.memacache + mysql + 垂直分表

网站80%的情况都是读操作、每次查询十分麻烦就出现了缓存技术

缓存的发展过程:优化数据结构的索引--文件缓存(io)--Memcahe

image-20210527214026124

3.分库分表 + 水平拆分 + mysql集群

技术和业务发展的同时,对人的要求也越来越高

本质:数据库的读写

早些年myisam:表锁 非常不利于并发

转战innodb:行锁

慢慢开始用分库分表来解决写的压力

推出了mysql集群

image-20210527221311575

4.如今的架构

近些年技术发生了翻天腹地的变化

热点搜索、数据量大、博客、图片、mysql效率低

动态加1列等问题下,

image-20210527222725435

为什么用nosql

用户的个人信息,社交网络,地理位置。用户自己产生的数据,用户日志等等爆发式增长!

这时候要使用nosql数据库,nosql可以很好的处理以上情况

2.什么是nosql

NoSQL

NoSQL = Not only sql 不仅仅是sql

泛指非关系型数据库

个人信息,社交网络,地理位置等信息的存储不需要固定的格式!不需要多余的操作就可以横向纵向扩展的,

NoSQL特点

解耦:

1、方便扩展

2、大数据量高性能(redis 1s写8W次 读11W次,Nosql的缓存是细粒度的缓存)

3、数据类型多种多样!(不需要设计数据库!随取随用!大型数据库难设计)

4、rdbms和nosql区别

传统的RDBMS
- 结构化的组织
- SQL
- 数据和关系都存储在表中
- 操作
- 严格的一致性
- 基础的事务
- ......
Nosql
- 不仅仅是数据
- 没有固定的查询语言
- 键值对,列存储,文档存储,图形数据库(社交关系)
- 最终一致性(最后结果一样就可以)
- CAP定理和BASE (异地多活)
- 高性能
- 高可用
- 高可扩
- ......

了解:3V+3高

image-20210527224525822

在公司中一定是nosql和rdbms一起使用才是最强的

image-20210527230446045

3.nosql分类

  • kv键值对:redis/memcache
  • 文档型数据库:mongoDB
  • 列存储数据库:Hbase、分布式文件存储
  • 关系存储数据库:社交拓扑图Neo4j infogrid

image-20210527231622348

Redis概述

Redis是什么

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

Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库,并提供多种语言的 API。

免费开源!最热门的的nosql之一!

Redis能干什么

1.内存存储、持久化、断电及丢失、数据持久化(rdb,aof)

2.效率高,缓存

3.pubsub

4.地图信息分析

5.计数器,计时器

特性

  1. 多样性数据结构
  2. 持久化
  3. 集群
  4. 事务
  5. ......

redis安装目录

/usr/local/bin

Redis-benchmark测试工具

Redis测试100000个并发请求

Redis-benchmark -h localhost -p 6379 -c 100 -n 100000
序号 选项 描述 默认值
1 -h 指定服务器主机名 127.0.0.1
2 -p 指定服务器端口 6379
3 -s 指定服务器 socket
4 -c 指定并发连接数 50
5 -n 指定请求数 10000
6 -d 以字节的形式指定 SET/GET 值的数据大小 2
7 -k 1=keep alive 0=reconnect 1
8 -r SET/GET/INCR 使用随机 key, SADD 使用随机值
9 -P 通过管道传输 请求 1
10 -q 强制退出 redis。仅显示 query/sec 值
11 --csv 以 CSV 格式输出
12 *-l*(L 的小写字母) 生成循环,永久执行测试
13 -t 仅运行以逗号分隔的测试命令列表。
14 *-I*(i 的大写字母) Idle 模式。仅打开 N 个 idle 连接并等待。
>>>
====== LPUSH (needed to benchmark LRANGE) ======
  100000 requests completed in 1.33 seconds	# 100000个请求花了1.33s
  100 parallel clients	# 100个客户端连接
  3 bytes payload	# 每次写三个字节
  keep alive: 1	# 每次只有一个服务器处理请求(单机性能)

55.49% <= 1 milliseconds
99.97% <= 2 milliseconds
100.00% <= 2 milliseconds
75075.07 requests per second

Redis基础

1.数据库命令

  • 选择数据库:select 0

    # select 数据库id
    select 0
    
  • 数据库大小:dbsize

    dbsize 
    
  • 查看所有的键:keys *

    127.0.0.1:6379> keys *
    1) "k3"
    2) "k2"
    3) "k1"
    
  • 清空数据库:flushdb

    flushdb
    
  • 判断key值是否存在:exists key

    127.0.0.1:6379> keys *
    1) "k3"
    2) "k2"
    3) "k1"
    127.0.0.1:6379> exists k1
    (integer) 1	# 存在返回1
    127.0.0.1:6379> exists k4
    (integer) 0 # 不存在返回0
    127.0.0.1:6379> 
    
  • 将key值移动到其他库:move k1 1

    127.0.0.1:6379> move k1 1
    (integer) 1
    127.0.0.1:6379> keys *
    1) "k3"
    2) "k2"
    127.0.0.1:6379> select 1
    OK
    127.0.0.1:6379[1]> keys *
    1) "k1"
    127.0.0.1:6379[1]> 
    
  • 设置过期时间:expire key seconds

    • 单点登录
    • 热点消息的过期时间都可以用这个功能
    127.0.0.1:6379[1]> set name alex
    OK
    127.0.0.1:6379[1]> expire name 3
    (integer) 1
    127.0.0.1:6379[1]> ttl name
    (integer) 0
    127.0.0.1:6379[1]> ttl name
    (integer) -2
    127.0.0.1:6379[1]> get name
    (nil)
    
  • 判断数据类型:type key

    127.0.0.1:6379[1]> keys *
    1) "k1"
    127.0.0.1:6379[1]> type k1
    string
    

2.Redis为什么是单线程的?

REDIS是基于内存的,cpu不是redis的瓶颈,redis的瓶颈是贷款和内存,这两方面单线程不受影响,所以使用了单线程

3.Redis有多快

QPS 100000+

误区:

  • 高性能服务器一定是多线程!(错误)
  • 多线程一定比单线程效率高!(错误)
    • 线程切换消耗

核心:

  • redis将所有的数据全部放在内存中,所以说单线程的效率就是最高的(多线程会有上下文切换会损耗性能)对于内存系统如果没有上下文切换效率就是最高的

Redis五大基础数据类型

官网:

​ Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存消息中间件。 它支持多种类型的数据结构,如 字符串(strings)散列(hashes) 列表(lists)集合(sets)有序集合(sorted sets) 与范围查询, bitmapshyperloglogs地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication)LUA脚本(Lua scripting)LRU驱动事件(LRU eviction)事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。

功能:

  • 数据库

  • 缓存中间件

  • 消息中间件

  • 主从复制

  • lua脚本

  • lru

  • 事务

  • 持久化

  • 哨兵模式

  • 分区

1.String

1.1 API:

  • set key value:设置键值对

  • get key:根据键获取值

  • append key value:在key后面增加value

##########################################################################
# set key value:设置键值对
# get key:根据键获取值
# append key value:在key后面增加value
127.0.0.1:6379> set key1 v1
OK
127.0.0.1:6379> append key1 v2
(integer) 4
127.0.0.1:6379> get key1
"v1v2"
##########################################################################
  • set key 0 :设置数字字符串0

  • incr views:自增1

  • decr views:自减1

##########################################################################
# set key 0 :设置数字字符串0
# incr views:自增1
# decr views:自减1
127.0.0.1:6379> SET views 0	# 初始浏览量
OK
127.0.0.1:6379> incr views	# 初始浏览量+1
(integer) 1
127.0.0.1:6379> incr views
(integer) 2
127.0.0.1:6379> incr views
(integer) 3
127.0.0.1:6379> decr views	# 初始浏览量-1
(integer) 2
127.0.0.1:6379> decr views
(integer) 1
127.0.0.1:6379> decr views
(integer) 0
##########################################################################
  • incrby views 10:自增10

  • decrby views 10:自减10

##########################################################################
# incrby views 10:自增10
# decrby views 10:自减10
127.0.0.1:6379> incrby views 10	# +10
(integer) 10
127.0.0.1:6379> incrby views 10
(integer) 20
127.0.0.1:6379> incrby views 10
(integer) 30
127.0.0.1:6379> incrby views 10
(integer) 40
127.0.0.1:6379> decrby views 10	# -10
(integer) 30
127.0.0.1:6379> decrby views 10
(integer) 20
127.0.0.1:6379> decrby views 10
(integer) 10
127.0.0.1:6379> decrby views 10
(integer) 0
##########################################################################
  • getrange:遍历字符串
  • setrange:从指定位置开始替换元素
##########################################################################
# getrange:遍历字符串
# setrange:从指定位置开始替换元素
127.0.0.1:6379> SET KEY ABCDEFG
OK
127.0.0.1:6379> GET KEY
"ABCDEFG"
127.0.0.1:6379> GETRANGE KEY 0 -1
"ABCDEFG"
127.0.0.1:6379> GETRANGE KEY 0 3
"ABCD"
127.0.0.1:6379> SETRANGE KEY 1 HELLO	# 将键为key的字符串的值从索引为1出开始替换为HELLO
(integer) 7
127.0.0.1:6379> GET KEY
"AHELLOG"
##########################################################################
  • setex key seconds values:设置过期时间
  • setnx:不存在在设置(保证一定有值)
  • ttl key:查看key还有多少时间过期
##########################################################################
# setex key seconds values:设置过期时间
# setnx:不存在在设置(保证一定有值)
# ttl key:查看key还有多少时间过期
127.0.0.1:6379> setex key3 10 helloworld
OK
127.0.0.1:6379> ttl key3	# 查看还有多少时间过期
(integer) 5
127.0.0.1:6379> ttl key3
(integer) 0
127.0.0.1:6379> ttl key3
(integer) -2
127.0.0.1:6379> setnx key2 value2
(integer) 1
##########################################################################
  • mset k1 v1 k2 v2 k3 v3: 一次设置多个值 这是原子性操作

  • mget k1 k2 k3: 一次获取多个值

##########################################################################
# mset k1 v1 k2 v2 k3 v3 	# 一次设置多个值
# mget k1 k2 k3				# 一次获取多个值
# msetnx k1 v1 k4 v4 # 不存在再设置
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3
OK
127.0.0.1:6379> keys *
1) "k3"
2) "k2"
3) "k1"
127.0.0.1:6379> mget k1 k2 k3
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v1 k4 v4	# 这是原子性操作
(integer) 0
127.0.0.1:6379> keys *	
1) "k3"
2) "k2"
3) "k1"	# k4不存在
##########################################################################
  • getset key value: 先获取值再设置值
##########################################################################
# getset key value: 先获取值再设置值 
127.0.0.1:6379> getset db redis	# 如果不存在返回nil
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> getset db mongo	# 如果存在先返回值再设置值
"redis"
127.0.0.1:6379> get db
"mongo"
##########################################################################

1.2 应用场景:

  • 计数器
  • 统计多单位数量
    • uid:1:views # 浏览数
    • uid:1:follow # 关注数
    • uid:1:fans # 粉丝数
  • 缓存+过期时间
# 对象
# 第一种情况
127.0.0.1:6379> set user:1 {name:zhangsan,age:3}
OK
127.0.0.1:6379> get user:1
"{name:zhangsan,age:3}"
# 第二种情况(优于第一种 不用解析json)
127.0.0.1:6379> mset user:1:name zhangsan user:1:age 3
OK
127.0.0.1:6379> mget user:1:name user:1:age 3
1) "zhangsan"
2) "3"

2.List

所有的list命令以l开头

  • lpush list [element,]
  • rpush list [element,]
  • lrange list start end
##################################################################
# lpush list [element,] # 向list列表d左侧插入值
# rpush list [element,] # 向list列表右侧插入值
# lrange list start end # 根据索引遍历列表
127.0.0.1:6379> lpush list 1 2 3 4 5	# 将数据插入到列表的头部
(integer) 5	# 成功插入了5个数据
127.0.0.1:6379> lrange list 0 -1	# 遍历列表(从左侧)
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
127.0.0.1:6379> lrange list 0 1
1) "5"
2) "4"
127.0.0.1:6379> FLUSHDB	# 清空当前数据库
OK
127.0.0.1:6379> rpush list 1 2 3 4 5
(integer) 5
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
##################################################################
  • lpop list
  • rpop list
  • lindex list index
  • llen list
  • lrem list key count
  • ltrim list start end
  • rpoplpush source destination
  • lset key index element
  • linsert key BEFORE|AFTER pivot element
##################################################################
# lpop list # 左侧删除一个元素
# rpop list # 右侧删除一个元素
# lindex list index # 根据索引获取数据
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> lpop list
"1"
127.0.0.1:6379> lrange list 0 -1
1) "2"
2) "3"
3) "4"
4) "5"
127.0.0.1:6379> rpop list
"5"
127.0.0.1:6379> lrange list 0 -1
1) "2"
2) "3"
3) "4"
##################################################################
# lindex list index # 根据索引获取值
127.0.0.1:6379> lrange list 0 -1
1) "2"
2) "3"
3) "4"
127.0.0.1:6379> lindex list 0
"2"
127.0.0.1:6379> lindex list 1
"3"
127.0.0.1:6379> lindex list 2
"4"
##################################################################
# llen list # 获取list长度
127.0.0.1:6379> llen list
(integer) 3
##################################################################
# lrem list key count #移除list中指定的值(关注列表取关)
127.0.0.1:6379> lrange list 0 -1
1) "2"
2) "2"
3) "1"
4) "2"
5) "3"
6) "4"
127.0.0.1:6379> lrem list 1 2
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "2"
2) "1"
3) "2"
4) "3"
5) "4"
127.0.0.1:6379> lrem list 2 2
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "3"
3) "4"
##################################################################
# ltrim list start end # 截取列表
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> lpush mylist hello
(integer) 1
127.0.0.1:6379> lpush mylist hello1
(integer) 2
127.0.0.1:6379> lpush mylist hello2
(integer) 3
127.0.0.1:6379> lpush mylist hello3
(integer) 4
127.0.0.1:6379> lpush mylist hello4
(integer) 5
127.0.0.1:6379> lpush mylist hello5
(integer) 6
127.0.0.1:6379> lrange mylist 0 -1
1) "hello5"
2) "hello4"
3) "hello3"
4) "hello2"
5) "hello1"
6) "hello"
127.0.0.1:6379> ltrim mylist 1 2	# 从左侧通过下表截取指定的长度,前后都包括,list已经被改变
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "hello4"
2) "hello3"
##################################################################
# rpoplpush source destination # 移除列表的最后一个元素并添加到新的列表中,如果新列表不存在则创建一个再插入
127.0.0.1:6379> rpush mylist 000 111 222 333 444
(integer) 5
127.0.0.1:6379> rpoplpush mylist newlist
"444"
127.0.0.1:6379> lrange mylist 0 -1
1) "000"
2) "111"
3) "222"
4) "333"
127.0.0.1:6379> lrange newlist 0 -1
1) "444"
##################################################################
# lset key index element # 列表中指定下表的值替换为另外一个值
127.0.0.1:6379> exists list	# 判断列表是否存在
(integer) 1
127.0.0.1:6379> lpush list 1
(integer) 1
127.0.0.1:6379> lset list 0 item	# 更新列表的值
OK
127.0.0.1:6379> lrange list 0 -1	# 不存在索引则会报错
1) "item"
##################################################################
# linsert key BEFORE|AFTER pivot element	# 在某个值前面或者后面插入一个值
127.0.0.1:6379> lpush list 0  1 2 3 4 5
(integer) 6
127.0.0.1:6379> lrange list 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
6) "0"
127.0.0.1:6379> linsert list before 4 100
(integer) 7
127.0.0.1:6379> lrange list 0 -1
1) "5"
2) "100"
3) "4"
4) "3"
5) "2"
6) "1"
7) "0"
##################################################################

小结:

  • redis列表实际上是一个链表,before after node left right都可以插入值
  • 如果key不存在创建一个链表
  • 如果key存在新增内容
  • 两边插入值,效率高!中间插入元素,效率相对低

功能:

  • 消息队列
    • lpush lpop 栈
    • lpush rpop 队列

3.set

set无序不重复集合

  • sadd key member [member ...]
  • smembers key
  • sismember key member
  • scard set # 查看set有多少个值
  • srem key member [member ...] # 移除set集合中的指定元素
  • smembers key # 集合随机出一个元素
  • spop key [count] # 随机删除一个元素
  • smove source destination member # 把一个集合中的元素移动到另一个集合
##################################################################
# sadd key member [member ...] # set中添加值
# smembers key # 查看set中所有的值
# sismember key member # 查看set中是否有member
127.0.0.1:6379> sadd set 1 2 3	# set中添加值
(integer) 3
127.0.0.1:6379> smembers set	# 查看set中的值
1) "1"
2) "2"
3) "3"
127.0.0.1:6379> sismember set hello	# 查看某个元素是否在set中
(integer) 0	# 不在返回0
127.0.0.1:6379> sismember set 1
(integer) 1 # 在返回1
##################################################################
# scard set # 查看set有多少个值
127.0.0.1:6379> scard set
(integer) 3
##################################################################
# srem key member [member ...] # 移除set集合中的指定元素
127.0.0.1:6379> srem set 1
(integer) 1
127.0.0.1:6379> smembers set
1) "2"
2) "3"
##################################################################
# smembers key # 集合随机获取一个元素(抽奖)
127.0.0.1:6379> smembers set
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
127.0.0.1:6379> srandmember set 1
1) "2"
127.0.0.1:6379> srandmember set 1
1) "2"
127.0.0.1:6379> srandmember set 1
1) "1"
127.0.0.1:6379> srandmember set 1
1) "6"
##################################################################
# spop key [count] # 随机删除一个元素
127.0.0.1:6379> smembers set
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
127.0.0.1:6379> spop set
"3"
127.0.0.1:6379> smembers set
1) "1"
2) "2"
3) "4"
4) "5"
5) "6"
127.0.0.1:6379> spop set
"1"
127.0.0.1:6379> smembers set
1) "2"
2) "4"
3) "5"
4) "6"
##################################################################
# smove source destination member # 把一个集合中的元素移动到另一个集合
127.0.0.1:6379> sadd set2 set2
(integer) 1
127.0.0.1:6379> smove set set2 2	# 把set集合中的2移动到set2集合
(integer) 1
127.0.0.1:6379> smembers set
1) "4"
2) "5"
3) "6"
127.0.0.1:6379> smembers set2
1) "set2"
2) "2"
##################################################################
# sdiff key [key ...]	# 差集
# sunion key [key ...] # 并集
127.0.0.1:6379> sadd s1 1 2 3 4 5
(integer) 5
127.0.0.1:6379> sadd s2  3 4 5 6 7
(integer) 5
127.0.0.1:6379> smembers s1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> smembers s2
1) "3"
2) "4"
3) "5"
4) "6"
5) "7"
127.0.0.1:6379> sdiff s1 s2	 # 差集:以s1为基准查看s2中不同的集合
1) "1"
2) "2"
127.0.0.1:6379> sunion s1 s2 # 并集:
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
7) "7"
##################################################################

小结:

  • 交集
  • 并集
  • 差集

功能:

  • 交集:共同关注
  • 二度好友

4.hash

想像成map集合

set myhash field hello

以h开头的就是哈希命令

  • hset key field value [field value ...] # 设置一个或者多个键值对
  • hget key field # 获取一个键的值
  • hmset key field value [field value ...] # 设置一个或者多个键值对
  • hmget key field [field ...] # 获取多个键的值
  • hgetall key # 获取所有键值对
  • hexists key field # 查看是否存在
  • hkeys key # 获取所有的key
  • hvals key # 获取所有的value
  • hincrby key field increment # hash的value自增1
##################################################################
# hset key field value [field value ...]	# 设置一个或者多个键值对
# hget key field	# 获取一个键的值
# hmset key field value [field value ...]	# 设置一个或者多个键值对
# hmget key field [field ...] # 获取多个键的值
# hgetall key # 获取所有键值对
# hlen key # 获取哈希的长度
127.0.0.1:6379> hset myhash field1 hello	# 给myhash设置一个key value
(integer) 1
127.0.0.1:6379> hget myhash field1
"hello"
127.0.0.1:6379> hset myhash k1 v1 k2 v2 k3 v3	# 给myhash设置多个key value
(integer) 3
127.0.0.1:6379> hget myhash k1	# 获取一个key的value
"v1"
127.0.0.1:6379> hget myhash k2
"v2"
127.0.0.1:6379> hget myhash k3
"v3"
127.0.0.1:6379> hmget k1 k2 k3
1) (nil)
2) (nil)
127.0.0.1:6379> hmget myhash k1 k2 k3	# 获取多个key的value
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> hgetall myhash	# 获取所有的键值
1) "field1"
2) "hello"
3) "k1"
4) "v1"
5) "k2"
6) "v2"
7) "k3"
8) "v3"
127.0.0.1:6379> hlen myhash
(integer) 4
127.0.0.1:6379> hgetall myhash
1) "field1"
2) "hello"
3) "k1"
4) "v1"
5) "k2"
6) "v2"
7) "k3"
8) "v3"
##################################################################
# hexists key field # 查看是否存在
127.0.0.1:6379> hexists myhash k1
(integer) 1	# 存在 
127.0.0.1:6379> hexists myhash k5
(integer) 0 # 不存在
##################################################################
# hkeys key # 获取所有的key
# hvals key # 获取所有的value
127.0.0.1:6379> hkeys myhash
1) "field1"
2) "k1"
3) "k2"
4) "k3"
127.0.0.1:6379> hvals myhash
1) "hello"
2) "v1"
3) "v2"
4) "v3"
##################################################################
# hincrby key field increment # hash的value自增1
127.0.0.1:6379> hset hash k1 1
(integer) 0
127.0.0.1:6379> hget hash k1
"1"
127.0.0.1:6379> hincrby hash k1 1	# 自增1
(integer) 2
127.0.0.1:6379> hincrby hash k1 1
(integer) 3
127.0.0.1:6379> hincrby hash k1 1
(integer) 4
127.0.0.1:6379> hget hash k1
"4"
127.0.0.1:6379> hincrby hash k1 -1 # 减少1
(integer) 3
127.0.0.1:6379> hincrby hash k1 -1
(integer) 2
127.0.0.1:6379> hincrby hash k1 -1
(integer) 1
127.0.0.1:6379> hget hash k1
"1"
##################################################################

小结:

  • 变更数据
  • 哈希更适合存储对象
  • string更适合存储string
##################################################################
# 用户信息的保存(经常改变)
127.0.0.1:6379> hset user:1 name alex age 18
(integer) 2
127.0.0.1:6379> hget user:1 name
"alex"
127.0.0.1:6379> hget user:1 age
"18"
##################################################################

5.zset(有序集合)

在set的基础上增加了一个值

  • zadd key [NX|XX] [CH] [INCR] score member [score member .. # 有序集合添加

  • zrange key start stop [WITHSCORES] # 有序集便利

  • zrangebyscore key min max [WITHSCORES] [LIMIT offset count # 排序

  • zrem key member [member ...] # 移除制定元素

  • zcard key # 获取有序结合中的个数

  • zcount myset 1 2 # 获得指定区间的成员数量

##################################################################
# zadd key [NX|XX] [CH] [INCR] score member [score member .. # 有序集合添加
# zrange key start stop [WITHSCORES]	# 有序集便利
127.0.0.1:6379> zadd myset 1 one
(integer) 1
127.0.0.1:6379> zadd myset 2 two
(integer) 1
127.0.0.1:6379> zadd myset 3 three
(integer) 1
127.0.0.1:6379> zrange myset 0 -1
1) "one"
2) "two"
3) "three"
##################################################################
# zrangebyscore key min max [WITHSCORES] [LIMIT offset count # 排序
127.0.0.1:6379> zadd salary 500 alex
(integer) 1
127.0.0.1:6379> zadd salary 800 kack
(integer) 1
127.0.0.1:6379> zadd salary 800 bob
(integer) 1
127.0.0.1:6379> zrangebyscore salary -inf +inf	# 查询负无穷大到正无穷排序后的结果(values)
1) "alex"
2) "bob"
3) "kack"
127.0.0.1:6379> zrangebyscore salary -inf +inf withscores # 查询负无穷大到正无穷排序后的结果(key,value)
1) "alex"
2) "500"
3) "bob"
4) "800"
5) "kack"
6) "800"
127.0.0.1:6379> zrangebyscore salary -inf 700 withscores # 查询负无穷大到700排序后的结果
1) "alex"
2) "500"
##################################################################
# zrem key member [member ...] # 移除制定元素
127.0.0.1:6379> zrem salary alex
(integer) 1
127.0.0.1:6379> zrange salary 0 -1
1) "bob"
2) "kack"
##################################################################
# zcard key	# 获取有序结合中的个数
127.0.0.1:6379> zcard salary
(integer) 2
##################################################################
# zcount myset 1 2 # 获得指定区间的成员数量
127.0.0.1:6379> zadd myset 1 hello
(integer) 1
127.0.0.1:6379> zadd myset 1 world
(integer) 1
127.0.0.1:6379> zadd myset 1 alex
(integer) 1
127.0.0.1:6379> zcount myset 0 -1
(integer) 0
127.0.0.1:6379> zcount myset 1 2 # 获得指定区间的成员数量
(integer) 3

ZSET应用

存储成绩表

存储工资表排序

带权重的消息。。。

排行榜实现,top n

Redis三种特殊数据类型

1.Geospatial 地理位置

这个数据类型基于zset,所以zset的命令也适合

朋友圈定位、附近的人、打车距离计算、等都可以用geo实现

单位:

m/km/mi/ft

geoadd

geoadd

添加城市信息:

##################################################################
# 添加城市的经纬度信息
# 有效的经度[-180:180] 有效的维度 [-85:85]
# 
# geoadd key longitude latitude member [longitude latitude m # 添加城市的经纬度信息
127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing
(integer) 1
127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai
(integer) 1
127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing
(integer) 1
127.0.0.1:6379> geoadd china:city 114.05 29.53 shengzhen
(integer) 1
127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou
(integer) 1
127.0.0.1:6379> geoadd china:city 108.96 34.26 xian
(integer) 1
##################################################################

geopos

geopos

获取某个城市的经纬度

##################################################################
# 获取指定的城市的经度和纬度
# geopos key member [member ...]
127.0.0.1:6379> geopos china:city xian
1) 1) "108.96000176668167114"
   2) "34.25999964418929977"
127.0.0.1:6379> geopos china:city xian hangzhou
1) 1) "108.96000176668167114"
   2) "34.25999964418929977"
2) 1) "120.1600000262260437"
   2) "30.2400003229490224"
##################################################################

geodist

geodist

获取两个城市之间的距离

##################################################################
# 获取两个城市之间的距离
# geodist key member1 member2 [m|km|ft|mi]
127.0.0.1:6379> geodist china:city xian chongqing	# 默认是米
"575046.9885"
127.0.0.1:6379> geodist china:city xian chongqing km	# 查看西安到重庆的直线距离
"575.0470"
127.0.0.1:6379> geodist china:city shanghai beijing km # 查看北京到上海的直线距离
"1067.3788"
127.0.0.1:6379>
##################################################################

georadius

georadius

附近的人

##################################################################
# 查看周围元素的情况
# georadius key longitude latitude radius m|km|ft|mi [WITH
# georadius china:city 110 30 400 km withcoord withdist count 2
# withcoord:查看周围城市的经度纬度
# withdist:查看周围城市和你的距离
# count:查询几个
127.0.0.1:6379> georadius china:city 110 30 1000 km	# 查看110,30这个位置周围1000km内的城市
1) "chongqing"
2) "xian"
3) "shengzhen"
4) "hangzhou"
127.0.0.1:6379> georadius china:city 110 30 500 km # 查看110,30这个位置周围500km内的城市
1) "chongqing"
2) "xian"
3) "shengzhen"
127.0.0.1:6379> georadius china:city 110 30 400 km # 查看110,30这个位置周围400km内的城市
1) "chongqing"
2) "shengzhen"
127.0.0.1:6379> georadius china:city 110 30 400 km withdist 
# 查看110,30这个位置周围400km内的城市到中心距离的位置
1) 1) "chongqing"
   2) "341.9374"
2) 1) "shengzhen"
   2) "394.4925"
127.0.0.1:6379> georadius china:city 110 30 400 km withcoord
# 查看110,30这个位置周围400km内的城市的经度纬度
1) 1) "chongqing"
   2) 1) "106.49999767541885376"
      2) "29.52999957900659211"
2) 1) "shengzhen"
   2) 1) "114.04999762773513794"
      2) "29.52999957900659211"
127.0.0.1:6379> georadius china:city 110 30 400 km withcoord withdist count 1
#  查看110,30这个位置周围400km内的城市到中心的距离、城市的定位 显示1个
1) 1) "chongqing"
   2) "341.9374"
   3) 1) "106.49999767541885376"
      2) "29.52999957900659211"
127.0.0.1:6379> georadius china:city 110 30 400 km withcoord withdist count 2
#  查看110,30这个位置周围400km内的城市到中心的距离、城市的定位 显示2个
1) 1) "chongqing"
   2) "341.9374"
   3) 1) "106.49999767541885376"
      2) "29.52999957900659211"
2) 1) "shengzhen"
   2) "394.4925"
   3) 1) "114.04999762773513794"
      2) "29.52999957900659211"
##################################################################

georadiusbymembe

georadiusbymembe

查询指定元素周围指定距离内的元素(找朋友)

##################################################################
# 找出指定元素指定距离周围的元素
# georadiusbymembe key member radius m|km|ft|mi [WITHCOORD] [WITHDIST]
127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 1000 km# 查看北京周围1000km范围内的城市
1) "beijing"
2) "xian"
127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 2000 km# 查看北京周围2000km范围内的城市
1) "chongqing"
2) "xian"
3) "shengzhen"
4) "hangzhou"
5) "shanghai"
6) "beijing"
##################################################################

geohash

geohash

返回11位的哈希值

##################################################################
# 返回11位的哈希值
127.0.0.1:6379> geohash china:city beijing # 返回当前城市的经纬度11位的哈希
1) "wx4fbxxfke0"	# 1维字符串 两个字符串约接近则距离越近
127.0.0.1:6379> geohash china:city xian # 返回当前城市的经纬度11位的哈希
1) "wqj6zky6bn0"
##################################################################

zset操作geo

##################################################################
127.0.0.1:6379> zrange china:city 0 -1 # 查看地图中全部元素
1) "chongqing"
2) "xian"
3) "shengzhen"
4) "hangzhou"
5) "shanghai"
6) "beijing"
127.0.0.1:6379> zrem china:city chongqing # 移除一个城市
(integer) 1
##################################################################

2.hyperloglog

什么是基数?

A:{1,3,5,7,8,7}

B:{1,3,5,7,8}

基数就是不重复的元素

A B 的基数=5 可以接受误差

hyperloglog简介:

redis2.8.9版本就更新了hyperloglog数据结构

redis 的 hyperloglog 使用来做基数统计的算法

网页的uv(页面访问量,一个人访问网站多次)

  • 第一种做法是set或者语言的set数据类型
    • 无误差
    • 占用资源多
  • 第二种redis-hyperloglog
    • 有误差
    • 占用内存小且固定

pfadd

添加

pfcount

数量

pfmerge

合并

##################################################################
# 用户访问量统计
127.0.0.1:6379> pfadd mykey a b c d e f g h i	# 创建第一组元素
(integer) 1
127.0.0.1:6379> pfadd mykey1 h i j k l m n o p q i s t # 创建第二组元素
(integer) 1
127.0.0.1:6379> pfcount mykey # 统计第一组的基数数量
(integer) 9
127.0.0.1:6379> pfcount mykey1 # 统计第二组的基数数量
(integer) 12
127.0.0.1:6379> pfmerge mykey3 mykey mykey1 # 合并两组生成第三组(并集)
OK
127.0.0.1:6379> pfcount mykey3
(integer) 18
##################################################################

3.Bitmaps

位存储

统计疫情感染人数:0 1 0 1 0 1

统计用户信息(活跃的和不活跃的)、用户登陆状态、打卡,这种只有两个状态的都可以用bitmap!

bitmap位图也是一种数据结构,所有的东西操作二进制来记录,只有0和1

##################################################################
# setbit key offset value # 统计周一到周日的打卡情况 0 未打卡 1 打卡
127.0.0.1:6379> setbit user:1:sign 1 0
(integer) 0
127.0.0.1:6379> setbit user:1:sign 2 1
(integer) 0
127.0.0.1:6379> setbit user:1:sign 3 1
(integer) 0
127.0.0.1:6379> setbit user:1:sign 4 1
(integer) 0
127.0.0.1:6379> setbit user:1:sign 5 1
(integer) 0
127.0.0.1:6379> setbit user:1:sign 6 1
(integer) 0
127.0.0.1:6379> setbit user:1:sign 7 0
(integer) 0
# getbit key offset 获取具体某天是否打卡
127.0.0.1:6379> getbit user:1:sign 1
(integer) 0
127.0.0.1:6379> getbit user:1:sign 2
(integer) 1
127.0.0.1:6379> getbit user:1:sign 3
(integer) 0
# 统计打了几天卡
127.0.0.1:6379> bitcount user:1:sign 0 -1
(integer) 4
127.0.0.1:6379> bitcount user:1:sign
(integer) 4
##################################################################

Redis高级

1.Redis-事务

事务基础

redis事务的本质:一组命令的集合!一个事务的所有命令都会被序列化,在事务的执行过程中会按照顺序执行

  • 一致性
  • 顺序选
  • 排它性
队列 set set set 执行
  • 没有隔离级别的概念

原子性:要么同时成功,要么同时失败

所有的命令在事务中只有执行的时候才会执行

redis的单条命了是保证原子性的,但是事务不保证原子性

redis的事物:

  • 开启事务
  • 命令入队
  • 执行事务

正常执行事务

##################################################################
127.0.0.1:6379> multi	# 开启事务
OK
127.0.0.1:6379> set k1 v1 # 命令入队
QUEUED
127.0.0.1:6379> set k2 v2 # 命令入队
QUEUED
127.0.0.1:6379> get k1 # 命令入队
QUEUED
127.0.0.1:6379> get k2 # 命令入队
QUEUED
127.0.0.1:6379> exec # 执行事务中的命令
1) OK
2) OK
3) "v1"
4) "v2"
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2  v2
QUEUED
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> DISCARD	# 取消事务的执行
OK
##################################################################

编译时错误(错误的命令)

##################################################################
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> setget k2	# 命令错误则事务中命令全部错误
(error) ERR unknown command `setget`, with args beginning with: `k2`,
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
##################################################################

运行时错误(命令没错,用在了不该用的地方)

##################################################################
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> incr k1	# v1是str不能incr 此条命令错了不影响事务
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) ERR value is not an integer or out of range
3) OK
4) "v1"
5) "v2"
##################################################################

监控

悲观锁

  • 很悲观,认为什么时候都会出问题,无论做什么都会加锁!

乐观锁-面试常问 秒杀并发场景

  • 很乐观,认为什么时候都不会有问题,所以不会上锁!更新数据的时候去判断一下,此期间是否修改过这个数据!
  • 获取version
  • 更新的时候比较version
# 乐观锁 正常状态
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money	# 监视money对象
OK
127.0.0.1:6379> MULTI	# 事务正常结束,数据期间有变动
OK
127.0.0.1:6379> DECRBY money 20
QUEUED
127.0.0.1:6379> incrby out 20
QUEUED
127.0.0.1:6379> get money
QUEUED
127.0.0.1:6379> get out
QUEUED
127.0.0.1:6379> exec
1) (integer) 80
2) (integer) 20
3) "80"
4) "20"
  • 两个线程模拟乐观锁

    Redis server v=6.0.8

# 线程1
127.0.0.1:6379> MULTI	# 1
OK
127.0.0.1:6379> incrby money 200	#2
QUEUED
127.0.0.1:6379> exec	# 4
1) (integer) 1200
127.0.0.1:6379> get money	# 5
"1200"
# 线程2
127.0.0.1:6379> set money 1000	# 3
OK
127.0.0.1:6379> get money	# 6
"1200"
  • mysql 乐观锁

  • 在老版本中事务会执行失败,返回nil,现在新版本不会了,新版本会返回执行之后的结果?

  • 监控失败后unwatch取消监控,再watch重新监控

2.Redis.conf文件详解

启动的时候,就是通过redis.conf启动的

单位配置

# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes

包含

image-20210618102912610

  • 可以包含其他配置文件

网络

bind 127.0.0.1 # 绑定的ip
protected-mode yes # 保护模式
port 6379 # 端口

通用配置

daemonize yes # 以守护进程的方式运行,默认是no,自己开启yes

pidfile /var/run/redis_6379.pid # 如果以后台方式运行要指定一个pid文件

# Specify the server verbosity level.
# This can be one of:
# debug (a lot of information, useful for development/testing)	# 测试开发
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)	# 通知 (默认生产)
# warning (only very important / critical messages are logged) # 重要信息
loglevel notice # 日志级别

logfile "" # 指定的日志文件位置

databases 16 # 数据库数量

always-show-logo yes # 是否显示logo

快照 持久化规则

redis是内存数据库,没有持久化数据就没了

#   save ""
save 900 1		# 900秒内(15分钟)至少1个key修改了一次 就进行持久化操作
save 300 10		# 300秒内(5分钟)至少10个key修改了一次 就进行持久化操作
save 60 10000	# 60秒内(1分钟)至少10000个key修改了一次 就进行持久化操作
# 持久化时候要自己配置
stop-writes-on-bgsave-error yes	# 持久化出错是否继续工作
rdbcompression yes	# 是否压缩rdb文件
rdbchecksum yes# 保存rdb文件的时候进行错误的验证
dir /var/lib/redis # 默认的保存目录

REPLICATION 主从复制 后面讲

security密码

在配置文件修改security

在redis-cli中修改

127.0.0.1:6379> config get requirepass	# 默认没密码
1) "requirepass"
2) ""
127.0.0.1:6379> config set requirepass root	# 设置密码
OK
127.0.0.1:6379> set k1 v1	# 设置失败
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth root	# 验证
OK	
127.0.0.1:6379> set k1 v1	# 设置成功
OK

限制

maxclients 10000 # 限制最大客户端数量
maxmemory <bytes> # redis最大内存容量
maxmemory-policy noeviction	# 内存达到上限的处理方式
#### maxmemory-policy 六种方式
1、volatile-lru:只对设置了过期时间的key进行LRU(默认值) 
2、allkeys-lru : 删除lru算法的key  
3、volatile-random:随机删除即将过期key  
4、allkeys-random:随机删除  
5、volatile-ttl : 删除即将过期的  
6、noeviction : 永不过期,返回错误

append only模式 aof

appendonly no	# 默认不开启aof持久化,默认是rdb持久化

appendfilename "appendonly.aof"	# 持久化文件名

# appendfsync always	# 每次修改都会同步 速度慢 消耗性能
appendfsync everysec	# 每秒执行一次 可能会丢失一秒的数据
# appendfsync no			# 不同步 操作系统自己同步 速度最快

具体的配置在持久化中详细说

3.Redis持久化

面试和工作,持久化都是重点

redis是内存数据库,如果不保存硬盘,断电丢失

RDB

在主从复制中,rdb就是在丛机上备用的

image-20210618110901194

image-20210618110737744

rdb保存的文件叫dump.rdb文件

# redis.conf 快照
dbfilename dump.rdb
save 60 5	# 60秒内(1分钟)至少5个key修改了一次 就进行持久化操作
# 此时删除默认的dump.rdb文件 在redis中save一次 只要1min中执行5次操作就会保存一个dump.rbd文件
# flashall 默认产生一个rdb文件

触发机制

1、save的规则满足

2、flushall 会触发

3、退出redis会产生.rdb文件

备份会生成一个dump.rdb文件

如果恢复rdb?

将rdb文件放在redis启动目录就好了,redis启动会检查

127.0.0.1:6379> config get dir	# 获取启动目录
1) "dir"
2) "/Users/root"

rdb模式默认的配置就够了

优点和缺点

  • 优点
    • 大规模、效率高
    • 如果对数据完整性要求不高
  • 缺点
    • 需要一定的时间间隔!如果redis意外宕机,最后一次的修改数据就没了。

生产环境需要备份

AOF(append only file)

image-20210618113016293

以日志的形式来记录每一次的写操作,将redis执行过的指令记录下来,只需追加文件但不可以改写文件,redis启动之初就会读取该文件重新构建数据,redis重启的话就根据日志文件的内容将写指令从前至后的执行一遍已完成数据恢复的工作。

aof保存的文件是appendonly.aof文件

aof

appendonly yes # 修改文yes后就开启了aof模式
# 重启就可以生效

image-20210618113900702

如果aof文件有问题,可以通过redis-check-aof来恢复aof文件

redis-check-aof --fix appendonly.aof	# 修复aof文件
cat appendonly.aof
image-20210618115117973

如果aof文件大于64m,太大了,会rewrite同一个新文件ÅÅ

优点和缺点

配置

appendonly no	# 默认不开启aof持久化,默认是rdb持久化

appendfilename "appendonly.aof"	# 持久化文件名

# appendfsync always	# 每次修改都会同步 速度慢 消耗性能
appendfsync everysec	# 每秒执行一次 可能会丢失一秒的数据
# appendfsync no			# 不同步 操作系统自己同步 速度最快
  • 优点
    • 每一次修改都同步,文件的完整性会更好
    • 每秒同步一次,会丢失疫苗的数据
    • 从不同步,效率最高
  • 缺点
    • 校队数据文件来说,aof大于rdb,修复速度也比rdb慢
    • aof运行比rdb慢,所以默认是rdb

扩展

image-20210618115354959

image-20210618115404885

4.Redis-pubsub

Redis发布订阅是一种消息通信方式

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

image-20210618115703051

image-20210618115916867

image-20210618115939705

订阅端

127.0.0.1:6379> SUBSCRIBE bilibili	# 监听bilibili channel
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "bilibili"
3) (integer) 1
1) "message"
2) "bilibili"
3) "222"
1) "message"
2) "bilibili"
3) "333"

发布端

127.0.0.1:6379> PUBLISH bilibili 111
(integer) 0
127.0.0.1:6379> PUBLISH bilibili 222
(integer) 1
127.0.0.1:6379> PUBLISH bilibili 333
(integer) 1

5.Redis主从复制

概念

image-20210618120634717

只要在公司中,主从复制是必须的,不可能单机使用redis

默认情况下每一个服务器都是一个主节点

环境配置

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0
master_replid:927770df422f4af03f043417cd9412b0804e2d07
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

复制和修改配置文件

cd /etc
cp redis.conf redis79.conf
cp redis.conf redis80.conf
cp redis.conf redis81.conf
vim redis79.conf
logfile /var/log/redis/redis6379.log
dbfilename dump6379.rdb
vim redis80.conf
port 6380
pidfile /var/run/redis_6380.pid
logfile /var/log/redis/redis6380.log
dbfilename dump6380.rdb
vim redis81.conf
port 6381
pidfile /var/run/redis_6381.pid
logfile /var/log/redis/redis6381.log
dbfilename dump6381.rdb

image-20210618125321001

搭建一主二从

默认情况下每一台机器都是主节点

# 6379
[root@iZ2ze614mku6kvinfevd3gZ etc]# redis-cli -p 6379
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0
master_replid:96ee8cc75300d4b10e9d1bf3a36978c8db94b7c4
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6379> 
# 6380
[root@iZ2ze614mku6kvinfevd3gZ ~]# redis-cli -p 6380
127.0.0.1:6380> ping
PONG
127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:0
master_replid:16ad10c9d1c515793792c1c01fb9b6e622831075
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
# 6381
[root@iZ2ze614mku6kvinfevd3gZ ~]# redis-cli -p 6381
127.0.0.1:6381> ping
PONG
127.0.0.1:6381> info repolication
127.0.0.1:6381> info replication
# Replication
role:master
connected_slaves:0
master_replid:7203c9f5e9fb0266994fa073e2621874e3a60cfe
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

只需要配置从机,配置从机就是认老大

第一种方式:redis-cli配置

# 给6380指定主机器未6379
127.0.0.1:6380> SLAVEOF 127.0.0.1 6379
OK
127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:0
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:d5ba26d8b45a4b2521224f693020fd6f321f36e0
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:0
# 给6381指定主机器未6379
127.0.0.1:6381> SLAVEOF 127.0.0.1 6379
OK
127.0.0.1:6381> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:28
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:d5ba26d8b45a4b2521224f693020fd6f321f36e0
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:28
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:29
repl_backlog_histlen:0
# 查看主机信息
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6380,state=online,offset=84,lag=1	# 从机1
slave1:ip=127.0.0.1,port=6381,state=online,offset=84,lag=1	# 从机2
master_replid:d5ba26d8b45a4b2521224f693020fd6f321f36e0
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:84
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:84
127.0.0.1:6379> 

第二种方式:redis.conf(生产)

image-20210618130639525

细节

  • 主机用来写
  • 从机用来读
# 6379主机
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> set k1 v1
OK
# 6380从机
127.0.0.1:6380> get k1
"v1"
127.0.0.1:6380> set k2 v2
(error) READONLY You can't write against a read only replica.	# readonly
# 6381从机
127.0.0.1:6381> get k1
"v1"
127.0.0.1:6381> set k2 v2
(error) READONLY You can't write against a read only replica. # readonly

到此 主从复制 读写分离搭建成功!!!

测试:主机断开了连接,从机依旧连接到主机,但是没有写操作。这个时候,主机如果回来了,从机依旧可以连接到主机

如果使用命令连接的主从买这个时候如果 从机重启了,从机就会变成主机,要重新配置。Å

复制原理

image-20210618132846417

第一种模式

image-20210618133421289

第二种模式

image-20210618133536860

6.宕机之后的手动配置

"""谋朝篡位"""

如果主机宕机了,我们要手动配置一个老大

在从机上执行

slaveof no one # 没有老大了 让自己当老大

如果老大修复了,只能重新配置

7.哨兵模式(面试高频)

自动选择老大

image-20210618134521882

image-20210618134554176

image-20210618134427912

测试

目前的状态是1主2从

配置哨兵配置文件

cd /etc
vim sentinel.conf
# sentinel monitor 被监控的名称 ip port 1
sentinel monitor myredis 127.0.0.1 6379 1

启动哨兵redis-sentinel sentinel.conf

[root@iZ2ze614mku6kvinfevd3gZ etc]# redis-sentinel sentinel.conf 
12975:X 18 Jun 2021 13:49:39.021 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
12975:X 18 Jun 2021 13:49:39.021 # Redis version=5.0.3, bits=64, commit=00000000, modified=0, pid=12975, just started
12975:X 18 Jun 2021 13:49:39.021 # Configuration loaded
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 5.0.3 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in sentinel mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 26379
 |    `-._   `._    /     _.-'    |     PID: 12975
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

12975:X 18 Jun 2021 13:49:39.022 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
12975:X 18 Jun 2021 13:49:39.024 # Sentinel ID is 40dbf0afce0b9edcca36d5f56da3892ec1032cef
12975:X 18 Jun 2021 13:49:39.024 # +monitor master myredis 127.0.0.1 6379 quorum 1
12975:X 18 Jun 2021 13:49:39.025 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
12975:X 18 Jun 2021 13:49:39.027 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379

如果主节点断开,会根据投票算法选出合适的机器作为master

如果主机回来了会归并为从机

12975:X 18 Jun 2021 13:53:08.034 # +sdown master myredis 127.0.0.1 6379
12975:X 18 Jun 2021 13:53:08.034 # +odown master myredis 127.0.0.1 6379 #quorum 1/1
12975:X 18 Jun 2021 13:53:08.034 # +new-epoch 1
12975:X 18 Jun 2021 13:53:08.034 # +try-failover master myredis 127.0.0.1 6379
12975:X 18 Jun 2021 13:53:08.035 # +vote-for-leader 40dbf0afce0b9edcca36d5f56da3892ec1032cef 1
12975:X 18 Jun 2021 13:53:08.035 # +elected-leader master myredis 127.0.0.1 6379
12975:X 18 Jun 2021 13:53:08.035 # +failover-state-select-slave master myredis 127.0.0.1 6379
12975:X 18 Jun 2021 13:53:08.125 # +selected-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379
12975:X 18 Jun 2021 13:53:08.125 * +failover-state-send-slaveof-noone slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379
12975:X 18 Jun 2021 13:53:08.180 * +failover-state-wait-promotion slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379
12975:X 18 Jun 2021 13:53:09.081 # +promoted-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379
12975:X 18 Jun 2021 13:53:09.081 # +failover-state-reconf-slaves master myredis 127.0.0.1 6379
12975:X 18 Jun 2021 13:53:09.169 * +slave-reconf-sent slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
12975:X 18 Jun 2021 13:53:10.093 * +slave-reconf-inprog slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
12975:X 18 Jun 2021 13:53:10.093 * +slave-reconf-done slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
12975:X 18 Jun 2021 13:53:10.192 # +failover-end master myredis 127.0.0.1 6379
12975:X 18 Jun 2021 13:53:10.192 # +switch-master myredis 127.0.0.1 6379 127.0.0.1 6381
### 6381成为主机
12975:X 18 Jun 2021 13:53:10.192 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6381
12975:X 18 Jun 2021 13:53:10.192 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ myredis 127.0.0.1 6381

优点和缺点

image-20210618135437651

哨兵模式的全配置

image-20210618135524874

image-20210618135656410

image-20210618135734333

image-20210618135842731

8.缓存穿透和缓存雪崩

面试高频,工作常用

缓存穿透:查不到

概念

image-20210618140620489

解决方案

布隆过滤器

image-20210618140549693

缓存空对象

image-20210618140449821

缓存击穿:量太大

概念

image-20210618140736101

解决方案

热点数据不过期

image-20210618140943743

互斥锁

image-20210618140955200

image-20210618141210909

缓存雪崩

概念

image-20210618141248500

image-20210618141619601

image-20210618141342391

解决方案

image-20210618141457346

posted @ 2021-06-19 18:55  GokuBlog  阅读(204)  评论(0)    收藏  举报