Redis
Nosql概述
为什么要用nosql?
大数据时代,大数据一般的数据库无法进行分析处理了
什么是NoSQL
关系型数据库=表格,行,列
NoSQL =Not Onlu SQL(不仅仅是SQL)
很多的数据里欸选哪个用户的个人信息,社交网络,地理位置。这些数据类型的存储不需要一个固定的格式
Nosql特点
解耦!
1。方便扩展(数据之间没有关系,很好扩展!)
2。大数据量高性能(Redis一秒写8万次,读取11万,NoSQL的缓存记录级,是一种细粒度的缓存,性能会比较高)
3.数据类型是多样型的
五大基本数据类型
String
List
Set
Hash
Zset
三种特殊数据类型
geo
hyperloglog
bitmap
传统的RDBMS和NoSQL
传统的RDBMS
-结构化组织
-SQL
-数据和关系都存在单独的表中
-操作,数据定义语言
-严格的一致性
-基础的事务
NoSQL
-不仅仅是数据
-没有固定的查询语言
-键值对存储,列存储,文档存储、图形数据库(社交关系)
-最终一致性
-CAP定理和BASE(异地多活)初级架构师
-高性能,高可用,高可扩
Redis能干嘛?
1.内存存储、持久化,内存中是断电即失、所有说持久化很重要
2.效率高,可以用于高速缓存
3,发布订阅系统
4,地图信息分析
5。计时器、计数器(浏览量)
特性:
1、多样的数据类型
2、持久性
3、集群
4、事务
Window下安装
1.下载安装包官网
2.运行redis-server.exe服务
3.同时运行redis-cli.exe连接redis
winodw下使用Redis使用简单,但是Redis推荐我们去Linux
Linux安装
1.官网下载tar.gz
2.解压
移动/opt文件,解压 tar -zxvf redis-6.0.9.tar.gz
3.进入解压后的文件,可以看到我们的配置文件
4.基本的环境安装
yum install gcc-c++
make
make install 确认安装没问题
如果有问题
Centos7安装redis6.0.3,报错make[1]: *** [server.o] Error 1的解决
菜鸟先飞123 2020-07-03 16:21:48 2250 收藏 9
分类专栏: redis 文章标签: redis desktop manager
版权
原因是因为gcc版本过低,yum安装的gcc是4.8.5的。因此需要升级gcc,升级过程如下:
yum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
scl enable devtoolset-9 bash
echo "source /opt/rh/devtoolset-9/enable" >> /etc/profile
gcc -v
make 和make install以后即可。注意安装完成以后redis-server在/usr/local/bin/目录下。
5。redis的默认安装路径 usr/
5.将redis配置文件。复制到我们当前目录下
复制到/opt/lconfig
6.redis默认不是后台,修改配置文件
7.启动redis服务
redis-server lconfig/redis.conf //启动复制之后的redis.config文件
redis-cli -p 6379端口号 测试连接
8.查看redis的进程是否开启
9.关闭服务
shutdown
测试性能
redis-benchmark是一个压力测试工具
官方自带的
我们简单测试一下:
#测试:100个并发连接,100000请求 redis-benchmark -h localhost -p 6379 -c 100 -n
100000
基础知识
默认16个数据库
默认使用是第0个
可以使用select进行切换
keys * #查看所有 flushdb 清除当前数据库 flushall 清除全部数据库
Redis是单线程
基于内存操作,cpu不是Redis性能瓶颈,Redis的根据机器的内存和网络带宽
为什么Redis单线程这么快?
核心:redis是将所有的数据全部放在内存中,所以说使用单线程去操作效率就是最高的,cpu会有上下文切换
五大数据类型
Redis-key
[root@daleilei bin]# redis-server lconfig/redis.conf
[root@daleilei bin]# redis-cli -p 6379
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> select 3
OK
127.0.0.1:6379[3]> DBSIZE
(integer) 0
127.0.0.1:6379[3]> set name daleilei
OK
127.0.0.1:6379[3]> DBSIZE
(integer) 1
127.0.0.1:6379[3]> select 7
OK
127.0.0.1:6379[7]> DBSIZE
(integer) 0
127.0.0.1:6379[7]> get na
(nil)
127.0.0.1:6379[7]> get name
(nil)
127.0.0.1:6379[7]> select 3
OK
127.0.0.1:6379[3]> DBSIZE
(integer) 1
127.0.0.1:6379[3]> get name
"daleilei"
127.0.0.1:6379[3]> keys *
1) "name"
127.0.0.1:6379[3]> select 0
OK
127.0.0.1:6379> keys *
1) "counter:__rand_int__"
2) "mylist"
3) "myhash"
4) "key:__rand_int__"
127.0.0.1:6379> clear
127.0.0.1:6379> set name daleilei
OK
127.0.0.1:6379> keys *
1) "key:__rand_int__"
2) "mylist"
3) "counter:__rand_int__"
4) "myhash"
5) "name"
127.0.0.1:6379> set age 1
OK
127.0.0.1:6379> get age
"1"
127.0.0.1:6379> EXISTS name
(integer) 1
127.0.0.1:6379> EXISTS name1
(integer) 0
127.0.0.1:6379> move name 1
(integer) 1
127.0.0.1:6379> keys
(error) ERR wrong number of arguments for 'keys' command
127.0.0.1:6379> keys *
1) "key:__rand_int__"
2) "mylist"
3) "age"
4) "counter:__rand_int__"
5) "myhash"
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> set name daleilei
OK
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> set age 1
OK
127.0.0.1:6379> EXPIRE name 10
(integer) 1
127.0.0.1:6379> ttl
(error) ERR wrong number of arguments for 'ttl' command
127.0.0.1:6379> ttl name
(integer) 2
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379>
String
字符串类型
append :往后加字
strlen:字符串长度
incr :增加
decr:减
incrby :根据步长增加
decrby:根据步长减少
字符串范围:getrange
替换:setrange
setex(set with expire) :设置过期时间
setnx (set if not exist): 不存在在设置
#######################################################
mset k1 v1 k2 v3 k3 v3:批量设置
mget k1 k2 k3 批量得到这个值
msetnx k1 v1 k4 v4:设置是否存在
getset #先get后set
List
基本的数据类型,列表
在redis中,我们可以把list玩成栈,队列、阻塞队列
所有list命令都是l开头
Rpush
删除:lpop、rpop
根据下标获得值:lindex
返回列表的长度:llen
移除指定的值!:lrem
截取:ltrim
rpoplpush:移除列表的最后一个元素,
lset :修改某列表几号位的值(相当于更新操作)
linsert
list小结:
实际上是一个链表,before Node after,left,right都可以插入值
如果key不存在,创建新的链表
如果key存在,新增内容
如果移除了所有的值,空链表,也代表不存在!
在两边插入或者改动值,效率最高!中间元素,相对来说,效率会低一点
消息排列!消息队列 Lpush Rpop
Set
(集合)
set中的值是不能重复的!
sadd:在set集合中添加值
smmembers:显示所有set值
sismember:判断是否有这个值,1表示有 0表示没有
scard :获取set集合中内容的元素个数、
srem:移除set中元素
set 无序不重复集合,抽随机
srandmember:随机抽取显示一个数
spop:随机移除元素
smove:将一个指定的值,移动到另外的一个的set中
sdiff :两个集合不同的值
sinter:两个集合交集
sunion:并集
Hash(哈希)
Map集合,key-Map集合 ,key-<key,value>,本质和string类型吗,欸有太大的区别,还是一个简单的集合
hset:存值
hget:取值
hmset:设置多值
hgetall :获取所有的值
hdel:删除hash指定的key字段,对应的value也就消失了
hlen:获得集合的有几个键值对
hexists:判断指定字段是否存在
hkeys:只获取key字段
hvalues:只获得value字段
hincr:增加一个值
hincrby:给一个加多少值
hsetnx:如果不存在就创建,存在就失败
Zset(有序集合)
在set上增加了一个值,set k1 v1,而zset k1 score1 v1
相当于score1就是一个排序
zadd:增加
zrem:移除
zrange:显示所有的(范围)
zcard :查看有多少元素
zrevrange:排序,从大到小
zcount:某个区间之内有多少元素
排序实现:zrangebyscore
-inf ,+inf :负无穷和正无穷
三种特殊数据类型
Geospatial (地理位置)
朋友的定位,附近的人,打车距离计算
相关命令
GEOADD
GEODIST
GEOHASH
GEOPOS
GEORADIUS
GEORADIUSBYMEMBER
添加规则:两级无法直接添加,我们一般会下载城市数据
获得数据
getpos
geodist:两个位置之间距离
单位:
m:米
km:千米
mi:英里
ft:英尺
georadius以给定的经纬度为中心,找出某一半径内的元素
georadiusbymember :根据什么为中心距离多远城市
geohash:命令:把二维的经纬度转换为一维的字符串
GEO底层的实现就是zset,所有可以使用zset的命令进行增删改
Hyperloglog()
什么是基数?
A{1,3,5,6,7,8,9}
简介:
redis2.8.9版本就更新了Hyperloglog数据结构
用于:网页的UV(一个人访问一个网站多次,但是还是算作一个人)
如果允许容错,那么可以使用hyperloglog
不允许的,就可以使用set或者自己的数据类型即可
Bitmaps
位存储
0 1 0 1
bitmaps位图,数据结构!都是操作二进制位来进行记录,只有0和1两个状态
Redis事务
Redis事务本质:一组命令的集合!一个事务的所有命令都会被序列化,在事务执行会按照顺序执行
一次性、顺序性、排他性!执行一些列的命令
Redis事务没有隔离级别的概念‘
所有的命令在事务中,并没有直接被执行!只有发起执行命令的时候才会执行
Redis单条命令是保证原子性,但是Redis事务不保证原子性
Redis的事务:
开启事务()multi
命令入队()…
执行事务()exec
放弃事务 discard
正常执行事务
编译型异常(代码有问题!命令有错!)事务中所有的命令都不会被执行!
运行时异常(1/0),如果事务队列中存在语法性,那么执行命令的时候,其他命令是可以执行的,错误命令抛出异常
监控 !watch
悲观锁:
很悲观,认为什么时候都会出问腿,无论做什么都会加锁!
乐观锁:
很乐观,认为什么时候都不会出问题,所以不会上锁!更新数据的时候去判断一下在此期间是否有人改动数据
获得version
更新的时候比较version
Redis测监视测试
测试多线程修改值,使用watch可以当作redis的乐观锁操作
如果修改失败,获取最新的值就好
Jedis
我们要使用java来操作redis
jedis是Redis官方推荐的java连接开发工具!使用java操作Redis
1.导入依赖
<dependencies>
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.3.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
</dependencies>
2.编码测试:
连接数据库
操作命令
常用的api
string
list
set
hash
zset
断开连接
Springboot整合redis
sprongboot操作数据:spring-data jpa jdbc mongodb redis
springdata也是springboot齐名
说明:在springboot2.x之后,原来使用的jedis被替换为了lettuce
jedis:采用直连,多个线程操作的话,是不安全的,如果想要避免不安全,就要用jedis pool连接池 BIO
lettuce:采用netty,实例可以在多个线程中进行共享,不存在线程不安全的情况。可以减少线程数据,更像NIO模式
Redis.conf详解
启动的时候,通过配置文件来启动!
1.配置文件unit单位 对大小不敏感
2.包含
相当于学习spring的时候,import其他文件
3。网络
绑定ip
是否受保护
修改端口
4.通用配置
damonize yes #以守护进程的方式进行,默认是no,我们需要自己开启
如果以后台的方式运行,我们就需要指定一个pid文件
日志级别
debug:用于测试开发阶段
verbose:记录较多的日志信息
notice:默认,生产环境适用
warning:关键的信息打印
日志文件位置名
默认数据库数量:16
always-show-logo yes是否显示logo
快照
持久化,在规定的时间内,执行了多少次操作,则会持久化到文件.rdb .aof
redis是内存数据库,没有持久化,那么数据断电即失
#900s内,至少一个key进行修改,我们就进行持久化操作
save 900 1
#300s内,至少10个key进行修改,我们就进行持久化操作
save 300 10
#60s内,至少10000个key进行修改,我们就进行持久化操作
save 60 10000
stop-writes-on-bgsave-error yes # 持久化如果出错,是否还需要继续工作
rdcompression yes #是否压缩rdb文件,需要消耗一些cpu资源!
rdbchecksum yes#保存rdb文件的时候,进行错误的检测校验
dir ./ #rdb文件保存的目录
SECURITY安全
设置密码
或者命令设置密码
限制CLIENTS
默认限制一万
maxclients 10000#设置连接上redis的最大客户端的数量
maxmemory #redis配置最大的内存容量
maxmemory-policy noeviction #内存到达上限之后的处理策略
1:vlatile-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 “appendonlu.aof”#持久化的文件的名字
#appendfsync always
appendfsync everysec #每秒执行一次
#appendfsync no
RedisRDB
Redis是内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一旦服务进程退出,服务器中的数据库状态也会消失。所以Redis提供了持久化功能
在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时将快照文件直接读到内存里‘
Redis会单独创建(Fork)一个子进程来进行持久化,会先将数据写入一个临时文件中,待持久化过程结束了,再用这个临时文件替换上次持久化的文件。整个过程中,主进程是不进行任何IO操作。这就确保了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB缺点就是最后一次持久化后的数据可能丢失。
rdb保存的文件是dump.rdb,都是我们的配置文件中快照中进行配置的!
触发机制
1.save的规则满足的情况下,会自动触发rdb规则
2.执行flushall命令
3.退出redis,也会产生rdb文件
备份就自动生产一个dumo.rdb文件
如何恢复rdb文件
1.只需要加rdb文件放入redis的启动目录下就可以,redis启动 会自动检查dump…rdb恢复数据
存储的文志
- “dir”
- “/usr/local/bin”#如果在这个目录下,启动就会自动恢复其中的数据
优点:
1.适合大规模数据恢复!dump.rdb
2、对数据完整性不高!
缺点:
1.需要一定的时间间隔进行操作,如果redis意外宕机了,这个最后一次修改数据就没有了
2.fork进程的时候,会占用一定的内存空间
AOF(Append Only File)
将我们所有的命令记录下来,history,恢复的时候就把这个文件全部执行一遍
以日志的形式来记录每个写操作,将Redis执行过的所有指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作
AOf保存的文件是appendonly.aof文件
默认不开启,这是修改的yes
重启之后就生效了
如果adf文件有错误,这时候redis启动不起来的,我们需要修复aof配置文件
redis给我们提供了redi-check-aod --fix appendonly.aof
优点:
1.每一次修改都同步,文件的完整会更加好
2.每秒同步一次,可能会丢失一秒的数据
3,从不同不,效率最高的
缺点:
1.相对与数据来说,aof远远大于rdb,修复速度也比rdb慢
2.aof运行效率比rdb慢,所以我们redis默认的配置就是rdb持久化
Redis发布订阅
Redis发布订阅是一种消息通信模式:发送者pub发送消息,订阅者sub接受消息
Redis客户端可以订阅任意数量的频道
测试:
主从复制
只配置从库,不用配置主库!
info replication 查看当前库的信息
复制几个redis.config
修改:
1.端口号
2.日志名字logfilename
3.daemonize 写成yes
4.pidfile name 该成相应
5.dump.rdb
一主二从
默认情况下,每台redis服务器都是主节点
当前主机状态
认主机,这个为从机
如果是使用命令行配置主从,这个时候如果重启了,就会变成主机
谋朝篡位
意思,如果采用层层链接模式,如果主机断开了连接,我们可以使用slaveof no one让自己变成主机
哨兵模式
(自动选举老大的模式)
主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器。这就需要人工干预,费时费力,还会造成一段时间内服务不可用。这不是一种推荐的方式,更多的时候,我们优先考虑哨兵模式。redis从2.8开始Sentinel架构
哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,它会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例
这里的哨兵有两个作用
1.通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器
2.当哨兵检测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机
然而一个哨兵进程对Redis服务器进行监控,可能会出现问题,为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式
测试:
进入lconfig,新建一个sentinel.config配置
配置内容:
2.启动哨兵!
redis-sentinel
如果Master节点断开了,这个时候就会从从机中随机选择一个服务器
优点:
1.哨兵集群,基于主从复制,所有的主从配置优点,他全由
2.主从可以切换,故障可以转移,系统可用性就会更好
3.哨兵模式就是我们的主从模式的升级,手动到自动,更加健壮!
缺点:
1.Redis不好在线扩容,集群容量一旦到达上线,在线扩容就十分麻烦
2.实现哨兵的模式配置很麻烦,里面有很多选择!
Redis缓存穿透和雪崩(查不到)
Redis缓存的使用,极大的提升了应用程序的性能和效率,特别是数据查询方面。但同时,他也带来了一些问题。其中,最要害的问题,就是数据的一致性问题,从严格意思上讲,这个问题无解。如果对数据的一致性要求很高,那么就不能使用缓存
缓存穿透
概念:缓存穿透的概念很简单,用户想要查询一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是想持久层数据库查询。发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中,于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。
解决方案:
布隆过滤器
布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力
缓存空对象
当存储层不命中后,即时返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端你数据源;
但是这种方法会存在两个问题:
1.如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中欧冠可能会有很多的空值的键
2.即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致的业务有一定影响
缓存击穿(量太大,缓存过期!)
概述
缓存击穿是指一个key非常热点,在不停的扛着大并发,大并发集中对这个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞
解决方案:
设置热点 数据永不过期
从缓存层面来看,没有设置过期时间,所有不会出现热点eky过期后产生的问题。
加互斥锁
分布式锁:使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可。这种方式将高并发的压力转移到了发布时锁,因此对分布式锁的考验很大
缓存雪崩
概念:
指在某一个时间段,缓存集中过期失效。Redis宕机
产生雪崩的原因之一,比如在写本文的时候,马上要到双十二零点,很快就会迎来了一波抢购,假设缓存一个小时,那么到了领导一点的时候,这批商品的缓存就都过期了,而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。于是所有的请求都会达到村层层,存储层的调用量会暴增,造成存储层也会挂掉的情况
解决方案
Redis高可用
多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就i是搭建的集群
限流降级
这个解决方案的思想是,在缓存失效后,通过枷锁或者队列来控制读数据库写缓存的线程数量。比如对某key只允许一个线程查询数据和写缓存,其他线程等待
数据预热
数据加热的含义就是在正式部署之前,我先可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问钱手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀