Redis学习笔记
一、概述
1.redis简介
1.1 redis是什么
是nosql技术的一应用(nosql---not only sql,nosql的产品主要有redis,memcache,mongdb),是一个开源的C语言编写、基于内存亦可持久化的Key-Value数据库,并提供多种语言的API.
1.2 用在哪里?
应用程序从MySQL查询到的数据,在redis登记一下,后面再需要用到的时候,就先找redis要,redis这里没有再找MySQL要。

1.2 redis优势
- 单线程:Redis 操作是单进程单线程,因为 Redis是基于内存的操作,CPU 不是瓶颈,机器内存的大小或者网络带宽才有可能是瓶颈。
- 高速:每秒可达到100万次以上的查询速度。为什么是单线程还这么快?
- 基于内存操作
- 不存在多线程导致的 CPU 切换,不需要加锁释放锁,没有死锁问题。
- 使用多路复用技术
- Redis相比memcached有哪些优势?
- memcached所有的值均是简单的字符串,redis作为其替代者, 支持更为丰富的数据类型
- redis的速度比memcached快很多
- redis可以持久化其数据
1.3 分布式系统与集群的区别:
- 分布式:多台服务器上部署不同的模块
- 集群:多台服务器上部署相同模块
redis---remote dictionary server的缩写,是用key/value的形式存储数据,是一种内存数据
1.4 传统数据库事物四大特征:ACID
- atomicity--原子性
- consistency--一致性
- isolation--隔离性
- durability--持久性
1.5 nosql数据库事务的三大特征:CAP
- consistency--一致性:指集群中每台节点中的数据都是一样的
- availability--高可用性:在任何时间点对服务器集群的读写操作都在规定时间内得到应答
- partition tolerance---分区容错性:指集群中部分中节点挂掉后,不会影响整个集群的正常运行
- CAP特点分析
- 传统数据库如mysql,能满足CA
- 集群和分布式系统中必须满足P
- ap型网站:大多数网站都采用a和p,强调高可用,可容忍适当的不一致性
- cp型网站:强调高一致性,网站会在高峰期后进行部署cp
2.redis的安装
下载地址:http://redis.cn
1.把/opt/software目录下的redis包解压到/opt/module目录中
tar -zxvf /opt/software/redis/redis-5.0.3.tar.gz -C /opt/module/
2.安装redis
因为redis是用c写的,所以只能用c的编译器gcc,如果系统中没有gcc编译器,则用 yum install gcc-c++先安装编译器
进入redis目录中,输入命令make,会使用makefile文件中的指令进行自动编译
3.make install安装文件
3.启动redis服器
进入/opt/module/redis目录中,redis-server redis.conf---默认启动会独占用一个窗口,不方便
可通过vim redis.conf文件,把daemonize no---改为daemonize yes,从而使服务器在启动后在后台运行
关闭服器:ps -aux | grep redis 获取pid--->kill -9 pid号
也可通过连接客户端,输入shutdown,quit关闭
5.开启redis客户端
redis-cli -p 6379
远程连接:
vim redis.conf--->注释掉bind 127.0.0.1-->protected-mode no-->
redis-cli -h 192.168.184.100 -p 6379
set test abc--添加一个键值对,get test--通过key取value
keys *--获取全部的key
二、基本操作
1.数据选择
redis一共有16个数据库,名称0,1,2,...15,默认用的是0号数据库,可通过select 数字的方式指定要使用哪个数据库
数据库中存储的数据中,key全是string,value可为String,Set,List,Sorted-set,Hash
2.五种数据类型及操作
2.1 string类型的数据
- set admin 123
- get admin
- del admin
- exists admin--判断是否存在key为admin,不存在返回0
- append admin 456--把key为admin的数据追加456
- strlen admin--获取value的长度
- incr num--num值增一,incrby num 2---增加步长为2
- decr num---num减一
- decrby num 2--每次执行减2
- setnx num 50---不存在num这个key则添加并设置值,存在则什么都不作,返回0
- set admin tom ex 5---添加数据,使其存活时间(expire)5秒
- set admin tom px 8000--添加数据,存活8000毫秒
- ttl admin---看数据能活多久
- getset admin 123---获取旧admin的值,修改成新值
- set admin "hello world"---如果value中包含特殊字符,可用"xxx"
- setrange admin 5 123---把下标为5处的三个字符替换成123
- getrange admin 2 4--获取下标为2到4处的字符
- mset a1 11 a2 22 a3 33---可一次添加多个键值对,这里是三对
- mget a1 a2 a3 admin---批量获取数据
2.2 list类型的数据
是一种顺序存储的双向链表,在头和尾增删元素效率高,中间效率低,应用场景:最新消息排行、消息队列。
- lpush list a b c d---添加4个元素,下标为0的元素d,每次都添加到头部(左边)。
- rpush lly a b c d添加顺序跟上面相反,每次都添加到尾部(右部)
- lrange list 0 2---获取元素为d c b
- lrange list 0 -1---获取list中全部元素
- lpop list---弹出栈顶元素并删除元素
- llen list---获取list集合元素个数
- lrem list 2 a--删除元素,如果有 很多个a元素,则删除最多2个,从下标为0位置
- lindex list 2--获取下标为2的元素
- lset list 2 hello---修改下标为2位置处元素的值hello
- del list---删除key为list的元素
2.3 set类型
元素不重复,应用场景:利用唯一性,统计访问网站的所有ip
-
sadd set a a b----向set集合中只放入2个元素
-
smembers set---查看set集合中元素
-
scard set---获取集合中元素数量
-
sismember set a----判断a元素在set中是否存在
-
srandmember set---随机获取一个元素
-
srandmember set 2--随机获取两个
-
spop set 1--弹出集合中一个元素,从集合中删除
-
srem set d---删除指定的元素d
2.4. sorted-set
每个元素都有一个权重,元素自动按权重排序,元素不能重复,但权重可重复,应用场景:排行榜。
- zadd lly 10 a 8 b 15 c---添加三个元素a,b,c,其权重分别为10,8,15
- zrange lly 0 -1---显示全部元素
- zrange lly 0 -1 withscores---带权重查看元素
- zcard lly--有几个元素
- zrank lly b---获取指定元素的下标
- zrem lly b--删除指定元素
- zscore lly c---显示指定元素的权重
- zrevrange lly 0 -1---倒序显示元素
2.5 hash类型
可理解为java中的Map,应用场景:购物车
- hset lly user tom---添加一对键值对
- hmset lly phone 1391222 address nj
- hget lly user
- hmget lly user phone age
- hgetall lly---获取全部元素
- hkeys lly---获取全部key
- hvals lly---获取全部value集合
- hlen lly--获取多少个键值对
- hdel lly phone
- hexists lly user---判断是否存在key为user的元素,有则返回1没有返回0
3.常规操作
- flushdb--清空当前选择的数据库,
- flushall清空所有数据库中数据
- keys *---全部key
- keys a*---a开头的key
- select 数字---选择某一个数据库,一共16个,第一个为0,最后一个为15
三、事物
1.redis的事物是部分事务
1.multi---开启事务
2.exec---提交事务
3.discard---回滚事务队列中所有命令
redis事务特点:在执行事务过程中,如果有不能入队列,则事务直接结束,如果队列中有语句不能成功执行,那么仅仅这一条失败,其它语句照样执行,也就是说redis单条命令是原子的,但事务不支持原子性。
所以redis仅部分的支持事物
示例:
set age 0
set lly 0
multi
set age 20
lrange lly 0 -1 ---错误,但能入队列,如果改为hello lly 0 -1就直接结束事务,全回滚
exec
结果中age变为20,但lly这条语句不能执行.
2 watch操作
类似乐观锁,只监测版本号,每次改动后会把版本号增1,如果本次提交时发现版本号比当前事务中保存的版本号大,就失败
窗口1
set money 1000
watch money
multi
窗口2
set money 120
窗口1
set money 50
exec
get money
四、主从复制
将读写分离,通过配置多个从服务器,执行读操作,从而实现负载均衡。
1.不修改配置文件实现主从复制
redis-server --port 6380 --slaveof 127.0.0.1 6379
2.修改配置文件的默认端口号
- cp一份配置文件命名为redis.conf6380并把默认端口号从6379改为6380
- redis-server redis.conf---启动主服务器
- redis-server redis.conf6380---启动从服务器
- 从两个窗口连接服务器 redis-cli -p 端口号
- slaveof 127.0.0.1 6379---让6380端口的服务器成为跟随者
- 查看每个客户端状态info replication
3.主从特点
主服务器可读可写,但从服务器只读,从而实现了读写分离和负载均衡功能
4.如何实现从为主
4.1 手动实现
关闭主服务器shutdown,在从服务器中slaveof no one
4.2哨兵模式
当主机挂掉后自动让从服务器反客为主
-
把sentinel.con文件中的sentinel monitor mymaster....中的2改为1
-
redis-server redis.conf---开启主机
-
redis-server redis.conf 6380--开启从机
-
redis-sentinel sentinel.conf--启动哨兵来监听主从服务器的状态
-
让主机挂掉,过一会儿再看从机的状态
-
选举制度:
如果有多个从机,则当主机挂掉后,多个从机会对自己从主机哪里得到 的数据量进行排名,得到数据量多的从机向其它节点发起投票,得到的票数过半就当选leader
五、持久化
1.RDB持久化:
采用快照方式存储,也就是文件中存储的是内存中数据本身
1.1 自动保存
save 900 1---15分钟内修改就会保存在dump.rdb文件中
save 300 10---5分钟内修改了10次及以上会自动保存到dump.rdb文件中
save 60 10000---1分钟内修改了1万次会保存到文件中
1.2 手动保存
save---该命令会把内存中数据保存到文件中
缺点:在保存期间会阻塞用户请求
优点:服务器消耗小
bgsave--同上
优点:不会阻塞用户请求
缺点:服务器压力大,因为会为数据的备份额外开一个线程
2.AOF持久化
原理:会把所有的写指令自动记录会先写往缓冲区中,当缓冲区满或时间到了就会一次性写到appendonly.aof文件中,在服务器重启时,会首先读取appendonly.aof文件
前提是要修改配置文件,把appendonly no这一行改成yes
问题1:rdb与aof各有什么特点?
-
rdb:
- 能够在指定的时间间隔内对数据进行快照存储
- 恢复数据快,但数据可能会少量丢失,ps -aux | grep redis--->得到进程号-->修改数据-->kill -9 进程号会导致数据丢失.
-
aof:
-
记录每次对服务器的写操作,服务器重启时会重新执行这些写命令来恢复数据,而且redis还能对aof文件进行优化,从而减少文件大小
-
恢复数据没有rdb快,但数据不易丢失
-
问题2:appendonly.aof与dump.rdb是否可共存?
可以,会优先读取aof文件,如果不存在会默认创建该文件,如果创建不成功或aof损坏则会进一步读取dump.rdb
六、java访问redis
1.连接客户端
1.先在配置文件redis.conf中把bind 127.0.0.1这一行注释掉
2.protected-mode yes改 为no
Jedis j = new Jedis("192.168.66.128",6379);
2.事务
- 乐观锁:j.watch("money");
- 开启事务:Transaction t = j.multi()
- 提交事务:list = t.exec(),如果事务失败则list为null
3.主从复制
创建主服务器的客户端和从服务器的客户端
向主服务器写数据,从服务器用来读数据
4. 连接池
- 要把连接池子作成单例。
- JedisPoolConfig用来设置池子
- pool.returnResourceObject(j)释放连接
- pool.getResource()获得连接
七、秒杀时的超卖问题
-
原理:
利用redis的快速及单个命令的原子性解决减库存
-
用到的知识点
- redis连接池
- 减法器CountDownLatch
八、redis的问题
1. 缓存穿透
1.1 什么是穿透?
用户使用一个不存在的key从redis中查询-->redis失败-->传统数据库-->查询失败,这一过程反复出现则导致mysql繁忙且是白忙,甚至会压跨数据库,而redis的作用无法发挥。

1.2 如何解决?
-
如果一个查询返回的数据为空,则把这一结果缓存到redis中,并且对这个数据设置一较短的过期时间。----问题:a) 如果攻击方通过频繁更换不存在的key来访问,会导致存储空间存在大量无效数据,从而占用过多缓存。
-
使用布隆过滤器:
-
原理
对所有可能查询的参数使用若干个(两个为例)hash算法不同的函数计算出两个数值,这两数值按数组长度取模后对应于数组中两个下标,则给这两下标处的元素置1,当要判断一个参数在mysql中是否存在时,先对该参数hash得出两个数值,再取模,这个结果作为数组下标,查看这两位置处是否都为1,如果都为1则认为该参数存在(实际不一定存在),如果有一个为0就认为必不存在直接丢弃,从而避免了对底层存储查询压力。
-
特点:它说该数据存在,那么它不一定存在,它说该数据不存在,那就一定不存在,所以是一个使用一定的错误率来换取空间(占用空间少)和时间(判断速度快)的算法。
-
提高准备率:
可通过扩大数组的长度和hash函数的个数来提升,但这两个指标增长太多,会增加存储空间,降低判断效率。
![image]()
![image]()
-
2. 缓存雪崩
指的是某一个时间段,一大批数据集中过期,比如双十一,而对这批商品的集中高并发访问时,在某一个时间点会同时无法查询到,从而全都转到传统数据库中,对数据库产生周期性的压力.
还可能是某个缓存服务器宕机或断网才是致命的,导致查询集中到传统数据库上。
如何解决?

- 可给每项数据的缓存设置过期时间为随机值。
- 限流降级:可通过队列来控制并发量.
- redis高可用:设置redis集群。
- 数据预热:在正式部署前,先把可能用到的数据预先访问一遍,这样就会在缓存中存储了部分数据。
3.缓存击穿
是指高并发集中对某一个数据访问,当这个key在失效的瞬间,持续的高并发就穿破缓存,就像在屏障上凿穿一个洞,直接请求数据库,从而可能瞬间 把后端db压垮

解决办法:(1)设置请求队列或添加分布式锁。(2)设置热点数据永远不过期



浙公网安备 33010602011771号