Java分布式篇4——Redis

  • Post author:
  • Post category:java




Java分布式篇4——Redis



1、互联网架构的演变历程



1.1、第一阶段

数据访问量不大,简单的架构即可搞定!

在这里插入图片描述



1.2、第二阶段

  • 数据访问量大,使用缓存技术来缓解数据库的压力
  • 不同的业务访问不同的数据库

在这里插入图片描述



1.3、第三阶段

  • 主从读写分离。 之前的缓存确实能够缓解数据库的压力,但是写和读都集中在一个数据库上,压力又来了,一个数据库负责写,一个数据库负责读,分工合作,让master(主数据库)来响应事务性(增删改)操作,让slave(从数据库)来响应非事务性 (查询)操作,然后再采用主从复制来把master上的事务性操作同步到slave数据库中

在这里插入图片描述



1.4、第四阶段

  • mysql集群

在这里插入图片描述



2、Redis介绍

Redis 是一种运行速度很快,并发性能很强,并且运行在内存上的NoSql(not only sql)数据库


redis的瓶颈是内存和带宽,不是CPU



2.1、适用场景

  • 缓存,毫无疑问这是Redis当今最为人熟知的使用场景。在提升服务器性能方面非常有效;一 些频繁被访问的数据,经常被访问的数据如果放在关系型数据库,每次查询的开销都会很 大,而放在redis中,因为redis 是放在内存中的可以很高效的访问
  • 排行榜,在使用传统的关系型数据库(mysql oracle 等)来做这个事儿,非常的麻烦,而利 用Redis的SortSet(有序集合)数据结构能够简单的搞定
  • 计算器/限速器,利用Redis中原子性的自增操作,我们可以统计类似用户点赞数、用户访问 数等,这类操作如果用MySQL,频繁的读写会带来相当大的压力;限速器比较典型的使用场 景是限制某个用户访问某个API的频率,常用的有抢购时,防止用户疯狂点击带来不必要的压力
  • 好友关系,利用集合的一些命令,比如求交集、并集、差集等。可以方便搞定一些共同好 友、共同爱好之类的功能
  • 简单消息队列,除了Redis自身的发布/订阅模式,我们也可以利用List来实现一个队列机制, 比如:到货通知、邮件发送之类的需求,不需要高可靠,但是会带来非常大的DB压力,完全 可以用List来完成异步解耦
  • Session共享,以jsp为例,默认Session是保存在服务器的文件中,如果是集群服务,同一个 用户过来可能落在不同机器上,这就会导致用户频繁登陆;采用Redis保存Session后,无论 用户落在那台机器上都能够获取到对应的Session信息



2.2、 Redis/Memcache/MongoDB对比

  • Redis和Memcache都是内存数据库。不过memcache还可用于缓存其他东西,例如图片、视频等
  • memcache 数据结构单一kv,redis 更丰富一些,还提供 list,set, hash 等数据结构的存储,有 效的减少网络IO的次数
  • 虚拟内存–Redis当物理内存用完时,可以将一些很久没用到的value交换到磁盘
  • 存储数据安全–memcache挂掉后,数据没了(没有持久化机制);redis可以定期保存到磁盘(持久化)
  • mongodb本质上还是硬盘数据库,在复杂查询时仍然会有大量的资源消耗,而且在处理复杂逻辑 时仍然要不可避免地进行多次查询,这时就需要redis或Memcache这样的内存数据库来作为中间层进行缓存和加速



3、CAP原理

  • C(Consistency):强一致性

    • “all nodes see the same data at the same time”,即更新操作成功并返回客户端后,所 有节点在同一时间的数据完全一致,这就是分布式的一致性。一致性的问题在并发系统 中不可避免,对于客户端来说,一致性指的是并发访问时更新过的数据如何获取的问 题。从服务端来看,则是更新如何复制分布到整个系统,以保证数据最终一致
  • A(Availability):高可用性

    • 可用性指“Reads and writes always succeed”,即服务一直可用,而且要是正常的响应 时间。好的可用性主要是指系统能够很好的为用户服务,不出现用户操作失败或者访问 超时等用户体验不好的情况
  • P(Partition tolerance):分区容错性

    • 即分布式系统在遇到某节点或网络分区故障时,仍然能够对外提供满足一致性或可用性 的服务。 分区容错性要求能够使应用虽然是一个分布式系统,而看上去却好像是在一个可以运转 正常的整体。比如现在的分布式系统中有某一个或者几个机器宕掉了,其他剩下的机器 还能够正常运转满足系统需求,对于用户而言并没有什么体验上的影响



3.1、CAP总结

根据 CAP 原理将 NoSQL 数据库分成了满足 CA 原则、满足 CP 原则和满足 AP 原则三大类

  • CA – 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大
  • CP – 满足一致性,分区容忍性的系统,通常性能不是特别高
  • AP – 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些



4、下载安装(linux)


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


redis5.0.4 百度云:https://pan.baidu.com/s/1BfWTbuSQuBAiRK7CWS73Ow

提取码:2b45



4.1、解压

tar -zxvf redis-5.0.4.tar.gz



4.2、安装gcc

yum -y install gcc



4.3、进入redis目录,编译

make
make install



4.4、redis默认不会使用后台运行,如果你需要,修改配置文件daemonize=yes

vim redis.conf
daemonize yes



4.5、默认安装到的位置为

/usr/local/bin



4.6、拷贝配置文件,并指定配置文件启动redis

[root@VM-8-13-centos bin]# cp /usr/local/redis-5.0.4/redis.conf redis.conf
[root@VM-8-13-centos bin]# ls
busybox-x86_64  redis-benchmark  redis-check-aof  redis-check-rdb  redis-cli  redis.conf  redis-sentinel  redis-server
[root@VM-8-13-centos bin]# redis-server redis.conf 
14566:C 31 Jul 2021 21:54:44.185 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
14566:C 31 Jul 2021 21:54:44.185 # Redis version=5.0.4, bits=64, commit=00000000, modified=0, pid=14566, just started
14566:C 31 Jul 2021 21:54:44.185 # Configuration loaded



4.7、测试

[root@VM-8-13-centos bin]# redis-cli -p 6379
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> exit



4.8、关闭

单实例

redis-cli shutdown

多实例

redis-cli -p 6379 shutdown



4.9、常用命令

检测6379端口是否在监听

netstat -lntp | grep 6379

检测后台进程是否存在

ps -ef|grep redis



5、性能测试

[root@VM-8-13-centos bin]# redis-benchmark 
====== PING_INLINE ======
  # 1.8秒处理了10万个请求
  100000 requests completed in 1.37 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

99.79% <= 1 milliseconds
99.93% <= 2 milliseconds
100.00% <= 2 milliseconds
# 每秒处理的请求
72886.30 requests per second

====== PING_BULK ======
  100000 requests completed in 1.35 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

99.66% <= 1 milliseconds
99.83% <= 2 milliseconds
99.85% <= 3 milliseconds
99.94% <= 4 milliseconds
100.00% <= 4 milliseconds
74349.44 requests per second



6、基础命令



6.1、测试是否连通

127.0.0.1:6379> ping
PONG



6.2、存值取值

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2
OK
127.0.0.1:6379> get k1
"v1"



6.3、数据库大小

127.0.0.1:6379> dbsize
(integer) 5



6.4、数据库所有值

127.0.0.1:6379> keys *
1) "mylist"
2) "key:__rand_int__"
3) "k2"
4) "k1"
5) "counter:__rand_int__"



6.5、清空数据库

清空单一数据库

127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> dbsize
(integer) 0

清空所有数据库

127.0.0.1:6379> flushall
OK



6.6、存在值

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> exists k1
(integer) 1
127.0.0.1:6379> exists k2
(integer) 0



6.7、过期时间

127.0.0.1:6379> expire k1 30
(integer) 1
127.0.0.1:6379> ttl k1
(integer) 19

ttl查看键还有多久过期



6.8、判断数据类型

127.0.0.1:6379> set k1 123
OK
127.0.0.1:6379> get k1
"123"
127.0.0.1:6379> type k1
string



6.9、移除键

127.0.0.1:6379> del k1
(integer) 1
127.0.0.1:6379> get k1
(nil)



6.10、移动键到其他数据库

127.0.0.1:6379> set k1 zhangsan
OK
127.0.0.1:6379> move k1 1
(integer) 1
127.0.0.1:6379> get k1
(nil)
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> get k1
"zhangsan"



7、五大基本数据类型



7.1、String



7.1.1、存取删

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> del k1
(integer) 1



7.1.2、追加

若不存在,则会新建

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> append k1 zhangsan
(integer) 10
127.0.0.1:6379> get k1
"v1zhangsan"



7.1.3、字符串长度

127.0.0.1:6379> strlen k1
(integer) 10



7.1.4、自增自减

127.0.0.1:6379> set k1 1
OK
127.0.0.1:6379> incr k1
(integer) 2
127.0.0.1:6379> get k1
"2"
127.0.0.1:6379> decr k1
(integer) 1
127.0.0.1:6379> get k1
"1"
127.0.0.1:6379> incrby k1 10
(integer) 11
127.0.0.1:6379> get k1
"11"
127.0.0.1:6379> decrby k1 10
(integer) 1
127.0.0.1:6379> get k1
"1"



7.1.5、截取字符串

127.0.0.1:6379> set k1 abhbfhbysydvsd
OK
127.0.0.1:6379> getrange k1 0 -1
"abhbfhbysydvsd"
127.0.0.1:6379> getrange k1 0 3
"abhb"



7.1.6、替换值

127.0.0.1:6379> setrange k1 0 HHHH
(integer) 14
127.0.0.1:6379> get k1
"HHHHfhbysydvsd"



7.1.7、添加数据并设置生命周期

setex(

set

with

ex

pir)

127.0.0.1:6379> setex k1 30 abc
OK
127.0.0.1:6379> ttl k1
(integer) 24



7.1.8、如果不存在才添加

setnx(

set

if

n

ot e

x

ist)

127.0.0.1:6379> setnx k2 v2
(integer) 0
127.0.0.1:6379> get k2
"v2"



7.1.9、一次添加多个值

mset/mget/msetnx

127.0.0.1:6379> mset k1 v1 k2 v2
OK
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
127.0.0.1:6379> mget k1 k2
1) "v1"
2) "v2"



7.1.10、先取后存

127.0.0.1:6379> getset k1 vv1
"v1"



7.2、List

允许有重复元素



7.2.1、lpush存(—>)

127.0.0.1:6379> lpush list1 1 2 3 4 5
(integer) 5



7.2.2、查(—>)

127.0.0.1:6379> lrange list1 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"



7.2.3、rpush存

127.0.0.1:6379> rpush list1 0
(integer) 6
127.0.0.1:6379> lrange list1 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
6) "0"



7.2.4、lpop取(<—)

127.0.0.1:6379> lpop list1
"5"
127.0.0.1:6379> lrange list1 0 -1
1) "4"
2) "3"
3) "2"
4) "1"
5) "0"



7.2.4、rpop取(—>)

127.0.0.1:6379> rpop list1
"0"
127.0.0.1:6379> lrange list1 0 -1
1) "4"
2) "3"
3) "2"
4) "1"



7.2.5、按下标取(<—)

127.0.0.1:6379> lrange list1 0 -1
1) "4"
2) "3"
3) "2"
4) "1"
127.0.0.1:6379> lindex list1 0
"4"



7.2.6、集合长度

127.0.0.1:6379> lrange list1 0 -1
1) "4"
2) "3"
3) "2"
4) "1"
127.0.0.1:6379> llen list1
(integer) 4



7.2.7、删除指定个数指定的值

127.0.0.1:6379> lpush list2 1 1 2 2 2 3 3 3 4 4 4
(integer) 11
127.0.0.1:6379> lrange list2 0 -1
 1) "4"
 2) "4"
 3) "4"
 4) "3"
 5) "3"
 6) "3"
 7) "2"
 8) "2"
 9) "2"
10) "1"
11) "1"
127.0.0.1:6379> lrem list2 2 2
(integer) 2
127.0.0.1:6379> lrange list2 0 -1
1) "4"
2) "4"
3) "4"
4) "3"
5) "3"
6) "3"
7) "2"
8) "1"
9) "1"



7.2.8、修建集合

127.0.0.1:6379> lrange list2 0 -1
1) "4"
2) "4"
3) "4"
4) "3"
5) "3"
6) "3"
7) "2"
8) "1"
9) "1"
127.0.0.1:6379> ltrim list2 1 8
OK
127.0.0.1:6379> lrange list2 0 -1
1) "4"
2) "4"
3) "3"
4) "3"
5) "3"
6) "2"
7) "1"
8) "1"



7.2.9、弹出一个元素加入另外一个list集合

127.0.0.1:6379> lpush list1  1 2 3 4 5
(integer) 5
127.0.0.1:6379> lpush list2 one two three four five
(integer) 5
127.0.0.1:6379> rpoplpush list1 list2
"1"
127.0.0.1:6379> lrange list1 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
127.0.0.1:6379> lrange list2 0 -1
1) "1"
2) "five"
3) "four"
4) "three"
5) "two"
6) "one"



7.2.10、设置指定索引的值

127.0.0.1:6379> lrange list1 0 -1
1) "555"
2) "4"
3) "3"
4) "2"
127.0.0.1:6379> lset list1 1 444
OK
127.0.0.1:6379> lrange list1 0 -1
1) "555"
2) "444"
3) "3"
4) "2"



7.2.11、在指定值前插入数值

127.0.0.1:6379> lrange list1 0 -1
1) "555"
2) "444"
3) "3"
4) "2"
127.0.0.1:6379> linsert list1 before 555 999
(integer) 5
127.0.0.1:6379> lrange list1 0 -1
1) "999"
2) "555"
3) "444"
4) "3"
5) "2"
127.0.0.1:6379> linsert list1 after 555 999
(integer) 6
127.0.0.1:6379> lrange list1 0 -1
1) "999"
2) "555"
3) "999"
4) "444"
5) "3"
6) "2"



7.3、Set

无序不重复(此无序不是指的set无序,而是指没有插入顺序)



7.3.1、存

127.0.0.1:6379> sadd set1 5 8 6 3 1 9
(integer) 6



7.3.2、取

127.0.0.1:6379> smembers set1
1) "1"
2) "3"
3) "5"
4) "6"
5) "8"
6) "9"



7.3.3、判断值是否存在

127.0.0.1:6379> smembers set1
1) "1"
2) "3"
3) "5"
4) "6"
5) "8"
6) "9"
127.0.0.1:6379> sismember set1 9
(integer) 1
127.0.0.1:6379> sismember set1 7
(integer) 0



7.3.4、元素个数

127.0.0.1:6379> smembers set1
1) "1"
2) "3"
3) "5"
4) "6"
5) "8"
6) "9"
127.0.0.1:6379> sismember set1 9
(integer) 1
127.0.0.1:6379> scard set1
(integer) 6



7.3.5、移除元素

127.0.0.1:6379> srem set 6
(integer) 0
127.0.0.1:6379> smembers set1
1) "1"
2) "3"
3) "5"
4) "6"
5) "8"
6) "9"



7.3.6、随机选值

127.0.0.1:6379> smembers set1
1) "1"
2) "3"
3) "5"
4) "6"
5) "8"
6) "9"
127.0.0.1:6379> srandmember set1
"5"
127.0.0.1:6379> srandmember set1 3
1) "6"
2) "3"
3) "9"



7.3.7、随机移除值

127.0.0.1:6379> spop set1 
"3"
127.0.0.1:6379> spop set1 3
1) "1"
2) "9"
3) "6"
127.0.0.1:6379> smembers set1
1) "5"
2) "8"



7.3.8、将指定的值从源set集合移动到目标set集合

127.0.0.1:6379> smembers set1
1) "5"
2) "8"
127.0.0.1:6379> sadd set2 one two
(integer) 2
127.0.0.1:6379> smove set1 set2 5
(integer) 1
127.0.0.1:6379> smembers set1
1) "8"
127.0.0.1:6379> smembers set2
1) "5"
2) "one"
3) "two"



7.3.9、set集合1中set集合2没有的元素

127.0.0.1:6379> sadd set1 1 5 6 9 7 3
(integer) 6
127.0.0.1:6379> sadd set2 3 5 8 4 10 2
(integer) 6
127.0.0.1:6379> sdiff set1 set2
1) "1"
2) "6"
3) "7"
4) "9"



7.3.10、set集合1中set集合2有的元素

127.0.0.1:6379> sadd set1 1 5 6 9 7 3
(integer) 6
127.0.0.1:6379> sadd set2 3 5 8 4 10 2
(integer) 6
127.0.0.1:6379> sinter set1 set2
1) "3"
2) "5"



7.3.11、set集合、set集合2所有的元素

127.0.0.1:6379> sadd set1 1 5 6 9 7 3
(integer) 6
127.0.0.1:6379> sadd set2 3 5 8 4 10 2
(integer) 6
127.0.0.1:6379> sunion set1 set2
 1) "1"
 2) "2"
 3) "3"
 4) "4"
 5) "5"
 6) "6"
 7) "7"
 8) "8"
 9) "9"
10) "10"



7.4、Hash



7.4.1、存取

127.0.0.1:6379> hset hash1 k1 v1
(integer) 1
127.0.0.1:6379> hget hash1 k1
"v1"
127.0.0.1:6379> hmset hash1 k2 v2 k3 v3
OK
127.0.0.1:6379> hmget hash1 k1 k2 k3
1) "v1"
2) "v2"
3) "v3"



7.4.2、获取所有键值对

127.0.0.1:6379> hgetall hash1
1) "k1"
2) "v1"
3) "k2"
4) "v2"
5) "k3"
6) "v3"



7.4.3、获取长度

127.0.0.1:6379> hlen hash1
(integer) 3



7.4.4、判断键是否存在

127.0.0.1:6379> hexists hash1 k1
(integer) 1
127.0.0.1:6379> hexists hash1 k4
(integer) 



7.4.5、获取所有键

127.0.0.1:6379> hkeys hash1
1) "k1"
2) "k2"
3) "k3"



7.4.6、获取所有值

127.0.0.1:6379> hvals hash1
1) "v1"
2) "v2"
3) "v3"



7.4.7、如果不存在设置值

127.0.0.1:6379> hsetnx hash1 k4 v4
(integer) 1



7.5、Zset

有序set



7.5.1、存取

127.0.0.1:6379> zadd zset1 1 zhangsan
(integer) 1
127.0.0.1:6379> zadd zset1 3 lisi 2 wangwu 4 zhaoliu
(integer) 3
127.0.0.1:6379> zrange zset1 0 -1
1) "zhangsan"
2) "wangwu"
3) "lisi"
4) "zhaoliu"
#逆序
127.0.0.1:6379> zrevrange zset1 0 -1
1) "zhaoliu"
2) "lisi"
3) "wangwu"
4) "zhangsan"



7.5.2、范围

127.0.0.1:6379> zrangebyscore zset1 1 3
1) "zhangsan"
2) "wangwu"
3) "lisi"
#取排序依据在1-3之间的值,跳过一个,取一个
127.0.0.1:6379> zrangebyscore zset1 1 3 limit 1 1
1) "wangwu"



7.5.3、删除

127.0.0.1:6379> zrange zset1 0 -1
1) "zhangsan"
2) "wangwu"
3) "lisi"
4) "zhaoliu"
127.0.0.1:6379> zrem zset1 wangwu
(integer) 1
127.0.0.1:6379> zrange zset1 0 -1
1) "zhangsan"
2) "lisi"
3) "zhaoliu"



7.5.4、集合长度

127.0.0.1:6379> zcard zset1
(integer) 3



7.5.5、获取指定分数间元素的个数

127.0.0.1:6379> zcount zset1 2 3
(integer) 1



7.5.6、获取指定元素的下标(从上到下)

127.0.0.1:6379> zrange zset1 0 -1
1) "zhangsan"
2) "lisi"
3) "zhaoliu"
127.0.0.1:6379> zrank zset1 lisi
(integer) 1
127.0.0.1:6379> zrank zset1 zhangsan
(integer) 0
#(从下到上)
127.0.0.1:6379> zrevrank zset1 zhangsan
(integer) 2



7.5.7、获取元素分数

127.0.0.1:6379> zscore zset1 lisi
"3"



7.5.8、范围查找

127.0.0.1:6379> zadd zset1 11 zhangsan 21 lisi 62 wangwu 30 zhaoliu 52 qianmqi
(integer) 5
127.0.0.1:6379> zrangebyscore zset1 20 40
1) "lisi"
2) "zhaoliu"
127.0.0.1:6379> zrevrangebyscore zset1 40 20
1) "zhaoliu"
2) "lisi"



8、三大特殊数据类型



geospatial(地理位置)

  • geoadd 键 经度 纬度 名称(添加一个地理位置)
  • geopos 键 名称(获取地理位置的经纬度)
  • geodist 键 名称1 名称2(获取两地的距离,单位m)
  • geodist 键 名称1 名称2 km(获取两地的距离,单位km)
  • georadius 键 经度 纬度 半径 单位(根据指定经纬度和半径查询附近的人)
  • georadius 键 经度 纬度 半径 单位 withdist(根据指定经纬度和半径查询附近的人,并携带距离)
  • georadius 键 经度 纬度 半径 单位 withcoord(根据指定经纬度和半径查询附近的人,并携带经纬度)
  • georadius 键 经度 纬度 半径 单位 withcoord count 1(根据指定经纬度和半径查询附近指定数量的人)
  • georaduisbymember 键 值 距离 单位(寻找指定位置指定距离内的城市)
  • geohash 键 值(将2维的经纬度转换为1维的字符串,若字符串越接近,则距离越近)



hyperloglog(类似zset)



基数

  • pfadd 键 值1 值2 … 值n
  • pfcount 键
  • pfmerge 新hyperloglog hyperloglog1 hyperloglog2(合并hyperloglog)



Bitmaps(位存储)

  • setbit 键 偏移 值
  • getbit 键 偏移
  • bitcount 键(统计为1的值)



9、持久化技术



9.1、RDB(redis默认选择)

Redis DataBase



9.1.1、触发机制

  • 使用shutdown命令,redis会自动将数据库备份
  • 数据变更满足redis.conf里的条件

    • save 900 1 # 900秒内,至少变更1次,会自动备份
    • save 300 10 # 120秒内,至少变更10次,会自动备份
    • save 60 10000 # 60秒内,至少变更10000次,会自动备份
  • save命令



9.1.2、配置详解

  • stop-writes-on-bgsave-error:

    • yes:当后台备份时候反生错误,前台停止写入
    • no:不管是否错误,都往里写数据
  • rdbcompression:对于存储到磁盘中的快照,是否启动LZF压缩算法,一般都会启动

    • yes:启动
    • no:不启动(不想消耗CPU资源,可关闭)
  • rdbchecksum:在存储快照后,是否启动CRC64算法进行数据校验;

    • yes:启动
    • no:不启动(不想消耗CPU资源,可关闭)
  • dbfilename:快照备份文件名字
  • dir:快照备份文件保存的目录,默认为当前目录



9.1.3、优缺点

优:适合大规模数据恢复,对数据完整性和一致行要求不高

劣:一定间隔备份一次,意外down掉,就失去最后一次快照的所有修改



9.2、AOF

Append Only File(将redis执行过的写指令全部记录下来

读操作不记录

,redis在启动之初会读取该文件从头到尾执行一遍,这样来重新构建数据)



9.2.1、开启

redis.conf

appendonly yes
appendfilename appendonly.aof



9.2.2、触发机制

根据appendfsync规则



9.2.3、配置详解

  • appendonly:是否开启aof

    • yes
    • no
  • appendfilename:appendonly.aof aof备份的文件
  • appendfsync:追加策略

    • always:每次数据变更,就会立即记录到磁盘,性能较差,但数据完整性好
    • everysec:默认设置,异步操作,每秒记录,如果一秒内宕机,会有数据丢失
    • no:不追加
  • no-appendfsync-on-rewrite:重写时是否运用Appendfsync追写策略;用默认no即可,保证数据安全性
  • auto-aof-rewrite-percentage:如果AOF文件大小已经超过原来的100%,也就是一倍,才重写压缩
  • auto-aof-rewrite-min-size:64mb 如果AOF文件已经超过了64mb,才重写压缩



9.2.4、优缺点

  • 在最恶劣的情况下,也只丢失不超过2秒的数据,数据完整性比较高
  • 代价太大,会带来持续的IO



10、事务

一次执行多个命令,是一个命令组,一个事务中,所有命令都会序列化(排队),不会被插队


三特性

  • 隔离性:所有命令都会按照顺序执行,事务在执行的过程中,不会被其他客户端送来的命令 打断
  • 没有隔离级别:队列中的命令没有提交之前都不会被实际的执行,不存在“事务中查询要看到 事务里的更新,事务外查询不能看到”这个头疼的问题
  • 不保证原子性:冤有头债有主,如果一个命令失败,但是别的命令可能会执行成功,没有回滚



10.1、提交事务

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 k3 v3
QUEUED
127.0.0.1:6379> get k3
QUEUED
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) OK
4) "v3"
5) OK



10.2、取消提交

127.0.0.1:6379> multi
OK
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> set k2 v222
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> get k2
"v2"



10.3、命令出错(编译出错)

取消所有执行内容

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set1231213
(error) ERR unknown command `set1231213`, with args beginning with: 
127.0.0.1:6379> set k1 v111
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k1
"v1"



10.4、命令出错(运行出错)

错误的不执行,其他照旧执行

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



11、监控

  • watch 键
  • multi(开启事务)
  • exec(执行事务)

exec后会解锁



12、发布订阅

进程间的一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息


接收端

127.0.0.1:6379> subscribe cctv1 cctv9
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "cctv1"
3) (integer) 1
1) "subscribe"
2) "cctv9"
3) (integer) 2
1) "message"
2) "cctv1"
3) "xinwenlianbo"
1) "message"
2) "cctv9"
3) "xiongchumo"


发送端

127.0.0.1:6379> publish cctv1 xinwenlianbo
(integer) 1
127.0.0.1:6379> publish cctv9 xiongchumo
(integer) 1



13、主从复制的配置



13.1、修改配置文件

bind 0.0.0.0



13.2、配置主从复制

小弟可以选择谁是大哥,但大哥没有权利去选择小弟

slaveof 81.70.1.65 6379
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0
master_replid:30d46f6b4ef072f1feff943f6ed9cba15bdf6546
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> slaveof 81.70.1.65 6379
OK
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:81.70.1.65
master_port:6379
master_link_status:up
master_last_io_seconds_ago:4
master_sync_in_progress:0
slave_repl_offset:1932
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:2357d52fcf39762c8d1ce3005b3e435e8efe1a69
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1932
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1919
repl_backlog_histlen:14



13.3、数据同步问题

只要跟随后,数据立即同步(不论是跟随前的数据还是跟随后的数据都会同步)



13.4、读写问题

跟随后,主机负责写,从机负责读(从机无法写数据)



13.5、主从问题

  • 主机关闭,从机仍是从机(会显示主机已经掉线,master_link_status:down)
  • 主机再次启动后从,机仍是从机(会显示主机已经上线,master_link_status:up)
  • 从机关闭后,对于主机而言仅仅是少了一个从机
  • 从机再次重启,身份转变为master,不在在原来的集群,需重新配置



13.6、主从复制原理

在这里插入图片描述

  • 全量复制:Slave初始化阶段,这时Slave需要将Master上的所有数据都复制一份slave接收到数据 文件后,存盘,并加载到内存中;(步骤1234)
  • 增量复制:Slave初始化后,开始正常工作时主服务器发生的写操作同步到从服务器的过程;(步骤56)
  • Redis主从同步策略:主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步
  • 如果有需要,slave 在任何时候都可以发起全量同步
  • redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步



13.7、继承

一个主机理论上可以多个从机,但是这样的话,这个主机会很累,可以使用java面向对象继承中的传递性来解决这个问题,减轻主机的负担



13.8、重选主机

当1个主机挂掉了,从2个从机中再次选1个主机,1为master,2和3为slave,当1挂掉后,2篡权为master,3跟2

slaveof no one



13.9、哨兵模式


自动版重选主机

有个哨兵一直在巡逻,突然发现!!!!!老大挂了,小弟们会自动投票,从众小弟中选出新的老大

cp /usr/local/redis-5.0.4/sentinel.conf sentinel.conf

修改配置项(仅在主机配置即可)

daemonize yes
#				 服务器名 服务器ip	
sentinel monitor redis3 101.34.116.9 6379 1

启动哨兵

[root@VM-16-14-centos bin]# redis-sentinel sentinel.conf 
24628:X 01 Aug 2021 23:34:12.366 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
24628:X 01 Aug 2021 23:34:12.366 # Redis version=5.0.4, bits=64, commit=00000000, modified=0, pid=24628, just started
24628:X 01 Aug 2021 23:34:12.366 # Configuration loaded

自己断掉主redis,查看从redis的状态,自动转为master表示成功

主机重新启动后,哨兵发现主机连接后,主机会变成小弟,重新加入集群


缺点

  • 所有的写操作都是在master上完成的,然后再同步到slave上,两台机器之间通信会有延迟
  • 当系统很繁忙的时候,延迟问题会加重
  • slave机器数量增加,问题也会加重



13.10、多哨兵模式

待补



14、Redis.conf详细配置

# 注意单位: 当需要配置内存大小时, 可能需要指定像1k,4M,5GB,等常见格式
#
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes
#
# redis是对单位大小写不敏感的 1GB 1Gb 1gB 是相同的
################################## INCLUDES 包含文件相关
###################################
# 可以在这里包含一个或多个其他的配置文件,如果你有一个适用于所有Redis服务器的标准配置模板
# 但也需要一些每个服务器自定义的设置,这个功能将很有用。被包含的配置文件也可以包含其他配置文件
#
# 注意“inclue”选项不能被admin或Redis哨兵的"CONFIG REWRITE"命令重写
# 因为Redis总是使用最后解析的配置行最为配置指令的值, 你最好在这个文件的开头配置includes来避免它在运行时重写配置
# 如果相反你想用includes的配置覆盖原来的配置,你最好在该文件的最后使用include
#
# include /path/to/local.conf
# include /path/to/other.conf
################################ GENERAL 综合配置
#####################################
# 默认Rdis不会作为守护进程运行。如果需要的话配置成'yes'
# 注意配置成守护进程后Redis会将进程号写入文件/var/run/redis.pid
daemonize no
# 当以守护进程方式运行时,默认Redis会把进程ID写到 /var/run/redis.pid,你可以在这里修改路径
pidfile /var/run/redis.pid
# 接受连接的特定端口,默认是6379
# 如果端口设置为0,Redis就不会监听TCP套接字。
port 6379
# TCP listen backlog
# server在与客户端建立tcp连接的过程中,SYN队列的大小
# 在高并发环境下你需要一个高backlog值来避免慢客户端连接问题。注意Linux内核默默地将这个值减小
# 到/proc/sys/net/core/somaxconn的值,所以需要确认增大somaxconn和tcp_max_syn_backlog
# 两个值来达到想要的效果
tcp-backlog 511
# 默认Redis监听服务器上所有可用网络接口的连接。可以用"bind"配置指令跟一个或多个ip地址来实现
# 监听一个或多个网络接口
#
# 示例:
# bind 192.168.1.100 10.0.0.1
# bind 127.0.0.1
# 指定用来监听Unix套套接字的路径。没有默认值, 所以在没有指定的情况下Redis不会监听Unix套接字
#
# unixsocket /tmp/redis.sock
# unixsocketperm 755
# 一个客户端空闲多少秒后关闭连接(0代表禁用,永不关闭)
timeout 0
# TCP keepalive.
#
# 如果非零,则设置SO_KEEPALIVE选项来向空闲连接的客户端发送ACK,由于以下两个原因这是很有用的:
#
# 1)能够检测无响应的对端
# 2)让该连接中间的网络设备知道这个连接还存活
#
# 在Linux上,这个指定的值(单位:秒)就是发送ACK的时间间隔。
# 注意:要关闭这个连接需要两倍的这个时间值。
# 在其他内核上这个时间间隔由内核配置决定
#
# 这个选项的一个合理值是60秒
tcp-keepalive 0
# 指定服务器调试等级
# 可能值:
# debug (大量信息,对开发/测试有用)
# verbose (很多精简的有用信息,但是不像debug等级那么多)
# notice (适量的信息,基本上是你生产环境中需要的)
# warning (只有很重要/严重的信息会记录下来)
loglevel notice
# 指明日志文件名。也可以使用"stdout"来强制让Redis把日志信息写到标准输出上。
# 注意:如果Redis以守护进程方式运行,而设置日志显示到标准输出的话,日志会发送到/dev/null
logfile ""
# 要使用系统日志记录器,只要设置 "syslog-enabled" 为 "yes" 就可以了。
# 然后根据需要设置其他一些syslog参数就可以了。
# syslog-enabled no
# 指明syslog身份
# syslog-ident redis
# 指明syslog的设备。必须是user或LOCAL0 ~ LOCAL7之一。
# syslog-facility local0
# 设置数据库个数。默认数据库是 DB 0,
# 可以通过select <dbid> (0 <= dbid <= 'databases' - 1 )来为每个连接使用不同的数据库
databases 16
################################ SNAPSHOTTING 快照,持久化操作配置
################################
# 把数据库存到磁盘上:
#
# save <seconds> <changes>
#
# 会在指定秒数和数据变化次数之后把数据库写到磁盘上。
#
# 下面的例子将会进行把数据写入磁盘的操作:
# 900秒(15分钟)之后,且至少1次变更
# 300秒(5分钟)之后,且至少10次变更
# 60秒之后,且至少10000次变更
#
# 注意:你要想不写磁盘的话就把所有 "save" 设置注释掉就行了。
#
# 通过添加一条带空字符串参数的save指令也能移除之前所有配置的save指令
# 像下面的例子:
# save ""
save 900 1
save 300 10
save 60 10000
# 默认如果开启RDB快照(至少一条save指令)并且最新的后台保存失败,Redis将会停止接受写操作
# 这将使用户知道数据没有正确的持久化到硬盘,否则可能没人注意到并且造成一些灾难。
#
# 如果后台保存进程能重新开始工作,Redis将自动允许写操作
#
# 然而如果你已经部署了适当的Redis服务器和持久化的监控,你可能想关掉这个功能以便于即使是
# 硬盘,权限等出问题了Redis也能够像平时一样正常工作,
stop-writes-on-bgsave-error yes
# 当导出到 .rdb 数据库时是否用LZF压缩字符串对象?
# 默认设置为 "yes",因为几乎在任何情况下它都是不错的。
# 如果你想节省CPU的话你可以把这个设置为 "no",但是如果你有可压缩的key和value的话,
# 那数据文件就会更大了。
rdbcompression yes
# 因为版本5的RDB有一个CRC64算法的校验和放在了文件的最后。这将使文件格式更加可靠但在
# 生产和加载RDB文件时,这有一个性能消耗(大约10%),所以你可以关掉它来获取最好的性能。
#
# 生成的关闭校验的RDB文件有一个0的校验和,它将告诉加载代码跳过检查
rdbchecksum yes
# 持久化数据库的文件名
dbfilename dump.rdb
# 工作目录
#
# 数据库会写到这个目录下,文件名就是上面的 "dbfilename" 的值。
#
# 累加文件也放这里。
#
# 注意你这里指定的必须是目录,不是文件名。
dir ./
################################# REPLICATION 主从复制的配置
#################################
# 主从同步。通过 slaveof 指令来实现Redis实例的备份。
# 注意,这里是本地从远端复制数据。也就是说,本地可以有不同的数据库文件、绑定不同的IP、监听
# 不同的端口。
#
# slaveof <masterip> <masterport>
# 如果master设置了密码保护(通过 "requirepass" 选项来配置),那么slave在开始同步之前必须
# 进行身份验证,否则它的同步请求会被拒绝。
#
# masterauth <master-password>
# 当一个slave失去和master的连接,或者同步正在进行中,slave的行为有两种可能:
#
# 1) 如果 slave-serve-stale-data 设置为 "yes" (默认值),slave会继续响应客户端请求,
# 可能是正常数据,也可能是还没获得值的空数据。
# 2) 如果 slave-serve-stale-data 设置为 "no",slave会回复"正在从master同步
# (SYNC with master in progress)"来处理各种请求,除了 INFO 和 SLAVEOF 命令。
#
slave-serve-stale-data yes
# 你可以配置salve实例是否接受写操作。可写的slave实例可能对存储临时数据比较有用(因为写入
salve
# 的数据在同master同步之后将很容被删除),但是如果客户端由于配置错误在写入时也可能产生一些问题。
#
# 从Redis2.6默认所有的slave为只读
#
# 注意:只读的slave不是为了暴露给互联网上不可信的客户端而设计的。它只是一个防止实例误用的保护层。
# 一个只读的slave支持所有的管理命令比如config,debug等。为了限制你可以用'renamecommand'来
# 隐藏所有的管理和危险命令来增强只读slave的安全性
slave-read-only yes
# slave根据指定的时间间隔向master发送ping请求。
# 时间间隔可以通过 repl_ping_slave_period 来设置。
# 默认10秒。
#
# repl-ping-slave-period 10
# 以下选项设置同步的超时时间
#
# 1)slave在与master SYNC期间有大量数据传输,造成超时
# 2)在slave角度,master超时,包括数据、ping等
# 3)在master角度,slave超时,当master发送REPLCONF ACK pings
#
# 确保这个值大于指定的repl-ping-slave-period,否则在主从间流量不高时每次都会检测到超时
#
# repl-timeout 60
# 是否在slave套接字发送SYNC之后禁用 TCP_NODELAY ?
#
# 如果你选择“yes”Redis将使用更少的TCP包和带宽来向slaves发送数据。但是这将使数据传输到
slave
# 上有延迟,Linux内核的默认配置会达到40毫秒
#
# 如果你选择了 "no" 数据传输到salve的延迟将会减少但要使用更多的带宽
#
# 默认我们会为低延迟做优化,但高流量情况或主从之间的跳数过多时,把这个选项设置为“yes”
# 是个不错的选择。
repl-disable-tcp-nodelay no
# 设置数据备份的backlog大小。backlog是一个slave在一段时间内断开连接时记录salve数据的缓
冲,
# 所以一个slave在重新连接时,不必要全量的同步,而是一个增量同步就足够了,将在断开连接的这段
# 时间内slave丢失的部分数据传送给它。
#
# 同步的backlog越大,slave能够进行增量同步并且允许断开连接的时间就越长。
#
# backlog只分配一次并且至少需要一个slave连接
#
# repl-backlog-size 1mb
# 当master在一段时间内不再与任何slave连接,backlog将会释放。以下选项配置了从最后一个
# slave断开开始计时多少秒后,backlog缓冲将会释放。
#
# 0表示永不释放backlog
#
# repl-backlog-ttl 3600
# slave的优先级是一个整数展示在Redis的Info输出中。如果master不再正常工作了,哨兵将用它来
# 选择一个slave提升=升为master。
#
# 优先级数字小的salve会优先考虑提升为master,所以例如有三个slave优先级分别为10,100,25,
# 哨兵将挑选优先级最小数字为10的slave。
#
# 0作为一个特殊的优先级,标识这个slave不能作为master,所以一个优先级为0的slave永远不会被
# 哨兵挑选提升为master
#
# 默认优先级为100
slave-priority 100
# 如果master少于N个延时小于等于M秒的已连接slave,就可以停止接收写操作。
#
# N个slave需要是“oneline”状态
#
# 延时是以秒为单位,并且必须小于等于指定值,是从最后一个从slave接收到的ping(通常每秒发送)
# 开始计数。
#
# This option does not GUARANTEES that N replicas will accept the write, but
# will limit the window of exposure for lost writes in case not enough slaves
# are available, to the specified number of seconds.
#
# 例如至少需要3个延时小于等于10秒的slave用下面的指令:
#
# min-slaves-to-write 3
# min-slaves-max-lag 10
#
# 两者之一设置为0将禁用这个功能。
#
# 默认 min-slaves-to-write 值是0(该功能禁用)并且 min-slaves-max-lag 值是10。
################################## SECURITY 安全相关配置
###################################
# 要求客户端在处理任何命令时都要验证身份和密码。
# 这个功能在有你不信任的其它客户端能够访问redis服务器的环境里非常有用。
#
# 为了向后兼容的话这段应该注释掉。而且大多数人不需要身份验证(例如:它们运行在自己的服务器上)
#
# 警告:因为Redis太快了,所以外面的人可以尝试每秒150k的密码来试图破解密码。这意味着你需要
# 一个高强度的密码,否则破解太容易了。
#
# requirepass foobared
# 命令重命名
#
# 在共享环境下,可以为危险命令改变名字。比如,你可以为 CONFIG 改个其他不太容易猜到的名字,
# 这样内部的工具仍然可以使用,而普通的客户端将不行。
#
# 例如:
#
# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
#
# 也可以通过改名为空字符串来完全禁用一个命令
#
# rename-command CONFIG ""
#
# 请注意:改变命令名字被记录到AOF文件或被传送到从服务器可能产生问题。
################################### LIMITS 范围配置
####################################
# 设置最多同时连接的客户端数量。默认这个限制是10000个客户端,然而如果Redis服务器不能配置
# 处理文件的限制数来满足指定的值,那么最大的客户端连接数就被设置成当前文件限制数减32(因
# 为Redis服务器保留了一些文件描述符作为内部使用)
#
# 一旦达到这个限制,Redis会关闭所有新连接并发送错误'max number of clients reached'
#
# maxclients 10000
# 不要用比设置的上限更多的内存。一旦内存使用达到上限,Redis会根据选定的回收策略(参见:
# maxmemmory-policy)删除key
#
# 如果因为删除策略Redis无法删除key,或者策略设置为 "noeviction",Redis会回复需要更
# 多内存的错误信息给命令。例如,SET,LPUSH等等,但是会继续响应像Get这样的只读命令。
#
# 在使用Redis作为LRU缓存,或者为实例设置了硬性内存限制的时候(使用 "noeviction" 策略)
# 的时候,这个选项通常事很有用的。
#
# 警告:当有多个slave连上达到内存上限的实例时,master为同步slave的输出缓冲区所需
# 内存不计算在使用内存中。这样当驱逐key时,就不会因网络问题 / 重新同步事件触发驱逐key
# 的循环,反过来slaves的输出缓冲区充满了key被驱逐的DEL命令,这将触发删除更多的key,
# 直到这个数据库完全被清空为止
#
# 总之...如果你需要附加多个slave,建议你设置一个稍小maxmemory限制,这样系统就会有空闲
# 的内存作为slave的输出缓存区(但是如果最大内存策略设置为"noeviction"的话就没必要了)
#
# maxmemory <bytes>
# 最大内存策略:如果达到内存限制了,Redis如何选择删除key。你可以在下面五个行为里选:
#
# volatile-lru -> 根据LRU算法生成的过期时间来删除。
# allkeys-lru -> 根据LRU算法删除任何key。
# volatile-random -> 根据过期设置来随机删除key。
# allkeys->random -> 无差别随机删。
# volatile-ttl -> 根据最近过期时间来删除(辅以TTL)
# noeviction -> 谁也不删,直接在写操作时返回错误。
#
# 注意:对所有策略来说,如果Redis找不到合适的可以删除的key都会在写操作时返回一个错误。
#
# 目前为止涉及的命令:set setnx setex append
# incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd
# sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby
# zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby
# getset mset msetnx exec sort
#
# 默认值如下:
#
# maxmemory-policy volatile-lru
# LRU和最小TTL算法的实现都不是很精确,但是很接近(为了省内存),所以你可以用样本量做检测。
# 例如:默认Redis会检查3个key然后取最旧的那个,你可以通过下面的配置指令来设置样本的个数。
#
# maxmemory-samples 3
############################## APPEND ONLY MODE AOF模式配置
###############################
# 默认情况下,Redis是异步的把数据导出到磁盘上。这种模式在很多应用里已经足够好,但Redis进程
# 出问题或断电时可能造成一段时间的写操作丢失(这取决于配置的save指令)。
#
# AOF是一种提供了更可靠的替代持久化模式,例如使用默认的数据写入文件策略(参见后面的配置)
# 在遇到像服务器断电或单写情况下Redis自身进程出问题但操作系统仍正常运行等突发事件时,Redis
# 能只丢失1秒的写操作。
#
# AOF和RDB持久化能同时启动并且不会有问题。
# 如果AOF开启,那么在启动时Redis将加载AOF文件,它更能保证数据的可靠性。
#
# 请查看 http://redis.io/topics/persistence 来获取更多信息.
appendonly no
# 纯累加文件名字(默认:"appendonly.aof")
appendfilename "appendonly.aof"
# fsync() 系统调用告诉操作系统把数据写到磁盘上,而不是等更多的数据进入输出缓冲区。
# 有些操作系统会真的把数据马上刷到磁盘上;有些则会尽快去尝试这么做。
#
# Redis支持三种不同的模式:
#
# no:不要立刻刷,只有在操作系统需要刷的时候再刷。比较快。
# always:每次写操作都立刻写入到aof文件。慢,但是最安全。
# everysec:每秒写一次。折中方案。
#
# 默认的 "everysec" 通常来说能在速度和数据安全性之间取得比较好的平衡。根据你的理解来
# 决定,如果你能放宽该配置为"no" 来获取更好的性能(但如果你能忍受一些数据丢失,可以考虑使用
# 默认的快照持久化模式),或者相反,用“always”会比较慢但比everysec要更安全。
#
# 请查看下面的文章来获取更多的细节
# http://antirez.com/post/redis-persistence-demystified.html
#
# 如果不能确定,就用 "everysec"
# appendfsync always
appendfsync everysec
# appendfsync no
# 如果AOF的同步策略设置成 "always" 或者 "everysec",并且后台的存储进程(后台存储或写入AOF
# 日志)会产生很多磁盘I/O开销。某些Linux的配置下会使Redis因为 fsync()系统调用而阻塞很久。
# 注意,目前对这个情况还没有完美修正,甚至不同线程的 fsync() 会阻塞我们同步的write(2)调用。
#
# 为了缓解这个问题,可以用下面这个选项。它可以在 BGSAVE 或 BGREWRITEAOF 处理时阻止fsync()。
#
# 这就意味着如果有子进程在进行保存操作,那么Redis就处于"不可同步"的状态。
# 这实际上是说,在最差的情况下可能会丢掉30秒钟的日志数据。(默认Linux设定)
#
# 如果把这个设置成"yes"带来了延迟问题,就保持"no",这是保存持久数据的最安全的方式。
no-appendfsync-on-rewrite no
# 自动重写AOF文件
# 如果AOF日志文件增大到指定百分比,Redis能够通过 BGREWRITEAOF 自动重写AOF日志文件。
#
# 工作原理:Redis记住上次重写时AOF文件的大小(如果重启后还没有写操作,就直接用启动时的AOF大
小)
#
# 这个基准大小和当前大小做比较。如果当前大小超过指定比例,就会触发重写操作。你还需要指定被重写
# 日志的最小尺寸,这样避免了达到指定百分比但尺寸仍然很小的情况还要重写。
#
# 指定百分比为0会禁用AOF自动重写特性。
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
################################ LUA SCRIPTING ###############################
# 设置lua脚本的最大运行时间,单位为毫秒,redis会记个log,然后返回error。当一个脚本超过了最大时限。
# 只有SCRIPT KILL和SHUTDOWN NOSAVE可以用。第一个可以杀没有调write命令的东西。要是已经调用了write,只能用第二个命令杀。
lua-time-limit 5000
################################## SLOW LOG ###################################
# 是redis用于记录慢查询执行时间的日志系统。由于slowlog只保存在内存中,因此slowlog的效率很高,完全不用担心会影响到redis的性能。
# 只有query执行时间大于slowlog-log-slower-than的才会定义成慢查询,才会被slowlog进行记录。
# 单位是微妙
slowlog-log-slower-than 10000
# slowlog-max-len表示慢查询最大的条数
slowlog-max-len 128
############################ EVENT NOTIFICATION ##############################
# 这个功能可以让客户端通过订阅给定的频道或者模式,来获知数据库中键的变化,以及数据库中命令的执行情况,所以在默认配置下,该功能处于关闭状态。
# notify-keyspace-events 的参数可以是以下字符的任意组合,它指定了服务器该发送哪些类型的通知:
# K 键空间通知,所有通知以 __keyspace@__ 为前缀
# E 键事件通知,所有通知以 __keyevent@__ 为前缀
# g DEL 、 EXPIRE 、 RENAME 等类型无关的通用命令的通知
# $ 字符串命令的通知
# l 列表命令的通知
# s 集合命令的通知
# h 哈希命令的通知
# z 有序集合命令的通知
# x 过期事件:每当有过期键被删除时发送
# e 驱逐(evict)事件:每当有键因为 maxmemory 政策而被删除时发送
# A 参数 g$lshzxe 的别名
# 输入的参数中至少要有一个 K 或者 E,否则的话,不管其余的参数是什么,都不会有任何 通知被分发。详细使用可以参考http://redis.io/topics/notifications
notify-keyspace-events ""
############################### ADVANCED CONFIG ###############################
# 单位字节:数据量小于等于hash-max-ziplist-entries的用ziplist,大于hash-max-ziplistentries用hash
hash-max-ziplist-entries 512
# value大小小于等于hash-max-ziplist-value的用ziplist,大于hash-max-ziplist-value用hash。
hash-max-ziplist-value 64
# 数据量小于等于list-max-ziplist-entries用ziplist(压缩列表),大于list-max-ziplistentries用list。
list-max-ziplist-entries 512
# value大小小于等于list-max-ziplist-value的用ziplist,大于list-max-ziplist-value用list。
list-max-ziplist-value 64
# 数据量小于等于set-max-intset-entries用iniset,大于set-max-intset-entries用set。
set-max-intset-entries 512
# 数据量小于等于zset-max-ziplist-entries用ziplist,大于zset-max-ziplist-entries用zset。
zset-max-ziplist-entries 128
# value大小小于等于zset-max-ziplist-value用ziplist,大于zset-max-ziplist-value用zset。
zset-max-ziplist-value 64
# 基数统计的算法 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数
# 设置HyeperLogLog的字节数限制,这个值通常在0~15000之间,默认为3000,基本不超过16000。
# value大小小于等于hll-sparse-max-bytes使用稀疏数据结构(sparse),大于hll-sparse-maxbytes使用稠密的数据结构(dense)。
# 一个比16000大的value是几乎没用的,建议的value大概为3000。如果对CPU要求不高,对空间要求较高的,建议设置到10000左右。
hll-sparse-max-bytes 3000
# 重置hash。 Redis将在每100毫秒时使用1毫秒的CPU时间来对redis的hash表进行重新hash,可以降低内存的使用。
# 当你的使用场景中,有非常严格的实时性需要,不能够接受Redis时不时的对请求有2毫秒的延迟的话,把这项配置为no。
# 如果没有这么严格的实时性要求,可以设置为yes,以便能够尽可能快的释放内存。
activerehashing yes
# 对于Redis服务器的输出(也就是命令的返回值)来说,其大小通常是不可控制的。有可能一个简单的命令,能够产生体积庞大的返回数据。
# 另外也有可能因为执行了太多命令,导致产生返回数据的速率超过了往客户端发送的速率,这是也会导致服务器堆积大量消息,
# 从而导致输出缓冲区越来越大,占用过多内存,甚至导致系统崩溃。
# 用于强制断开出于某些原因而无法以足够快的速度从服务器读取数据的客户端的连接。
# 对于normal client,包括monitor。第一个0表示取消hard limit,第二个0和第三个0表示取消
# soft limit,normal client默认取消限制,因为如果没有寻问,他们是不会接收数据的。
client-output-buffer-limit normal 0 0 0
#对于slave client和MONITER client,如果client-output-buffer一旦超过256mb,又或者超过64mb持续60秒,那么服务器就会立即断开客户端连接。
client-output-buffer-limit slave 256mb 64mb 60
#对于pubsub client,如果client-output-buffer一旦超过32mb,又或者超过8mb持续60秒,那么服务器就会立即断开客户端连接。
client-output-buffer-limit pubsub 32mb 8mb 60
# redis执行任务的频率
hz 10
# aof rewrite过程中,是否采取增量"文件同步"策略,默认为"yes",而且必须为yes.
# rewrite过程中,每32M数据进行一次文件同步,这样可以减少"aof大文件"写入对磁盘的操作次数.
aof-rewrite-incremental-fsync yes



15、Jedis



15.1、redis服务器准备

  • 服务器配置安全组
  • redis允许所有ip访问(注释bind 127.0.0.1)
  • 关闭保护模式(protected-mode no)

附上linux防火墙命令

  • systemctl start firewalld:启动
  • systemctl status firewalld:查看状态
  • systemctl disable firewalld:禁止开机启动
  • systemctl stop firewalld:停止运行
  • firewall-cmd –zone=public –list-ports:查看所有打开的端口
  • firewall-cmd –reload更新防火墙规则
  • 开启端口:firewall-cmd –zone=public –add-port=80/tcp –permanent (–permanent永久生效,没有此参数重启后失效)



15.2、导入依赖

<dependencies>
    <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>3.2.0</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13</version>
        <scope>test</scope>
    </dependency>
</dependencies>



15.3、测试

public class RedisTest {
    @Test
    public void ping(){
        Jedis jedis=new Jedis("106.54.85.216",6379);
        System.out.println(jedis.ping());
    }
}



15.4、API

同linux操作命令,示例待补



15.5、事务

@Test
public void transaction(){
    Jedis jedis=new Jedis("106.54.85.216",6379);
    jedis.set("in","5000");
    jedis.set("out","1000");
    try {
        Transaction multi = jedis.multi();
        multi.decrBy("in",500);
        multi.incrBy("out",500);
        multi.exec();
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println(jedis.get("in"));
    System.out.println(jedis.get("out"));
}



16、JedisPool



16.1、导入依赖

<dependencies>
    <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>3.2.0</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13</version>
        <scope>test</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/commons-pool/commons-pool -->
    <dependency>
        <groupId>commons-pool</groupId>
        <artifactId>commons-pool</artifactId>
        <version>1.6</version>
    </dependency>
</dependencies>



16.2、JedisPoolUtil

public class JedisPoolUtil {
    private volatile static JedisPool jedisPool=null;

    private static JedisPool createJedisPool(){
        if (jedisPool==null){
            synchronized (JedisPoolUtil.class){
                JedisPoolConfig jedisPoolConfig=new JedisPoolConfig();
                // 连接池中的最大连接数
                jedisPoolConfig.setMaxTotal(100);
                // 连接池允许的最大空闲连接数
                jedisPoolConfig.setMaxIdle(30);
                // 当连接池连接用尽后,调用者的最大等待时间(单位为毫秒)
                jedisPoolConfig.setMaxWaitMillis(30*1000);
                // 向连接池借用连接时是否做连接有效性检测(业务量很大时候建议设置为false,减少一次ping的开销)
                jedisPoolConfig.setTestOnBorrow(true);
                jedisPool=new JedisPool(jedisPoolConfig,"106.54.85.216",6379);
            }
        }
        return jedisPool;
    }
    public static Jedis createJedis(){
        if (jedisPool==null){
            return createJedisPool().getResource();
        }
        return jedisPool.getResource();
    }
}



版权声明:本文为gyfghh原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。