redis从0-1学习记录(完结)
1、
NoSQL(not only sql):不仅仅是数据库,非关系型数据库,关系型数据库是以表格的行列进行存储的,而非关系型数据库是以键值对进行存储,不需要固定的格式。非关系型数据库的特点,方便扩展、大数据量、高性能、细粒度缓存、数据类型多样化(也不需要设计数据库表)。有redis(远程字典服务)、mongoDB等
2、
redis:是一种基于内存的存储的数据库,具有持久化、高效率、高速缓存、发布订阅系统、地图信息分析等优点和功能。redis是一种单线程基于内存的数据库,基于内存所以运行速度很快,为什么单线程运行速度还那么快呢?因为redis将所有数据都放在内存中,所以使用单线程操作效率是最高的,而且多线程操作cpu会进行上下文切换,也会消耗时间,所以对于内存来说没有上下文切换时最快的。redis可以做数据库,可以做缓存,可以做消息中间件(MQ)等。redis一共有16个数据库(0-15)
安装:Windows的安装,下载压缩包,解压安装。Linux的安装,下载压缩包,解包,进入带有redis.conf的包里面,运行make命令进行编译,默认安装路径usr/local/bin(安装时使用profile --fix 后面跟路径 可以改变安装的路径),在使用make install命令进行安装即可。安装完毕进入到有redis-server的目录里面运行redis-server启动redis服务器,使用redis-cli命令连接服务器即可。
3、
redis一共有八种数据类型用于存储数据:string、list、hash、set、zset、geospatial(处理地理位置)、typerloglolg(统计数量与去重),bitmap(位存储,只有0和1两种状态)
通用的命令(redis的命令是不区分大小写的):
select 数据库号(0-15):用于更换数据库
DBsize :查看数据库的大小
keys * :查看所有的key
flushdb :清空当前数据库
flushALL :清空所有数据库(危险性大 一般不用 最好不用 就是不要用就行)
exists key :判断key是否存在
move key :移除key
expire key 时间(秒) :给一个key设置过期时间
ttl key :查看key剩余的过期时间
4、——————————————————————————————————————————
string(字符串数据类型):一个key一个value,value是一个字符串。
set key value // 存入一个数据
get key // 获取一个数据
mset k1 v1 k2 v2....... //一次存入多个数据
mget k1 k2 ........// 批量获取多个数据
setnx key value // 当key不存在的时候存入,当key存在时不存入
msetnx k1 v1 k2 v2.....// 多个存入不存在的key
setrange key 开始下标 value // 从开始下标开始一次将值修改为value,数据库中的值改变
getrange key 开始下标 结束下表 // 获取从开始到结束下标的值,数据库中的值不改变
setex key 时间 value // 存入数据时同时设置key的过期时间
incr key // 如果key的value为数字,则自增1 ,不为数字,报错
decr key // 如果key的value为数字,则自减1 ,不为数字,报错
incrby key n // 如果key的value为数字,则自增 n ,不为数字,报错
decrby key n // 如果key的value为数字,则自减 n ,不为数字,报错
append key value // 往key中追加字符串,如不存在,则新建key
strlen key // 查看字符串的长度
getset key value // 返回key的值之后将key的值更新为value,若没有key ,返回NULL,在设置key
5、
List (列表),key为列表名 value为一个列表。List可以当作栈获取队列来使用(Lpush ,Lpop ,Rpush ,Rpop)
Lpush key value // 将value插入到列表的左边
Rpush key value // 将value插入到列表的右边
Lrange key 开始下标 结束下标 // 列表的区间取值 (0 -1)返回整个列表
Lpop key // 移除列表左边第一个元素
Rpop key // 移除右边第一个元素
Lindex key 下标 // 获取下标位置的值
Llen key // 获取列表长度
Lrem key n value // 移除列表中n个值为value的元素
Ltrim key 开始 结束 // 截取区间长度,数据库中只剩下截取的元素
Lset key 下标 value // 将列表中下标位置的值改为value,该下标必须存在,不存在无法使用
Linsert key before /after value1 value2 // 将value2插在value1的前/后面
6、
Hash:key ——value,而value里面又是一个kye ——value:key (k1 value),就相当于有一个表,表名叫key ,表中存了又存了很多k-v数据。
Hset key k1 v1 // 添加一个元素在key里
Hget key k1 // 获取k1 的value
Hmset key k1 v1 k2 v2 .... // 一次添加多个值
Hmget key k1 k2 ....// 一次获取多个值
Hkeys key //获取key里面所有的k
Hvals key // 获取key里面所有的value
Hdel key k //删除key中指定的k
Hlen key // 获取key的长度(hash表的长度),就是返回k的个数
Hexists key k // 判断k是否在key中
7、
set 集合 :集合里面的值为无序不重合。
Sadd key v1 v2 ......// 往集合key中添加值
Smembers key // 获取集合中的所有值
Sismembers key v // 判断值v是否存在与集合key中
Scard key //返回集合中的值个数
Srem key v //移除集合key中值v
Srandmember key //随机获取集合key中的一个值
Spop key // 随机删除一个集合key中的值
Smove key1 key2 value //将集合1中的value移动到集合2中
Sdiff key1 key2 // 求差集,以集合1为参照 ,返回集合1中集合2中没有的值,也就是返回集合1减去他两的交集
Sinter key1 key2 // 返回他俩的交集
Sunion key1 key2 // 返回她两的并集
8、
zset:有序集合。k-v(v里面有score和member),排序就是按照score来的
Zadd key score member //往有序集合里添加一个值,可同时添加多个值
Zrevrange key 0 -1 //将值从大到小进行排序
Zrangebyscore key -inf +inf // 将值从小到大排序,负无穷到正无穷
Zrem key member // 移除一个叫member值
Zcard key // 获取key里面v的数量
Zcount key 开始 结束 // 获取区间内的成员数量
9、
geospatial :地理位置的数据类型,可以推算地理位置信息,两地的距离,用于位置共享地图等。k-v(v里面是一个经度纬度和member)
geoadd key 经度 纬度 member // 添加一个值,可同时添加多个。如:geoad China:city 经度 纬度 beijing //将北京的经纬度添加到key为China:city中
geopos key member // 获取member的经纬度
geodist key member1 member2 //返回两地之间的直线距离(member1与member2之间)。
georadius key 经度 纬度 n(千米) // 以该经纬度为中心,返回n千米为半径以内的位置
10、
typerloglog : 统计数量与去重,有一定的重复率(0.81),用于对重复率要求不高的需求。有点像集合,但是集合运行慢(但是没有误差)。typerloglog运行很快,可以快速统计数量和去重。
PFadd key value // 添加一个值
PFcount key // 统计key中value的数量
PFmerge key key1 key2 // 将key1 和key2 合并到key里面去,而且没有重复元素。
11、
bitmap:位存储,只有0和1两个状态。比如打卡机,打卡与未打卡两种状态。
setbit key 偏移量 value(0/1) // 表示将偏移量这个位置的值设为0/1。偏移量一个二进制位表示一个偏移量,从左到右。比如一个月打卡情况:一个月三十天 ,偏移量就是0-29,默认值都是0,打卡一天就将该偏移量设为1。
getbit key 偏移量 // 获取该位置的值
bitcount key // 获取该key中所有value为1的数量。
————————————————————————————————-----—————————
12、
事务:在关系型数据库中有事务,事务指要么同时成功,要么同时失败且具有原子性。但是在redis里面,只有单个的命令是保证原子性的,而在redis的事务中是不保证原子性的。在redis事务中也没有隔离级别的概念,redis命令只有在发起执行命令时才回去执行。
事务的本质:就是一组命令的集合,命令会按照顺序依次执行。
redis事务流程:
(1)multi // 开启事务。
(2)redis的各种命令(开启事务后这里输入的命令会依次入队,先入队先执行,此时还没有执行)
(3)exec // 执行事务(这时才去依次执行队中的命令)
当我们(3)还没有执行,运行 discard 命令,放弃事务(放弃队列中的命令)。
redis事务流程结束。
redis事务的异常:异常分为两种:
命令错误(语法错误):当我们在命令入队时,命令写错,单词写错等,在入队的时候就会报错,并且所有的命令都不会去执行。
逻辑错误:语法没有错误,但是逻辑上有错误,比如对字符串进行+1操作等,在入队的时候是不会报错的,在执行的时候该条语句会抛出异常,而其他的语句会正常的执行。
13、
悲观锁:很悲观,做什么操作都要加锁,所有影响性能。
乐观锁:很乐观,任何时候都不加锁,但是在更新数据的时候,他会去比对一下现在的值与需要更新的时候的值是否一样,如果一样表示没有被修改过,那就就允许更新;如果现在的值与需要更新的时候的值不一样,那么就表示这个值被修改过,此时就不允许更新数据。redis中就有这样的乐观锁(watch)。使用场景:秒杀场景。
watch key // 监视key ,就相当于给这个key加上了一个监控,在监控期内,我还没有提交事务,但是该key已经被其他事务修改了值,这时当我再去提交事务,watch就会去比对监视之前与现在的值,如果值一样就表示没有被修改,那么可以提交事务;如果不一致就不能提交事务。
unwatch key // 取消对key的监视,当事务提交失败时执行该命令,然后在进行重新监视操作即可。
14、
redis的持久化骚操作:因为redis是在内存里面存储数据的,所以一旦断电,就会造成数据丢失。为了不让数据丢失,所以就需要将数据持久化到磁盘中。就是在满足一定的条件或者在一定的时间里就将内存中的数据持久化到磁盘中。redis有两种持久化数据的方式,一种rdb ,一种是aof。
rdb(redis database):将数据保存到dump.rdb文件中,每次redis开启时都会去读取这个文件里面的数据到内存中。大规模的数据恢复较快。可以在redis.conf中配置rdb,比如达到什么条件时就往磁盘里持久化数据。
rdb的缺点:需要一定时时间间隔才持久化一次,如何在该时间间隔内宕机了,那么就会丢失该时间间隔内的数据。还需要一个子进程来操作持久化,所以会额外的占用一点内存空间。
aof(append only file):就是将我们每次的执行命令记录下来,他是以日志的形式来记录每一个写操作(不记录读操作),只是追加写文件不能修改文件。当redis每次开机的时候就去读取appendonly.aof文件,然后重新读取里面的操作命令进行重构数据(就是将appendonly.aof里面的命令从前到后的执行一遍),完成数据的恢复从而达到数据的持久化目的。
当我们的appendonly.aof文件被破坏时,可以用redis-chech-aof --fix appendonly.aof 对其进行修复。
aof优点:每一次的修改都是同步到磁盘的,所以数据的完整性较好。
aof缺点:aof的文件比rdb大,所以开机时恢复数据较慢。运行效率也比较慢。
无论是rdb还是aof的持久化,在他们持久化的时候都都需要一个额外的子进程来做持久化操作,所以都需要消耗一定额外的内存空间。
15、
redis发布订阅操作:
是一种消息通信的模式,有发送者pub,接收者sub,订阅者可以订阅任意的发布者,发布者与订阅者时通过频道来通信的,频道就是redis服务器。也就是发布者将消息发布到频道上(redis-server),redis-server再将消息发给每一个订阅者。发布者---->redis-server------>接收者1,接收者2......。
subscribe 频道名1 ,频道名2...... // 订阅一个或多个频道,特别提醒:先订阅频道,在创建频道后才能接收消息,如果先创建频道,在订阅,那么无法接收创建时发出来的消息。
publish 频道名 要发生的消息 // 当订阅者订阅后,创建频道并将消息发送出去。
其实redis发布订阅其实就是一个MQ(消息中间件)的缩小版实现,redis发布订阅系统的底层就是一个字典加一些链表,一个字典里面有很多k-v对,每一个k-v对都存着一个发布者,而v又是指向一个链表的,而该链表又是订阅者,当有一个订阅者订阅时,就往链表里面加一个结点。当发布者发布消息时,redis就将消息发给所有结点即可。
16、
redis的主从复制:将一台redis-server的数据同步到其他的redis-server上,这一台服务器就叫主服务器(master),而其他的服务器就叫从服务器(slave),当建立主从关系之后,主服务器就负责写数据操作。而从服务器就负责读数据操作。每一次主服务器写如的数据都会同步到从服务器中,这就是主从复制,从而就实现了读写分离。将低了redis服务器的压力。
优点:故障恢复,当主服务器宕机时,还可以由其他的结点提供服务。负载均衡,读写分离分担了服务器的压力,从而提高了服务器的并大量。高可用,主从复制是哨兵和集群的基础,也是体现redis高可用的基础。
默认情况下每个redis-server都是一个master结点,一个master可有有多个从结点(或者没有从节点),而一个从结点只能有一个主节点。
配置主从结点:只配置从结点,主结点不用配置
info replication // 查看当前结点的主从信息,包括主结点有多少个从节点,从节点属于那个主节点等信息。
从机配置文件的配置:此时需要开启多个redis-server服务,那么需要多个redis的配置文件,我们将原配置文件cp一个并更改一下文件名来给从机使用,更改cp来的配置文件,需要更改端口号,logfile,dunp.rdb,pidfile等信息。每开启一个从机,都需要cp一个redis.conf文件来供从机使用。此时配置就好了,然后就可以开启每一个从机:redis-server /cp出来的redis.conf文件/ 表示用这个redis.conf配置文件开启该从机。
配置从机:就是让从机认主机(相当于认老大一样)。在从机上使用命令(成为从结点命令):slaveof 主机的ip地址 主机的端口号 //(取消从节点命令)slaveof no one 。此时这个从机就认该主机的为主节点了,该主节点就有了一个从机节点了。这是使用命令配置主从,从结点没断掉一个,那么我们就要重新配置(重新敲这个命令)。接下来使用配置文件配置(通过从机的redis.conf文件配置):这样配置的从机以后只要上线就会自动变成某主机的从机,从机的配置文件里面的replication下的replicaof 主机的ip 主机的端口号 ,如果主机还有密码等也需要在从机上进行配置。这就是主从的两种配置,
当我们配置好主从之后,我们的主机就只能写操作,当外界需要数据时就只能从从机上获取数据了,当然主机每次写入的数据都会自动同步到从机上的。
当我们的主机宕机了,我们的从结点依旧还是从节点,当主节点重新上线后,会自动与从节点连接的,连接完后即可恢复数据同步了;当从机断了一个,那么主机会显示从机掉了一个,如果我们使用的时文件配置的从机,当我们的从机在一次上线的时候就会自动连接主机,主机就会把数据全部同步到从机上。
主从复制的原理:有两个,一个是全盘复制:当slave第一次连接或者掉线重连时,slave水发送一个sync的同步命令给主机,主机收到后就会启动后台的存盘进程,同时接收全部用于修改数据的命令,执行后master就将整个数据文件发送给slave,从而完整一个完整的同步。还有一个就是增量复制:slave一直处于连接状态,每当master有写操作的时候,那么master就会将修改数据的命令发送给slave,从而完成同步。主机宕机我们就需要手动的再次配置主节点。
17、
主从复制的哨兵模式:上面就是主从复制手动版,主机宕机后需要在一次手动配置主机才能继续工作。使用哨兵就可以自动配置主机了,当我们主机掉线后,我们的哨兵就会在从机里面随机选一个结点来作为主机继续工作。哨兵其实就是一个进程,一个哨兵时,容错率较高,因为哨兵也可能会掉线,所以一般用的时多哨兵模式,每一个哨兵都会去监视所有的结点,并且每个哨兵之间也会相互监视。主机掉线后,哨兵们会进行投票在选一个主节点来继续工作,如果当原来的主主节点回来后就不再时主节点了,只能当从节点了。
开启哨兵的进程:redis-sentinel (运行他就可开启了一个哨兵了)。
18、
多哨兵模式的配置:
每个哨兵最基本的配置:有一个sentinel.conf 的文件,这个文件就是用来配置哨兵的,每一个哨兵都要有一个这样的配置文件,文件里面最基本的也是最重要的配置:新建一个名叫sentinel.conf文件,在里面写上:sentinel monitor 给哨兵起的一个名字 master的IP master的端口号 1 #表示该哨兵去监视该IP下的这个端口的主机以及跟他连接的所有从机。后面的1表示主机宕机然后进行投票用的。当我们有多个哨兵的时候。这个时候我们就需要给每一个哨兵配置一个端口号,防止端口号冲突。sentinel.conf /哨兵的配置文件的路径/ 启动该哨兵。
哨兵集群的优点:主从可切换,故障可转移,系统的可用性更好。主从复制的高级版,从手动到自动,使系统更加的健壮。
哨兵集群的缺点:在线扩容难,集群一旦达到上限,扩容就十分的麻烦,哨兵模式的配置比较麻烦(繁琐)。
19、
redis缓存的穿透、击穿和雪崩:
穿透:用户去访问缓存和数据库库中没有的数据,当短时间内有大量的用户访问该数据(高并发)的时候,后端的数据库没有扛下来,就会造成缓存穿透。也就是大量的请求数据库中没有的数据,而数据库又不停的去查找,最后导致数据库崩盘。
解决穿透问题:(1)使用布隆过滤器(一个数据结构),在缓存层加入一个布隆过滤器,对所有可能查询的参数以Hash的形式存储,当有用户访问数据时,先进性校验,不符合校验的直接丢弃。这样就避免了对底层的存储系统的查询压力。(有点像防火墙一样)。(2)用户第一次查询没有结果,则数据库返回一个NULL,而缓存层将这个NULL也进行缓存,当还有用户进行查询的时候,缓存层直接就返回NULL值,就不用再重复去存储层查询了,从而降低了查询的次数,这样也可以减少查询的压力。但是这样有两个弊端,一个是NULL值过多会占用内存,从而影响缓存的性能;二是如果当一个缓存在缓存层里面的NULL值还没有过期时,这时我们往数据库中存储了该值,那么当我们用户再去访问该值的时候,缓存里面依然还会返回NULL,这样就会导致一致性、实时性很差的问题(分布式、集群的硬伤)(对一致性要求高的业务逻辑就无法使用该方法)。
击穿:击穿与穿透不一样,穿透讲的是高并发访问缓存与数据库中没有的数据;而击穿是高并发访问数据库中存在的数据。比如当缓存里面的一个数据过期了,但是这时又有高并发产生,而缓存区数据库里面区数据的时候有一定的时间,加入需要0.1秒,但是这0.1秒的时间内有很高的高并发,缓存中又没有数据,所以用户 只能区数据库中查询了,大量的用户去数据库中查询就会导致数据库扛不住压力,从而崩盘。
解决击穿问题:(1)将访问量大的时间段内的 k-v 的过期时间设置长一点或者不要设置过期时间,但是这样就会造成占用内存空间的问题。(2)加互斥锁,就是使用分布式锁,同一时间访问同一个数据只能有一个线程(用户)去访问数据库(查询数据),因为上锁了所以其余的线程就不允许进行数据库中,在外面等待即可,等第一个线程将数据查询出来,将数据放到redis的缓存中后,其余的线程再去redis中拿数据即可,这种方法对分布式锁的要求较高。
雪崩:雪崩就是缓存中的数据集中过期或者大量过期、断电、断网等情况。
解决雪崩问题:(1)合理设置缓存中数据的过期时间。(2)redis缓存可能宕机,那么我们就可以多放几台缓存服务器,其中一台宕机,其他的还可以接着工作。(3)限流降级,就是限制部分次要的功能,从而保证主要的功能正常运行。(3)数据预热,在某一时间段内,把可能会产生高并发的数据访问一遍,使他放在缓存中(手动设置合理的过期时间)。
—————————————redis完活—————————————————————