兴趣是最好的老师!

欣赏狂神:在外面做自己喜欢的事情,就算吃不饱饭,不愿意打工!

之前的感悟:打工仔只是创业者的衍生物丶

NoSQL概述

架构师有一个套路:什么东西都加一个中间层

数据库解决方案

  • cache(缓存,解决读的压力)

  • 垂直拆分(读写分离、主从复制,读写的时候锁表锁行,影响效率)

  • 水平拆分(分库分表(集群),解决写的压力)

NoSQL特点

  • 方便扩展(数据之间没有关系)

  • 大数据量高性能(Redis一秒写8万次,读11万次;NoSQL的缓存是记录级、细粒度的缓存,性能高)

  • 数据类型是多样型的(不需要事先设计数据库,设计数据库据说需要天赋)

RDBMS(关系型数据库)和NOSQL对比

传统RDBMS

- 结构化组织- sql- 数据和关系都存在单独的表中- 操作数据库定义语言- 严格的一致性- 基础的事务- ……

NOSQL

- 不仅仅是数据- 没有固定的查询语言- 键值对存储(Redis)、列存储(大数据Hbase)、文档存储(MongoDB)、图形数据库(Neo4j社交关系)- 最终一致性- cap 定理 和 base 理论(异地多活)只要学不死就往死里学- 高性能,高可用,高可扩- ……

3V3高

大数据时代的3V

  1. 海量Volume

  2. 多样Variety

  3. 实时Velocity

互联网需求的3高:

  1. 高并发

  2. 高可拓

  3. 高性能

NoSQL + RDBMS 结合使用才是最强大的!

NoSQL的四大分类

KV键值对:

  • sina:redis

  • meituan:redis+tair

  • ali:redis+memcached

文档型数据库(bjson):

  • Mongodb

    • 分布式文件存储数据库,c++,主要用以处理大量文档

    • mongodb是介于关系型数据库和非关系型数据库中间的产品,是非关系型数据库中功能最丰富、最像关系型数据库的

  • conthdb

列存储数据库

图关系数据库

所有牛逼的人,都有一段苦逼的岁月丶但是需要去像傻x一样的去坚持!

Redis介绍

https://www.redis.net.cn/

http://www.redis.cn/

概述

- Remote Dictionary Server,远程字典服务- 是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。- 免费和开源!是当下最热门的nosql技术之一!也被称之为结构化数据库!

功能

- 持久化的两种机制:RDB、AOF- 效率高,可用于高速缓存- 发布订阅(简单的消息队列的活)- 地图信息分析- 计时器,计数器(浏览量)

特性

- 多样的数据类型- 持久化- 集群- 事务

Redis单机版安装

docker方式搭建
docker pull redisdocker imagesmkdir /usr/local/rediswget -P /usr/local/redis http://download.redis.io/redis-stable/vi /usr/local/redis/

6379是九宫格输入法MERZ,代表作者信奉的一种理念:but with very technical value, or with an impressive amount of skills and patience and work involved, but still... stupid.

如果要用Java程序连接,关闭保护模式(估计配置文件中也可以事先修改)

[root@10-9-48-229 ~]

redis-benchmark性能测试

Redis基础命令

[root@10-9-48-229 ~]# docker exec -it redis /bin/bash
root@90702770fe66:/data# redis-cli -p 6379
> select 3 # 切换数据库
OK
[3]> dbsize # 查看db大小
(integer) 0
[3]> set name xiaoming #写入数据
OK
[3]> dbsize # 发现大小变化了
(integer) 1
[3]> select 7 # 验证不用的数据放在不同的库内
OK
[7]> dbsize
(integer) 0
[7]> get name
(nil)
[7]> select 3
OK
[3]> get name
"xiaoming"
[3]> flushdb # 清空当前db
OK
[3]> keys *
(empty array)
[3]> select 0 # 验证清空所有库的数据
OK
> keys *
1) "myhash:{tag}"
2) "counter:{tag}:__rand_int__"
3) "mylist:{tag}"
4) "key:{tag}:__rand_int__"
> select 3
OK
[3]> flushall
OK
[3]> select 0
OK
> keys *
(empty array)

redis是单线程的!redis是基于内存操作,cpu不是redis的性能瓶颈,其瓶颈是机器的内存和网络带宽。

redis为什么单线程还这么快?

  1. 高性能的服务器不一定是多线程的

  2. 多线程不一定比单线程效率高(cpu上下文切换消耗资源,redis将所有的数据放在内存,单线程效率更高)

五大数据类型

Redis-Key操作命令,对应Java API

> exists name # 判断key是否存在
(integer) 1
> keys *
1) "age"
2) "name"
> move name 1 # 移除key
(integer) 1
> keys *
1) "age"
> set name xx
OK
> get name
"xx"
> expire name 10 # 设置key的过期时间
(integer) 1
> ttl name # 查看key的剩余时间
(integer) 6
> ttl name
(integer) -2 # -2表示已经过期,等于是移除了
> set name xx
OK
> type name # 查看类型
string
String

API调用工程师!

> set key1 v1
OK
> exists key1
(integer) 1
> append key1 "hello" # 字符串追加,如果不存在,就set一个
(integer) 7
> get key1
"v1hello"
> strlen key1 # 获取String长度
(integer) 7
> append key1 ",xiaoming"
(integer) 16
> get key1
"v1hello,xiaoming"

操作数值类型

> set views 0
OK
> get views
"0"
> incr views # 自增1
(integer) 1
> incr views
(integer) 2
> decr views # 自减1
(integer) 1
> incrby views 10 # 自增,步长10
(integer) 11
> decrby views 6 # 自减,步长6
(integer) 5

字符串获取范围

> clear
> flushdb
OK
> keys *
(empty array)
> set key1 "hello,xiaoming"
OK
> getrange key1 0 3 # 截取字符串 [0,3]
"hell"
> getrange key1 0 -1 # 同get key1
"hello,xiaoming"

替换字符串中的某一段

> clear
> set key2 abcdefg
OK
> get key2
"abcdefg"
> setrange key2 1 xx # 替换指定位置开始的字符串
(integer) 7
> get key2
"axxdefg"

设置过期时间

> setex key3 30 "hello"
OK
> ttl key3
(integer) 24
> get key3
"hello"

不存在再设置,存在就创建失败。

分布式锁中常使用

> setnx mykey "redis"
(integer) 1
> get mykey
"redis"
> setnx mykey "MongoDB"
(integer) 0
> get mykey
"redis"

批量设置

> flushdb
OK
> mset k1 v1 k2 v2 k3 v3
OK
> keys *
1) "k1"
2) "k2"
3) "k3"
> mget k1 k2 k3
1) "v1"
2) "v2"
3) "v3"
> msetnx k1 v11 k4 v4 # 原子性操作,要么一起成功、要么一起失败
(integer) 0 # 未设置成功,因为k1已经存在了(nx表示not exists)
> mget k1 k2 k3 k4
1) "v1"
2) "v2"
3) "v3"
4) (nil)

实用操作:保存对象

# set user:1 {name:zhangsan,age:3} # 设置user1对象,json保存对象
# 或使用下面的方式
> mset user:1:name zhangsan user:1:age 12
OK
> mget user:1:name user:1:age
1) "zhangsan"
2) "12"

组合命令:getset更新操作

> getset db redis
(nil)
> get db
"redis"
> getset db mongodb
"redis"
> get db
"mongodb"
List

在Redis里,可以把List搞成队列、栈、阻塞队列。

[root@10-9-48-229 ~]# docker exec -it redis /bin/bash
root@90702770fe66:/data# redis-cli -p 6379
> lpush list one # 将一个或多个值插入列表的头部(左) 这里list表示名称
(integer) 1
> lpush list two
(integer) 2
> lpush list three
(integer) 3
> lrange list 0 -1
1) "three"
2) "two"
3) "one"
> lrange list 0 1
1) "three"
2) "two"
> rpush list right # 将一个或多个值插入到列表的尾部(右)
(integer) 4
> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
> lpop list # 移除第一个元素
"three"
> lrange list 0 -1
1) "two"
2) "one"
3) "right"
> rpop list # 移除最后一个元素
"right"
> lrange list 0 -1
1) "two"
2) "one"
> lindex list 0 # 根据下标获取元素
"two"
> lindex list 1
"one"
> llen list # 返回列表的长度
(integer) 2
> lrem list 1 one # 移除一个one元素
(integer) 1
> lrange list 0 -1
1) "three"
2) "three"
3) "two"
> lrem list 1 three
(integer) 1
> lrange list 0 -1
1) "three"
2) "two"
> lpush list three
(integer) 3
> lrange list 0 -1
1) "three"
2) "three"
3) "two"
> lrem list 2 three # 移除两个three元素
(integer) 2
> lrange list 0 -1
1) "two"
> flushdb
OK
> rpush mylist "hello"
(integer) 1
> rpush mylist "hello1"
(integer) 2
> rpush mylist "hello2"
(integer) 3
> rpush mylist "hello3"
(integer) 4
> ltrim mylist 1 2 # 剔除列表两头的不要的元素
OK
> lrange mylist 0 -1
1) "hello1"
2) "hello2"
> rpoplpush mylist mylist2 # 移除队尾元素并将其添加到另一个队列的头部
"hello2"
> lrange mylist 0 -1
1) "hello1"
> lrange mylist2 0 -1
1) "hello2"
1) "hello2"
> clear
> flushdb
OK
> exists list
(integer) 0
> lpush lista value1
(integer) 1
> lrange lista 0 0
1) "value1"
> lset lista 0 item1 # 重写/覆盖第0个元素
OK
> lrange lista 0 0
1) "item1"
> lset lista 1 item # 如果不存在,则会报错
(error) ERR index out of range
> flushdb
OK
> rpush mylist hello
(integer) 1
> rpush mylist world
(integer) 2
> linsert mylist before "world" "other" # 插入元素
(integer) 3
> lrange mylist 0 -1
1) "hello"
2) "other"
3) "world"
> linsert mylist after "world" "new" # 插入元素
(integer) 4
> lrange mylist 0 -1
1) "hello"
2) "other"
3) "world"
4) "new"

小结

- List实际上是一个链表,before node after,left,right都可以插入值;
- 如果key不存在,创建新的链表;
- 如果key存在,新增元素;
- 如果移除了所有值,也代表List不存在了;
- 在两边插入和改动值,效率高一些,操作中间元素,效率低一些。
Set

无序不重复集合

> flushdb
OK
> sadd myset "hello" # 往set集合中加元素
(integer) 1
> sadd myset "xiaoming"
(integer) 1
> sadd myset "hahahahahah"
(integer) 1
> smembers myset # 查看集合中的所有成员
1) "hahahahahah"
2) "xiaoming"
3) "hello"
> sismember myset hello # 判断某成员是否在集合中
(integer) 1
> sismember myset world
(integer) 0
> sadd myset "hahahahahah" # 添加重复的值会失败
(integer) 0
> scard myset # 查看集合中成员个数
(integer) 3
> srem myset hello # 移除集合中某个元素
(integer) 1
> smembers myset
1) "hahahahahah"
2) "xiaoming"
> smembers myset
1) "hahahahahah"
2) "test1"
3) "test2"
4) "xiaoming"
5) "test3"
> srandmember myset # 随机抽出一个元素
"test3"
> srandmember myset
"hahahahahah"
> srandmember myset
"xiaoming"
> srandmember myset 2 # 随机抽出两个元素
1) "hahahahahah"
2) "xiaoming"
> smembers myset
1) "test1"
2) "test2"
3) "hahahahahah"
4) "xiaoming"
5) "test3"
> spop myset # 随机删除set集合中的元素
"test2"
> smembers myset
1) "test1"
2) "hahahahahah"
3) "xiaoming"
4) "test3"
> flushdb
OK
> sadd myset "hello"
(integer) 1
> sadd myset "world"
(integer) 1
> sadd myset "love"
(integer) 1
> sadd myset2 "set2"
(integer) 1
> smove myset myset2 "love" # 将集合中指定的值移动到另一个集合中
(integer) 1
> smembers myset
1) "world"
2) "hello"
> smembers myset2
1) "love"
2) "set2"
> flushdb
OK
> sadd key1 a
(integer) 1
> sadd key1 b
(integer) 1
> sadd key1 c
(integer) 1
> sadd key2 c
(integer) 1
> sadd key2 d
(integer) 1
> sdiff key1 key2 # 两个集合的差集
1) "a"
2) "b"
> sinter key1 key2 # 交集
1) "c"
> sunion key1 key2 # 并集
1) "d"
2) "a"
3) "c"
4) "b"
Hash

Key-Map集合

[root@10-9-48-229 ~]# docker exec -it redis /bin/bash
root@90702770fe66:/data# redis-cli -p 6379
> ping
PONG
> flushdb
OK
> hset myhash field1 xiaoming # set一个域和值
(integer) 1
> hget myhash field1 # get一个域
"xiaoming"
> hmset myhash field1 hello field2 world # m代表multiple指多个;set的时候field存在会覆盖
OK
> hmget myhash field1 field2 # 获取指定域的值
1) "hello"
2) "world"
> hgetall myhash # 获取所有域的值
1) "field1"
2) "hello"
3) "field2"
4) "world"
> hdel myhash field1 # 删除指定域
(integer) 1
> hgetall myhash
1) "field2"
2) "world"
> hlen myhash #得到域的个数
(integer) 1
> hexists myhash field1 # 判断hash中的某个域是否存在
(integer) 1
> hexists myhash field3
(integer) 0
> hkeys myhash # 得到该hash所有的域
1) "field2"
2) "field1"
> hvals myhash # 得到hash所有的值
1) "world"
2) "hello"
> hset myhash field3 5
(integer) 1
> hincrby myhash field5 1
(integer) 1
> hdel myhash field5
(integer) 1
> hincrby myhash field3 1 # 自增1
(integer) 6
> hincrby myhash field3 -1 # 自增-1
(integer) 5
> hsetnx myhash field4 hello # 不存在,则搞进去
(integer) 1
> hsetnx myhash field4 hello
(integer) 0

经常变动的信息可以用hash保存,适合存储对象

Zset

有序集合

> flushdb
OK
> zadd myset 1 one # 添加一个成员元素
(integer) 1
> zadd myset 2 two
(integer) 1
> zadd myset 3 three 4 four # 添加多个
(integer) 2
> zrange myset 0 -1 # 获取所有元素
1) "one"
2) "two"
3) "three"
4) "four"
> zadd salary 2500 xiaohong # 薪水 集合
(integer) 1
> zadd salary 5000 xiaoming
(integer) 1
> zadd salary 500  hahah
(integer) 1
> zrangebyscore salary -inf +inf # 排序 负无穷到正无穷 infinite无限的无穷尽的
1) "hahah"
2) "xiaohong"
3) "xiaoming"
> zrevrange salary 0 -1 # 排序,倒序排列
1) "xiaoming"
2) "hahah"
> zrangebyscore salary -inf +inf withscores # 排序输出 带上大小
1) "hahah"
2) "500"
3) "xiaohong"
4) "2500"
5) "xiaoming"
6) "5000"
> zrangebyscore salary -inf 2500 withscores
1) "hahah"
2) "500"
3) "xiaohong"
4) "2500"
> zrangebyscore salary -inf 2500 withscores
1) "hahah"
2) "500"
3) "xiaohong"
4) "2500"
> zrange salary 0 -1
1) "hahah"
2) "xiaohong"
3) "xiaoming"
> zrem salary xiaohong # 干掉小红
(integer) 1
> zcard salary # 统计有序集合中的个数
(integer) 2
> flushdb
OK
> zadd myset 1 hello 2 world 3 xiaoming
(integer) 3
> zcount myset 1 3 # 获取指定区间的成员数量
(integer) 3
> zcount myset 1 2
(integer) 2

SortedSets最佳实践

  • 班级成绩表、工资排序表

  • 普通消息、重要消息

  • 排行榜top100

三种特殊数据类型

Geospatial diz 地理位置

朋友的定位、附近的人、打车距离计算

> flushdb
OK
> geoadd china:city 116.41 39.90 beijing
(integer) 1
> geoadd china:city 121.47 31.23 shanghai 114.09 22.55 shenzhen # 添加城市
(integer) 2
> geoadd china:city 106.50 29.53 chongqing 120.15 30.28 hangzhou 108.96 34.27 xian
(integer) 3
> geopos china:city beijing # 获取指定城市的经度和纬度
1) 1) ""2) ""
> geopos china:city beijing chongqing
1) 1) ""2) ""
2) 1) ""2) ""
> geodist china:city beijing shanghai
""
> geodist china:city beijing shanghai km # 北京和上海之间的直线距离
""
> georadius china:city 110 30 1000 km # 以110 30为中心,搜索半径1000km内的城市
1) "chongqing"
2) "xian"
3) "shenzhen"
4) "hangzhou"
> georadius china:city 110 30 500 km
1) "chongqing"
2) "xian"
> georadius china:city 110 30 500 km withdist # 带上距离
1) 1) "chongqing"2) ""
2) 1) "xian"2) ""> georadius china:city 110 30 500 km withcoord
1) 1) "chongqing"2) 1) ""2) ""
2) 1) "xian"2) 1) ""2) ""
> georadius china:city 110 30 500 km withcoord withdist count 1
1) 1) "chongqing"2) ""3) 1) ""2) ""
> georadiusbymember china:city beijing 1000 km # 找城市附近的城市
1) "beijing"
2) "xian"
> georadiusbymember china:city shanghai 400 km
1) "hangzhou"
2) "shanghai"
> geohash china:city beijing chongqing # 将二维的经纬度位置转换为11位的hash字符串
1) "wx4fbzx4me0"
2) "wm5xzrybty0"
> zrange china:city 0 -1 # 本质还是集合,
1) "chongqing"
2) "xian"
3) "shenzhen"
4) "hangzhou"
5) "shanghai"
6) "beijing"
> zrem china:city beijing # 移除某个元素
(integer) 1
Hyperloglog

应用场景:统计网站访问量(可能存在的误差,优势是位运算,占用空间仅为固定12K)

# 集合形式 基数统计
> pfadd mykey a b c d e f g h i j # 创建第一组元素
(integer) 1
> pfcount mykey # 这个目测可以用来统计访问量
(integer) 10
> pfadd mykey2 i j z x c v b n m
(integer) 1
> pfcount mykey2
(integer) 9
> pfmerge mykey3 mykey mykey2 # 合并两组元素
OK
> pfcount mykey3
(integer) 15
Bitmap

位存储:用户是否活跃、员工是否打卡、登录或未登录(只要有两个状态的)

# 记录周一到周五打卡或未打卡
> setbit sign 0 1
(integer) 0
> setbit sign 1 0
(integer) 0
> setbit sign 2 0
(integer) 0
> setbit sign 3 1
(integer) 0
> setbit sign 4 1
(integer) 0
> setbit sign 5 0
(integer) 0
> setbit sign 6 0
(integer) 0
> getbit sign 3 # 查询周四是否打卡
(integer) 1
> bitcount sign # 查询打卡的总数
(integer) 3

事务

Redis事务:一组命令的集合。具有:一次性、顺序性、排他性。

Redis单条命令是保证原子性的,但是事务不保证原子性;没有隔离级别的概念

Redis的事务

  • 开启事务(multi)

  • 命令入队(……)

  • 执行事务(exec)

> multi # 开启事务
OK
# 命令入队
> set key1 v1
QUEUED
> set k2 v2
QUEUED
> get k2
QUEUED
> set k3 v3
QUEUED
> exec # 执行事务
1) OK
2) OK
3) "v2"
4) OK
# 测试 放弃事务
> multi
OK
> set k1 v1
QUEUED
> set k2 v2
QUEUED
> set k4 v4
QUEUED
> discard # 放弃事务
OK
> keys *
1) "key1"
2) "k2"
3) "k3"

编译型异常:事务中的所有命令都不会被执行

> flushdb
OK
> multi
OK
> set k1 v1
QUEUED
> set k2 v2
QUEUED
> getset k3 # 命令语法错误,会导致一系列命令都不被执行
(error) ERR wrong number of arguments for 'getset' command
> set k4 v4
QUEUED
> exec
(error) EXECABORT Transaction discarded because of previous errors.

运行时异常(类似Java 1/0、下标越界):错误命令抛出异常,其他命令正常执行

> clear
> flushdb
OK
> set k1 "v1"
OK
> multi
OK
> set k2 v2
QUEUED
> incr k1 # 这里出错,不影响前后命令
QUEUED
> set k3 v3
QUEUED
> exec
1) OK
2) (error) ERR value is not an integer or out of range
3) OK
> keys *
1) "k1"
2) "k2"
3) "k3"

用watch监控实现乐观锁丶

> flushdb
OK
> set money 100
OK
> set out 20
OK
> watch money # 监视 money 对象
OK
> multi
OK
> decrby money 20
QUEUED
> incrby out 20
QUEUED
> exec # 事务正常结束,监控会取消掉 否则需要执行unwatch
1) (integer) 80
2) (integer) 40
# 多线程测试:watch实现乐观锁
> watch money
OK
> multi
OK
> decrby money 10
QUEUED
> incrby out 10
QUEUED
> exec
(nil) # 下次需要先unwatch
# 执行 exec 命令之前 新开一个会话窗口,充当另一个线程 在上面的事务过程中修改了数据 被watch到了
[root@10-9-48-229 ~]# docker exec -it  redis /bin/bash
root@90702770fe66:/data# redis-cli -p 6379
> get money
"80"
> set money 1000
OK

Jedis

先建空项目,再建子项目,选好Java&maven环境及idea设置,api与上文的命令对应,源码见

SpringBoot整合

spring boot操作数据相关的内容都在spring-data里:jpa、jdbc、mongodb、redis等,spring boot和spring data齐名

jedis:直连,多线程不安全,避免的方法是连接池,但是造成server会特别大,更像BIO(阻塞)模式

lettuce:采用netty,实例可以在多个线程中进行共享,不存在线程不安全的问题,可以减少线程数量,更像NIO(非阻塞)模式

导入依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency><groupId>io.lettuce</groupId><artifactId>lettuce-core</artifactId>
</dependency>
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId>
</dependency>
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId>
</dependency>
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId>
</dependency>

配置连接

# spring-boot-autoconfigure-2.3.4.RELEASE.jar ->
# ->spring.factories
# ->RedisAutoConfiguration
# ->RedisProperties
spring.redis.host=
spring.redis.port=6379

测试

@SpringBootTest
class Redis02SpringbootApplicationTests {@Autowired@Qualifier("redisTemplate")//private RedisTemplate<String,String> redisTemplate;private RedisTemplate redisTemplate;@Autowiredprivate RedisUtil redisUtil;@Testvoid contextLoads() {//redisTemplate 操作不同的类型 api和我们的指令是一致的//opsForValue 操作字符串//opsForList  操作List//opsForSet//opsForHash//连接级别的操作通过:RedisConnection connection = ().getConnection();进行().set("myKey","小明dd");(().get("myKey"));}@Testpublic void test() throws JsonProcessingException {User user = new User("小明", 3);String jsonUser = new ObjectMapper().writeValueAsString(user);().set("user",jsonUser);(().get("user"));}@Testpublic void test2() {("kk", "nam");(("kk"));}
}

配置类、工具类见源码:解决中文、对象存储

详解

/usr/local/redis/,能看懂,就比新手厉害了丶行家有没有,出手就知道,一些小小的配置,就可以显著的优化性能,让你脱颖而出!

# 单位配置不区分大小写:1GB 1Gb 1gB
################################## INCLUDES ###################################
# 表示引入其他配置文件
################################## MODULES #####################################
# 加载.so文件,不重要
################################## NETWORK #####################################
# 网络
bind 127.0.0.1
# 表示只能在本地访问
protected-mode yes
# 受保护的模式,java连接的话需要将其设置为no
port 6379
# 端口设置
################################# TLS/SSL #####################################
# 不管
################################# GENERAL #####################################
# 通用设置
daemonize no
# 通常设置为yes,表示后台运行(守护进程方式)
pidfile /var/run/redis_6379.pid
# 配置文件的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
# 默认16个数据库
always-show-logo yes
# 是否总是显示logo
################################ SNAPSHOTTING  ################################
# 快照
# 持久化,在规定的时间内,执行了多少次操作,会持久化到文件.rdb .aof
save 900 1
# 900秒内,如果有1个key进行了修改,系统会进行持久化操作。下同
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
# 持久化出错后是否继续工作
rdbcompression yes
# 是否压缩rdb文件,需要消耗cpu资源
rdbchecksum yes
# 保存rdb文件时,进行错误的检查校验
dir ./
# rdb保存的目录,默认当前目录
################################# REPLICATION #################################
# 主从复制用
################################## SECURITY ###################################
# requirepass foobared
# 默认是没有密码,requirepass 123456,通常用命令进行设置密码:config set/get requirepass 123456
################################### CLIENTS ####################################
# maxclients 10000 最大客户端数量
############################## MEMORY MANAGEMENT ################################
# maxmemory <bytes> 最大内存容量
# maxmemory-policy noeviction 内存到达上限之后的处理策略(移除过期的key、报错等)
# noeviction: 不删除策略, 达到最大内存限制时, 如果需要更多内存, 直接返回错误信息。(默认值)
# allkeys-lru: 所有key通用; 优先删除最近最少使用(less recently used ,LRU) 的 key。
# volatile-lru: 只限于设置了 expire 的部分; 优先删除最近最少使用(less recently used ,LRU) 的 key。
# allkeys-random: 所有key通用; 随机删除一部分 key。
# volatile-random: 只限于设置了 expire 的部分; 随机删除一部分 key。
# volatile-ttl: 只限于设置了 expire 的部分; 优先删除剩余时间(time to live,TTL) 短的key。
############################## APPEND ONLY MODE ###############################
# aof相关配置
appendonly no
# 默认是不开启aof模式,默认使用rdb方式持久化,大部分情况rdb够用了
appendfilename ""
# 持久化文件的名字
# appendfsync always
# 每次修改都会同步(消耗性能)
appendfsync everysec
# 每秒执行一次sync,可能会丢失这1秒的数据
# appendfsync no
# 不同步,这个时候操作系统自己同步数据,速度最快

Redis持久化

RDB(Redis DataBase)

优:一个方便、恢复数据效率高、fork子进程性能好

劣:最后一次保存的快照信息可能会丢失、因为fork子进程导致服务短暂停滞

################################ SNAPSHOTTING  ################################
# 快照
# 持久化,在规定的时间内,执行了多少次操作,会持久化到文件.rdb .aof
save 900 1
# 900秒内,如果有1个key进行了修改,系统会进行持久化操作。下同
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
# 持久化出错后是否继续工作
rdbcompression yes
# 是否压缩rdb文件,需要消耗cpu资源
rdbchecksum yes
# 保存rdb文件时,进行错误的检查校验
dir ./
# rdb保存的目录,默认当前目录

Docker启动找不到目录可以输入docker inspect 容器名进行查看"Mounts":[{"Source": "/var/lib/docker/volumes/fc214b8d4ef0fbcf56d7cf799cc79e1d38ebfe9035a6cf6d2c60798db1bd1eb2/_data"

触发保存rdb的条件
- save设置的条件满足时
- 执行了flushall命令
- 退出redis(shutdown)时
用rdb恢复数据?只需要将文件放到redis的启动目录即可
通常只在从机上持久化RDB文件,并且只保留15分钟的方案
AOF(Append Only File)

优:每秒每修改和不同步带来更高的数据安全性、append这个动作就很温柔不影响以前记录且可以check、rewrite机制写到磁盘、格式清晰易理解

劣:文件较大、恢复慢

############################## APPEND ONLY MODE ###############################
# aof相关配置
appendonly no
# 默认是不开启aof模式,默认使用rdb方式持久化,大部分情况rdb够用了
appendfilename ""
# 持久化文件的名字
# appendfsync always
# 每次修改都会同步(消耗性能)
appendfsync everysec
# 每秒执行一次sync,可能会丢失这1秒的数据
# appendfsync no
# 不同步,这个时候操作系统自己同步数据,速度最快
修改配置文件开启aof,重启redis即可产生.aof文件,接下来每秒钟都会往里边进行append
挖槽,这个aof破坏之后,在docker环境下咋个模拟用check修复呢……

Redis发布订阅

SUBSCRIBE runoobChat
PUBLISH runoobChat "Redis PUBLISH test"

搭建3主3从(太监)

三主三从,无中心节点

先保证云主机端口是开启的:7001-7006,17001-17006

拉取镜像

docker pull redis

新建文件夹redis-cluster2

mkdir /usr/local/redis-cluster2

新建文件(配置文件的模板,在中会使用)

vim 

内容如下

##设置外部网络连接redis服务,默认是yes,即开启。开启protected-mode保护模式,需配置bind ip或者设置访问密码,关闭protected-mode模式,此时外部网络可以直接访问
protected-mode no
##节点端口
port ${PORT}
##指定redis是否要用守护线程的方式启动,默认no
daemonize no
##持久化模式
appendonly yes
##cluster集群模式
cluster-enabled yes
##集群配置名
cluster-config-file nodes.conf
##超时时间
cluster-node-timeout 15000
##实际为各节点网卡分配ip
cluster-announce-ip
##节点映射端口
cluster-announce-port ${PORT}
##节点总线端
cluster-announce-bus-port 1${PORT}
##连接密码(可选)
requirepass 123456

新建脚本创建目录及配置文件

vim 

内容如下

for port in `seq 7001 7006`; do \base=6999 \&& ip=$[port-base] \&& mkdir -p ${port}/conf \&& PORT=${port} TEMP=${ip} envsubst <  > ${port}/conf/ \&& mkdir -p ${port}/data;\
done

赋予执行权限

chmod 755 

创建自定义网桥

docker network create redis-net

创建启动docker模板(启动docker,试想这些可能事不同机器上的docker及容器)

vi 

内容如下

for port in `seq 7001 7006`; dodocker run -p ${port}:${port} -p 1${port}:1${port} --name redis-${port} \-v /usr/local/redis-cluster2/${port}/conf/:/usr/local/etc/redis/ \-v /usr/local/redis-cluster2/${port}/data:/data --name redis-${port} --net redis-net -d  redis  redis-server /usr/local/etc/redis/;
done

说明

--name redis-${port}:容器的名字
-d redis:拉取的镜像名字 redis构建启用容器
redis-server /usr/local/etc/redis/::用/usr/local/etc/redis/文件作为启动redis的配置文件

赋予执行权限

chmod 755 

执行脚本

./

执行结果

[root@10-9-48-229 redis-cluster2]# ./
[root@10-9-48-229 redis-cluster2]# ls
7001  7002  7003  7004  7005  7006
[root@10-9-48-229 redis-cluster2]# tree
.
├── 7001
│   ├── conf
│   │   └──
│   └── data
├── 7002
│   ├── conf
│   │   └──
│   └── data
├── 7003
│   ├── conf
│   │   └──
│   └── data
├── 7004
│   ├── conf
│   │   └──
│   └── data
├── 7005
│   ├── conf
│   │   └──
│   └── data
├── 7006
│   ├── conf
│   │   └──
│   └── data
├──
├──
└── 18 directories, 9 files

执行脚本

./

执行结果

[root@10-9-48-229 redis-cluster2]# ./
f0018b73a7f994bd50fdca15f137ff2f955b9dbb9104797bccb1c0a593c7de7d
cfecb00ba432a2152439c7c51f680fe11e126f4c3ce08039bf033a32d160d610
6431a01bc762596e300b97b4bf340a89e661ae939b30b7adc22bd948ca2efa0d
ba7326b91058c24ef3028cc5ed6fc7696c07d045c7ec7b8f277f6aa6cd3286e7
7cbc9f1ece227f059869f1d331e3a30002a4cd80612a7a2d994859afcb5c88bd
19cca5cd14fb2e4529d60ae8ba7263daed00da98ca5285396977ee36ccf14627
[root@10-9-48-229 redis-cluster2]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                                        NAMES
19cca5cd14fb        redis               "…"   2 minutes ago       Up 2 minutes        0.0.0.0:7006->7006/tcp, 6379/tcp, 0.0.0.0:17006->17006/tcp   redis-7006
7cbc9f1ece22        redis               "…"   2 minutes ago       Up 2 minutes        0.0.0.0:7005->7005/tcp, 6379/tcp, 0.0.0.0:17005->17005/tcp   redis-7005
ba7326b91058        redis               "…"   2 minutes ago       Up 2 minutes        0.0.0.0:7004->7004/tcp, 6379/tcp, 0.0.0.0:17004->17004/tcp   redis-7004
6431a01bc762        redis               "…"   2 minutes ago       Up 2 minutes        0.0.0.0:7003->7003/tcp, 6379/tcp, 0.0.0.0:17003->17003/tcp   redis-7003
cfecb00ba432        redis               "…"   2 minutes ago       Up 2 minutes        0.0.0.0:7002->7002/tcp, 6379/tcp, 0.0.0.0:17002->17002/tcp   redis-7002
f0018b73a7f9        redis               "…"   2 minutes ago       Up 2 minutes        0.0.0.0:7001->7001/tcp, 6379/tcp, 0.0.0.0:17001->17001/tcp   redis-7001

随便进入一个容器

docker exec -it redis-7001 /bin/bash

执行集群命令,执行命令之后要输入yes(将不同机器上的容器规划成一个集群)

redis-cli  --cluster create :7001 :7002 :7003 :7004 :7005 :7006 --cluster-replicas 1 -a 123456 # --cluster-replicas 1 一主一从

执行结果(主机123从机564)

root@f0018b73a7f9:/data# redis-cli  --cluster create :7001 :7002 :7003 :7004 :7005 :7006 --cluster-replicas 1 -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica :7005 to :7001
Adding replica :7006 to :7002
Adding replica :7004 to :7003
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: 5ba40559ac1a136158e4eb66475792bba651fff4 :7001slots:[0-5460] (5461 slots) master
M: 0164dc219485c3d598cb6e8ad72b2cd5cada19be :7002slots:[5461-10922] (5462 slots) master
M: 04d1fa0907a37e6d7d0f1fe321d1fac3b5c1036c :7003slots:[10923-16383] (5461 slots) master
S: d0bf21473ab351f53f56e9e3af63924aeda7b30a :7004replicates 04d1fa0907a37e6d7d0f1fe321d1fac3b5c1036c
S: 55f03a29141a8dad7bb8fb6e7dd7638806447718 :7005replicates 5ba40559ac1a136158e4eb66475792bba651fff4
S: 289c038d4e54c0c172ef133ad9828b52bda9c021 :7006replicates 0164dc219485c3d598cb6e8ad72b2cd5cada19be
Can I set the above configuration? (type 'yes' to accept): yes

随便进入一个容器

docker exec -it redis-7001 /bin/bash
redis-cli -c -h  -p 7001
auth 123456
ping
cluster nodes
set name xiaoming

客户端连接

主机主要写、从机主要读,主机单向向从机进行复制,读写分离,解决读的问题;单台redis最大使用内存不应超过20G;非docker搭建的集群命令:info replication # 查看当前库的信息、slaveof 127.0.0.1 6379 # 认老大

手动实验上面的3主3从发现

  • 向集群写入内容,集群会自动分配/切换主机进行写,写完之后,查看从机key*发现还是空的,--cluster-replicas没卵用

  • 客户端连接的话,每个机器都能看到全量的数据

主从复制没有得到验证,宣布太监了

搭建1主2从3哨兵(太监)

仅仅几个redis实例,用docker启动确实意义不大,用docker就应该搞服务编排与升级降级…先不管了

拓扑结构

先开端口

6379:master节点
6380:slave节点
6381:slave节点
26379:sentinel节点
26380:sentinel节点
26381:sentinel节点
16379:总线端口
16380:总线端口
16381:总线端口

新建文件夹

mkdir /usr/local/redis123
cd /usr/local/redis123
mkdir /usr/local/redis123/master
mkdir /usr/local/redis123/slave_6380
mkdir /usr/local/redis123/slave_6381
mkdir /usr/local/redis123/sentinel_26379
mkdir /usr/local/redis123/sentinel_26380
mkdir /usr/local/redis123/sentinel_26381

拉取镜像

docker pull redis

下载配置文件

wget http://download.redis.io/redis-stable/

cp一份命名为修改如下内容

cp
port 6379
dir "/data" # 默认文件路径,dbfilename及logfile都会在这个路径下创建
dbfilename ""
logfile ""
# 注释这一行,表示Redis可以接受任意ip的连接
# bind 127.0.0.1
# 关闭保护模式
protected-mode no
# 后台运行会报错,只能设为no
daemonize no
# 设定密码(可选,如果这里开启了密码要求,slave的配置里就要加这个密码. 只是练习配置,就不使用密码认证了)
# requirepass masterpassword 

启动主节点

docker run -d -p 6379:6379 --name redis_master -v /usr/local/redis123/:/redis/ -v /usr/local/redis123/master/:/data redis:latest redis-server /redis/
# 解释
-p 6379:6379  # 端口映射
--name redis_master  # 容器名称
-v /usr/local/redis123/:/redis/  # 配置文件挂载
-v /usr/local/redis123/master/:/data  # 数据卷挂载
redis:latest  # 镜像
redis-server /redis/   # docker启动后执行的命令,配置文件在redis下

开始搞第一个从节点

cp  redis_slave_6380.conf
# 修改如下配置
port 6379 # 由于是docker部署,所以内部端口都是6379
daemonize no # 不设置为守护模式(后台运行)
dir "/data" # 工作目录
dbfilename "" # 持久化文件名称
logfile "" # 日志文件名称
# 注释这一行,表示Redis可以接受任意ip的连接
# bind 127.0.0.1
# 关闭保护模式
protected-mode no
#
daemonize no
# 设定密码(可选,如果这里开启了密码要求,slave的配置里就要加这个密码)
requirepass masterpassword
# 设定主库的密码,用于认证,如果主库开启了requirepass选项这里就必须填相应的密码
masterauth <master-password>
# 设定master的IP和端口号,redis配置文件中的默认端口号是6379
# 低版本的redis这里会是slaveof,意思是一样的,因为slave是比较敏感的词汇,所以在redis后面的版本中不在使用slave的概念,取而代之的是replica
# 将做为主,其余两台机器做从。ip和端口号按照机器和配置做相应修改。
replicaof  6379

启动第一个从节点

docker run -d -p 6380:6379 --name redis_slave_1 -v /usr/local/redis123/redis_slave_6380.conf:/redis/ -v /usr/local/redis123/slave_6380/:/data redis:latest redis-server /redis/
# 解释
-p 6380:6379  # 端口映射
--name redis_slave_1  # 容器名称
-v /usr/local/redis123/redis_slave_6380.conf:/redis/  # 配置文件挂载
-v /usr/local/redis123/slave_6380/:/data  # 数据卷挂载
redis:latest  # 镜像
redis-server /redis/   # docker启动后执行的命令,配置文件在redis下

检查第一个从节点

[root@10-9-48-229 ~]# docker exec -it redis_slave_1 /bin/bash
root@2af58390bde6:/data# redis-cli -p 6379
> ping
PONG
> info replication
# Replication
role:slave
master_host:
master_port:6379
master_link_status:up
master_last_io_seconds_ago:8
master_sync_in_progress:0
slave_repl_offset:56
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:4d3b177ec1321267b2789594441b7aca35479bca
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:56
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:56

配置第二个从节点

cp  redis_slave_6381.conf
# 修改如下配置
port 6379 # 由于是docker部署,所以内部端口都是6379
daemonize no # 不设置为守护模式(后台运行)
dir "/data" # 工作目录
dbfilename "" # 持久化文件名称
logfile "" # 日志文件名称
# 注释这一行,表示Redis可以接受任意ip的连接
# bind 127.0.0.1
# 关闭保护模式
protected-mode no
#
daemonize no
# 设定密码(可选,如果这里开启了密码要求,slave的配置里就要加这个密码)
requirepass masterpassword
# 设定主库的密码,用于认证,如果主库开启了requirepass选项这里就必须填相应的密码
masterauth <master-password>
# 设定master的IP和端口号,redis配置文件中的默认端口号是6379
# 低版本的redis这里会是slaveof,意思是一样的,因为slave是比较敏感的词汇,所以在redis后面的版本中不在使用slave的概念,取而代之的是replica
# 将做为主,其余两台机器做从。ip和端口号按照机器和配置做相应修改。
replicaof  6379

启动第二个从节点

docker run -d -p 6381:6379 --name redis_slave_2 -v /usr/local/redis123/redis_slave_6381.conf:/redis/ -v /usr/local/redis123/slave_6381/:/data redis:latest redis-server /redis/

查看第二个从节点

[root@10-9-48-229 ~]# docker exec -it redis_slave_2 /bin/bash
root@e4318bd3e641:/data# redis-cli -p 6379
> ping
PONG
root@5fc83f0afe53:/data# redis-cli -p 6379
> ping
PONG
> info replication
# Replication
role:slave
master_host:
master_port:6379
master_link_status:up
master_last_io_seconds_ago:9
master_sync_in_progress:0
slave_repl_offset:868
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:8dd4c5bcdec908f1a888e4e2f982b090db376180
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:868
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:855
repl_backlog_histlen:14

查看主节点(胎货)

[root@10-9-48-229 redis123]# docker exec -it redis_master /bin/bash
root@1e14a516bce9:/data# redis-cli -p 6379
> ping
PONG
> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=,port=6379,state=online,offset=1008,lag=0
slave1:ip=,port=6379,state=online,offset=1008,lag=0
master_replid:8dd4c5bcdec908f1a888e4e2f982b090db376180
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1008
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:855
repl_backlog_histlen:154

Redis主从复制

# 主机
> set name xiaoming
OK
> get name
"xiaoming"
# 从机1
> get name
"xiaoming"
> set k2 v2
(error) READONLY You can't write against a read only replica.
# 从机2
> get name
"xiaoming"

客户端查看,主从复制也没有问题

配置哨兵sentinel节点(下面这端内容未成功)

wget http://download.redis.io/redis-stable/sentinel.conf
cp sentinel.conf redis_sentinel_26379.conf
cp sentinel.conf redis_sentinel_26380.conf
cp sentinel.conf redis_sentinel_26381.conf

修改redis_sentinel_26379.conf

port 26379  # 由于要进行端口映射,内部端口为6379
daemonize no
logfile "2"
dir "/data"
#bind  127.0.0.1
protected-mode no
sentinel monitor mymaster  6379 1 #2 主节点的ip及端口
#30秒ping不通主节点的信息,主观认为master宕机(30秒以后扶正)
sentinel down-after-milliseconds mymaster 30000
#故障转移后重新主从复制,1表示串行,>1并行
sentinel parallel-syncs mymaster 2
#故障转移开始,三分钟内没有完成,则认为转移失败
sentinel failover-timeout mymaster 180000

修改redis_sentinel_26380.conf

port 26379  # 由于要进行端口映射,内部端口为6379
daemonize no
logfile "2"
dir "/data"
#bind  127.0.0.1
# 172.17.0.2
protected-mode no
sentinel monitor mymaster  6379 1 #2 主节点的ip及端口docker inspect redis_master

修改redis_sentinel_26381.conf

port 26379  # 由于要进行端口映射,内部端口为6379
daemonize no
logfile "2"
dir "/data"
#bind  127.0.0.1
protected-mode no
sentinel monitor mymaster  6379 1 #2 主节点的ip及端口

启动哨兵

# 第一个哨兵
docker run -d -p 26379:26379 --name redis_sentinel_1 -v /usr/local/redis123/redis_sentinel_26379.conf:/redis/sentinel.conf -v /usr/local/redis123/sentinel_26379/:/data redis:latest redis-sentinel /redis/sentinel.conf
# 第二个哨兵
docker run -d -p 26380:26379 --name redis_sentinel_2 -v /usr/local/redis123/redis_sentinel_26380.conf:/redis/sentinel.conf -v /usr/local/redis123/sentinel_26380/:/data redis:latest redis-sentinel /redis/sentinel.conf
# 第三个哨兵
docker run -d -p 26381:26379 --name redis_sentinel_3 -v /usr/local/redis123/redis_sentinel_26381.conf:/redis/sentinel.conf -v /usr/local/redis123/sentinel_26381/:/data redis:latest redis-sentinel /redis/sentinel.conf

启动第一个哨兵后,直接就把master斗成了slave了!

反复测试拷贝到记事本

docker rm -f $(docker ps -aq)docker run -d -p 6379:6379 --name redis_master -v /usr/local/redis123/:/redis/ -v /usr/local/redis123/master/:/data redis:latest redis-server /redis/
docker run -d -p 6380:6379 --name redis_slave_1 -v /usr/local/redis123/redis_slave_6380.conf:/redis/ -v /usr/local/redis123/slave_6380/:/data redis:latest redis-server /redis/
docker run -d -p 6381:6379 --name redis_slave_2 -v /usr/local/redis123/redis_slave_6381.conf:/redis/ -v /usr/local/redis123/slave_6381/:/data redis:latest redis-server /redis/docker run -d -p 26379:26379 --name redis_sentinel_1 -v /usr/local/redis123/redis_sentinel_26379.conf:/redis/sentinel.conf -v /usr/local/redis123/sentinel_26379/:/data redis:latest redis-sentinel /redis/sentinel.confdocker exec -it redis_master /bin/bash
redis-cli -p 6379
info replication

启动第一个哨兵master就被干掉了

[root@10-9-48-229 ~]# docker exec -it redis_sentinel_1 /bin/bash
root@2fcc6ae3ab48:/data# tail 2
1:X 23 Oct 2020 03:02:39.271 * +convert-to-slave slave :6379  6379 @ mymaster  6379
1:X 23 Oct 2020 03:03:39.285 # +sdown master mymaster  6379
1:X 23 Oct 2020 03:03:39.285 # +odown master mymaster  6379 #quorum 1/1
1:X 23 Oct 2020 03:03:39.285 # +new-epoch 1
1:X 23 Oct 2020 03:03:39.285 # +try-failover master mymaster  6379
1:X 23 Oct 2020 03:03:39.287 # +vote-for-leader df0641c0a7e82d8cf86377272d42fd6c002845ff 1
1:X 23 Oct 2020 03:03:39.287 # +elected-leader master mymaster  6379
1:X 23 Oct 2020 03:03:39.287 # +failover-state-select-slave master mymaster  6379
1:X 23 Oct 2020 03:03:39.346 # -failover-abort-no-good-slave master mymaster  6379
1:X 23 Oct 2020 03:03:39.398 # Next failover delay: I will not start a failover before Fri Oct 23 03:09:39 2020

宣布以上这种方式搭建哨兵太监了(哨兵启动是成功了,但是可能配置问题直接把主redis干掉了)

搭建1主2从3哨兵(compose)

命令

docker pull redis
mkdir /usr/local/redis666
mkdir /usr/local/redis666/redis
cd /usr/local/redis666/redis
vi docker-compose.yml

内容如下

version: ''
services:master:image: rediscontainer_name: redis-masterrestart: alwayscommand: redis-server --port 6379 --requirepass 123456  --appendonly yesports:- 6379:6379volumes:- ./data:/dataslave1:image: rediscontainer_name: redis-slave-1restart: alwayscommand: redis-server --slaveof  6379 --port 6380  --requirepass 123456 --masterauth 123456  --appendonly yesports:- 6380:6380volumes:- ./data:/dataslave2:image: rediscontainer_name: redis-slave-2restart: alwayscommand: redis-server --slaveof  6379 --port 6381  --requirepass 123456 --masterauth 123456  --appendonly yesports:- 6381:6381volumes:- ./data:/data

启动

docker-compose up -d
docker ps
docker logs -f redis-slave-2
docker logs -f redis-master
docker exec -it redis-master bash
redis-cli
ping
auth 123456
info replicationdocker exec -it redis-slave-1 bash
redis-cli -p 6380
ping
auth 123456
info replicationdocker exec -it redis-slave-2 bash
redis-cli -p 6381
ping
auth 123456
info replicationdocker-compose down
docker-compose up -ddocker stop $(docker ps -a -q)
docker rm $(docker ps -a -q)
exit

主从复制得到验证,客户端连接也没有问题,数据持久化成功!

哨兵模式

一主两从三哨兵:哨兵之间相互监控,哨兵整体监控主机与从机,这种模式感觉够用了,自己做网站小创业也实用;

要做的事情:配置哨兵规则、启动哨兵、主机宕机后哨兵选举从机为新主机、机器宕机配置发送邮件。

部署哨兵

mkdir /usr/local/redis666/sentinel
cd /usr/local/redis666/sentinel
vi docker-compose.yml

内容如下

version: ''
services:sentinel1:image: rediscontainer_name: redis-sentinel-1command: redis-sentinel /usr/local/etc/redis/sentinel.confrestart: alwaysports:- 26379:26379volumes:- ./sentinel1.conf:/usr/local/etc/redis/sentinel.confsentinel2:image: rediscontainer_name: redis-sentinel-2command: redis-sentinel /usr/local/etc/redis/sentinel.confrestart: alwaysports:- 26380:26379volumes:- ./sentinel2.conf:/usr/local/etc/redis/sentinel.confsentinel3:image: rediscontainer_name: redis-sentinel-3command: redis-sentinel /usr/local/etc/redis/sentinel.confrestart: alwaysports:- 26381:26379volumes:- ./sentinel3.conf:/usr/local/etc/redis/sentinel.conf

编写sentinel.conf

vi sentinel.conf

内容如下

port 26379
dir /tmp
# 自定义集群名,其中  为 redis-master 的 ip,6379 为 redis-master 的端口,2 为最小投票数(因为有 3 台 Sentinel 所以可以设置成 2)
sentinel monitor mymaster  6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel auth-pass mymaster 123456
sentinel failover-timeout mymaster 180000
sentinel deny-scripts-reconfig yes

复制3份

cp sentinel.conf sentinel1.conf
cp sentinel.conf sentinel2.conf
cp sentinel.conf sentinel3.conf

启动

docker-compose up -d
docker exec -it redis-sentinel-1 bash
redis-cli -p 26379
sentinel master mymaster
sentinel slaves mymaster

验证哨兵模式,在上面的基础上,停掉主redis

docker logs -f redis-sentinel-1docker stop redis-masterdocker exec -it redis-slave-1 bash
redis-cli -p 6380
ping
auth 123456
info replicationdocker exec -it redis-slave-2 bash
redis-cli -p 6381
ping
auth 123456
info replication

一小会之后,发现6380被扶正了!

新皇操作权限已经改变(虽然名字还没变,但是实权变了)

老皇帝老儿回来乖乖当勾践

Redis缓存穿透和雪崩

缓存穿透

缓存里边查不到(缓存没有被命中),数据库里也查不到,因此疯狂的查数据库,即为缓存穿透。

缓存穿透解决方案一:布隆过滤器

过滤掉一些请求

缓存穿透解决方案二:缓存空对象

数据库中没有的时候,在缓存中存一个空对象(一致性会有问题)

缓存击穿

一个热点key,一直抗着巨大并发,当该key失效的一瞬间(重新加载也许只需要),所有的请求全部砸在数据库上,导致宕机。

缓存击穿解决方案一:设置热点key不过期

缓存击穿解决方案二:分布式锁,只允许一个线程访问数据库

缓存雪崩

缓存集群全部宕机,所有请求全部砸在数据库上,数据库随即崩溃

缓存雪崩解决方案一:redis高可用

缓存雪崩解决方案二:限流降级

缓存雪崩解决方案一:数据预热

gin redis 链接不上_Redis通俗易懂丶 - 夜雨秋池相关推荐

  1. gin redis 链接不上_Redis 高并发问题,及解决方案!

    (一)redis技术的使用: redis真的是一个很好的技术,它可以很好的在一定程度上解决网站一瞬间的并发量,例如商品抢购秒杀等活动... redis之所以能解决高并发的原因是它可以直接访问内存,而以 ...

  2. gin redis 链接不上_自然的风味,GIN 在杯中

    在墨尔本 | 创造专属奢华体验 | | | GRAND HYATT MELBOURNE  电影<卡萨布兰卡>剧照 Of all the gin joints, in all the tow ...

  3. gin redis 链接不上_内存优化,Redis是如何实现的!

    点击上方"小罗技术笔记",关注公众号 第一时间送达实用干货 各位朋友新年开工好,今年由于特殊情况好多小伙伴今天在家开启远程办公模式(一直很向往),不过在这真想吐槽一下现有的远程办公 ...

  4. gin redis 链接不上_php + redis 高并发商品秒杀 完整业务模拟流程 实现方案

    关于商品秒杀 之前百度了很多关于商品秒杀的业务怎么做,网上的答案真的是五花八门,归纳一下就两种方式 队列或计数器 网上大部分都没有写具体的代码业务 我这里模拟一个业务小场景进行实践 商品:1 每日限量 ...

  5. redis链接不上,报保护模式

    错误信息: DENIED Redis is running in protected mode because protected mode is enabled, no bind address w ...

  6. redis映射的概念_Redis存储总是心里没底?你大概漏了这些数据结构原理

    原标题:Redis存储总是心里没底?你大概漏了这些数据结构原理 上一篇文章<Redis存储总用String?你大概错过了更优的使用方法>我们了解了Redis的数据类型特点与适用场景,本期内 ...

  7. Redis在linux上安装教程,超级详细

    Redis安装说明 大多数企业都是基于Linux服务器来部署项目,而且Redis官方也没有提供Windows版本的安装包.因此课程中我们会基于Linux系统来安装Redis. 此处选择的Linux版本 ...

  8. Redis在Windows上的使用

    Redis在Windows上的使用 安装 Redis可视化工具 Redis的主从复制 遇到的问题 安装 下载地址:https://github.com/MSOpenTech/redis/release ...

  9. redis在Linux上的安装

    1.redis在Linux上的安装 1)安装redis编译的c环境,yum install gcc-c++ 2)将redis-2.6.16.tar.gz上传到Linux系统中 3)解压到/usr/lo ...

最新文章

  1. 【力扣网练习题】回文数
  2. python编程100例头条-我用Python编程语言做了一些神奇好玩的事情
  3. 深度学习(训练/开发/测试集)的划分技巧
  4. 关于jsp页面传值乱码问题
  5. centos6配置日志外发_CentOS6下记录后台操作日志的两种方式
  6. Python中的支持向量机SVM的使用(有实例有源码)
  7. 那些藏在你键盘里的emoji,背后到底有着怎样的故事?
  8. HTML中放置CSS的三种方式和CSS选择器
  9. zincrby redis python_【Redis数据结构 序】使用redis-py操作Redis数据库
  10. 二年级的女儿用计算机算算术,小学二年级算术练习题(三篇)
  11. Centos 7 安装 TEMPO2
  12. 解决Windows Update错误“80072EFD”
  13. codefoces 417D Cunning Gena 状压DP
  14. springboot整合RabbitMQ启动报错:An unexpected connection driver error occured,Socket Closed
  15. Redis 进阶笔记
  16. SLCP验厂辅导,企业在认证之后便可以将经验证过后的数据信息分享给其它各托管平台
  17. ubuntu 回到根目录,回到上一级 常用指令
  18. nonlocal和global的区别
  19. ff14不同服务器有什么影响,FF14转服后的各种弊端分析 切勿盲目跟风
  20. MyEclipse 注册码分享

热门文章

  1. 通过RS485串口对力川A6伺服电机的调试
  2. 家用电器行业为什么需要订货管理系统
  3. 微信小程序开发--常用方法
  4. day95-容器编排-kubernetes介绍与安装部署
  5. powershell 简单实现核算单位往来(对账)
  6. WordPress虚拟资源商城主题日主题RiPro6.7 开源版 星空资源网首发
  7. 高并发解决方案之熔断处理
  8. MTK Android 13平台开关机动画铃声客制化
  9. c#读取dwg零件表_C#实现的读取CAD表格文字
  10. 如何在html上显示时间设置,js实现在网页上简单显示时间的方法