redis入门终极简略版
Nosql概念
Nosql :Not Only sql
表示并不只是sql,是一种非关系型数据库,通常同Key-value的方式存储
比如很多地理位置信息,它并不适合用Mysql来存储
Nosql特点
- 方便扩展
- 大数据量,高性能:1s写八万次,读十一万次
- 数据类型多样
- 不需要设计数据库
大数据时代的3V+3高:
数据海量、多样、快速
服务高并发、高性能、高可扩
其他的数据库类型
文档型数据库:MangoDB
图片型(对象型文件系统):FastDFS,OSS
Nosql四大分类
redis
概念
redis是一种远程字典服务,用c语言编写,使用k-v存储
linux下安装
在官网下载压缩包,使用tar命令解压在/opt文件下,然后安装c/c++环境:yum install gcc-c++,成功后使用make命令等待完成后再使用make install命令即可。
redis默认安装文件路径是 /usr/local/bin
由于redis启动默认不是后台启动,我们需要修改配置文件:在redis.conf文件中daemonize配置为yes
最后启动服务可以指定配置文件启动:redis-server addr-config
查看进程是否启动 ps -ef | grep redis
关闭服务:在redis命令行中使用 shutdown
基础知识
redis默认有16个数据库,使用第0个数据库
一些命令
- 使用select切换数据库:
select [number]
- 查看数据库大小:
DBSIZE
- 查看库内容:
keys *
- redis是单线程的,因为CPU不是它的性能瓶颈,而内存和网络带宽才是,所以单线程也能实现高性能
- 判断某个值存在:
exists key
- 存储数据:
set key value
- 数据限时:
expire key number\setex key number value
限时多少秒后数据失效,ttl key
查询还有多久截止 - 查看key类型:
type key
- 删除数据库:
flushall or flushdb DbName
- 批量插入、获取:
mset k1 v1 k2 v2...\mget k1 k2 k3...
msetnx当批量插入的时候其中有存在的就失败,原子性的操作
五大基本类型
-
String:
- 拼接key的value和value,并返回新value的长度:
append keyName value
- 获取字符串长度:
strlen key
- 对数字内容String自增、自减:
incr key
,decr key
- 任意步长自增:
incrby key number
- 截取子串:
getrange key start end
(截取后包括start end所在的值,end为-1则获取所有项,java则不会包含end) - 替换子串:
setrange key offset value
(从offset开始将value替换后面的内容) - 如果存在则:
setnx key value
- 插入一个json字符串:
set user:1 {name:JayChou,id:1}
- 拼接key的value和value,并返回新value的长度:
-
List:所有的List命令都是l开头
- 插入:
lpush listName value(头插法)\rpush listName value(尾插法)}
- 获取:
lrange listName start end
,lindex listName index
- 移除:
lpop\rpop:头删\尾删
,lrem listName number vlue:移除特定集合的特定值的number个
- 长度:
llen listName
- 集合子集:
ltrim listName start end
- 移动元素到新集合:
rpoplpush oldlist newlist:尾删头插
- 替换:
lset listName index newValue,将list中index位置的值替换为newValue
- 插入:
linsert list after|before value1 value2在value1前|后插入value2
- 插入:
-
Set:无序集合
- 添加:
sadd key value
- 查看所有:
smembers setName
- 访问大小:
scard setName
- 移除:
srem setName keys
- 随机抽取元素:
srandmember setName [number]:随机抽取number个元素
- 随机移除:
spop setName
- 移动元素:
smove setName newSet member
- 差、并、交集:
sdiff\sinter\sunion set1 set2
- 添加:
-
hash
- hashset
- 添加:
hset\hsetnx\hmset name field value
- 获取:
hget\hmget\hgetall\hkeys\hvals
- 删除:
hdel set field
- 计算长度:
hlen set
- 自增任意数:
hincrby set field number
- 添加:
- hashset
-
Zset:有序集合,按照score排序
- 添加:
zadd key scores values
- 查看:
zrange key start end
,zrangebyscore set min max [withscores] [limit offset count:offset表示元素下标,count表示展示多少]
,zrevrange key start end
和zrange是反序的 - 移除:
zrem zset value
- 访问大小:
zcard zset
,zcount zset min max:指定范围内元素个数
- 添加:
特殊数据类型
-
Geo:地理位置,用Zset实现的,所以Zset的命令也能对Geo生效
- 添加:
geoadd key latitude pair value:latitude pair纬度对
- 有效的经度从-180度到180度。 有效的纬度从-85.05112878度到85.05112878度
- 获取元素:
geopos key value:返回latitude pair
- 计算两个元素的距离:
geodist key value1 value2
,返回单位千米 - 筛选元素:
GEORADIUS key longitude latitude radius m|km|ft|mi [WITHcooRD][WITHDIST] [WITHHASH][count [ANY]][ASC|DESC]
,在圆心为latitude pair半径为radius内的所有元素value,count限制数量georadiusbymember key ....
,将某个元素作为中心,半径为radius - 元素hash:
geohash key value:返回11位hash值
- 添加:
-
hyperloglog:基数统计(集合的基数),可用于网站访问量统计
- 添加:
pfadd key values
- 访问大小:
pfcount key
- 集合合并:
pfmege key3 key1 key2
,将两个集合合并在key3里,没有重复元素
- 添加:
-
BitMaps:位存储,如打卡记录就能用它存储
- 插入:
setbit key index value
- 查询:
getbit key index
- 插入:
事务
redis命令保证了原子性,但是事务不保证原子性,因为redis的事务是一组命令的集合,单个命令有原子性,一组命令没有原子性。redis事务没有隔离级别概念,当发起执行的时候才会执行命令
基本
事务操作分为三步:
- 开启事务
- multi命令开启事务
- 放入命令
- 执行事务
- exec执行事务
- 取消事务:
- discard
执事务中可能出现的异常:
-
编译型异常
- 命令符合格式,但是语法错误,导致事务中的命令都不会执行
- 如:
zadd set f ff
-
运行时异常
- 只会影响该条命令,对其他不影响
乐观锁
watch key
:对key加上乐观锁unwatch
:放弃监视
当加上乐观锁后,另一个线程对这个key进行修改,会造成监控key的线程的操作失败。
并且失效的场景只会在事务中执行对key的操作命令生效,发生失败后,watch功能失效。
也就是说watch撤销的情况只有两种:
- 一是
unwatch
主动撤销 - 二是在事务中引发了版本修改
持久化
持久化主要有两种方式:
- RDB:Redis DataDase
- 默认的保存文件格式是dump.rdb,保存数据需要配置持久化策略
- 在配置文件中会有指定保存方式,指定间隔时间,当进行文件持久化的时候,需要将文件快照写入磁盘,
Redis会单独创建一个子进程,将数据写入临时文件中,持久化完成后,将这个文件替换上次持久化的临时文件,
主进程不会进行io。
save 100 10:如果100s内有10条数据更改,就会发生一次快照保存。
恢复快照的时候,只需要将rdb文件位置放在配置文件中就行。 - 优点是适合大规模数据恢复
- 缺点是最后一次持久化可能会数据丢失。 fork需要占用一定内存空间。
- AOF:Append Only File
- 开启AOF:在配置文件中更改为
appendly yes
- 如果AOF文损坏之后,就不能启动redis-server,因为内存加载数据的时候会发现文件不可使用。 redis提供了一个工具:redis-check-aof,可以修复aof文件
- 以日志的形式将每个写操作记录下来,在加载redis-server服务的时候通过再次执行命令恢复数据库数据。
- 缺点是aof的文件大小远远大于rdb,运行效率比rdb慢
- 开启AOF:在配置文件中更改为
Redis中AOF持久化有三种策略:
- always:默认的策略,每个写命令都被立即记录到AOF文件中,保证数据的实时性。这种方式对AOF文件的更新比较频繁,同时也可以在Redis意外退出时最大程度地恢复数据。
- everysec:每秒钟执行一次AOF日志记录,减少AOF文件记录的频率,也减少了将数据写入磁盘的次数,降低了对性能的影响,但是在Redis意外退出时可能会丢失不足一秒钟的数据。
- no:即不开启AOF持久化,Redis只使用内存作为数据存储,这种方式对性能影响最小,但对于对数据完整性有特殊要求的应用程序来说,风险较大。
消息订阅
redis发布订阅是一种消息通信模式:pub发送消息,sub接收消息,它是单向通信。
- 建立并订阅频道:
subscribe name
- 发布消息:
publish name message
使用场景:
实时消息系统
聊天室
订阅关注系统
更复杂的我们需要用MQ
主从复制
将一台redis服务器作为主节点,多个redis服务器作为从节点,主节点专门负责写数据,从节点专门负责读数据,实现读写分离,从主从复制就是主节点数据复制到从节点, 数据流向只能是单向的。
主从复制的作用:
- 数据冗余
- 故障恢复
- 负载均衡
- 高可用
默认情况下每个Redis服务器都是主节点,当设置为从节点的时候,只能有一个主节点,而一个主节点可以有多个从节点
info replication
:查看当前库的信息
配置方式
- 使用多个配置文件启动多个redis-server
- 每个服务一个不同的端口,配置文件需要修改每个server的信息 比如端口号、数据存放路径、pidfile、lo等等
- 配置从机:
slaveof host port
主机的所有写操作都会刷入到从机,从机不能进行任何写操作
当没有哨兵的时候,如果主机宕机导致连接端口,从机仍然认为主机存在,当主机恢复连接依然可用,但是断开的时候不能写,虽然这样保持了高可用性,但断开的时候应该自主选择一个从机作为主机;如果从机断开,重连后从机配置消失,只有将主从配置写入配置文件才能继续保持高可用。
一个从机可以作为另一个从机的主机,主从嵌套。
哨兵模式
哨兵是一个独立进程,原理是通过哨兵发送redis命令确定redis-server存活,同时一般来讲我们会配置多个哨兵,相互监控redis-server和别的哨兵。
假设主服务器机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵主观的认为主服务器不可用,这个现象成为主观下线。当后面的哨兵也检测到主服务器不可用,并数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover故障转移操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自已监控的从服务器实现切换主机,这个过程称为客观下线
创造一个哨兵过程
- 配置文件:sentinel.conf
sentinel minitor redis-name host port id[id自己取名,是数字]
用于注册一个被监视redis-server 一般监视主机,它会自动发现从机
- 启动哨兵:
redis-sentinel config-address
当哨兵发现主机宕机后,会自动选取一个从机作为其余从机的主机
优点: 1、哨兵集群,基于主从复制模式,所有的主从配置优点,它全有 2、主从可以切换,敌障可以转移,系统的可用性就会更好 3、哨兵模式就是主从模式的升级,手动到自动,更加健壮! 缺点: 1、Redis不好啊在线扩容的,集群容量一旦到达上限,在线扩容就十分麻烦! 2、实现哨兵模式的配置其实是很麻烦的,里面有很多选择!
一些哨兵配置:
#Examplesentinel.conf #哨兵sentine1实例运行的端口默认26379 port26379 #哨兵sentinel的工作目录 dir /tmp #哨兵sentine监控的redis主节点的ipport #master-name可以自己命名的主节点名字只能由字母A-z、数字o-9、这三个字符",-"组成。 #quorum配置多少个sentine1哨兵统一认为master主节点失联那么这时客观上认为主节点失联了
sentinel monitor
<master-name><ip>``<redis-port><quorum>
sentine1 monitor mymaster 127.0.0.1 6379 2 #当在Redis实例中开启了requirepassfoobared授权密码这样所有连接Redis实例的客户端都要提供密码 #设置哨兵sentine连接主从的密码注意必须为主从设置一样的验证密码 #sentinelauth-pass
<master-name><password>
sentine1 auth-pass mymaster MysuPER--secret-0123passwOrd #指定多少毫秒之后主节点没有应答哨兵sentine1此时哨兵主观上认为主节点下线默认3o秒 #sentineldown-after-mi11iseconds<master-name><mii1iseconds>
sentinel down-after-mi11iseconds mymaster 30oo0 #这个配置项指定了在发生failover主备切换时最多可以有多少个slave同时对新的master进行同步 这个数字越小,完成fai1over所需的时间就越长 但是如果这个数字越大,就意味着越多的slave因为rep1ication而不可用。 可以通过将这个值设为1来保证每次只有一个s1ave处于不能处理命令请求的状态。
缓存穿透
读的请求会先在缓存redis中查询,如果没有,则会进入mysql进行查询,如果mysql中也没有(有则会缓存在redis中)
当大量的查询请求涌向mysql就会造成mysql奔溃。
解决方案
- 在redis中加上一层过滤
- 对于查询为空的请求返回""
布隆过滤器和缓存空对象
缓存击透
在redis进行持久化数据的过程中,可能有大量相同key的请求涌向redis,而redis没有处理请求而涌向了mysql,造成了缓存击透
解决方案:
设置热点数据永不过期
加上互斥锁:在相同请求涌向mysql的时候,保证只有一个线程进入mysql
缓存雪崩
缓存雪崩指的是某一个时间段,缓存几种过期失效,redis宕机
在写入redis的时候,突然写入大量的数据,而且他们的缓存时间设置相同,当时间已过,缓存过期,同时有大量的访问进入导致走向了mysql,造成雪崩。还有一中是redis宕机,导致所有请求走向mysql数据库
解决方案:
保持redis高可用
限流降级 这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个ke只充许一个线程查询数据和写缓存,其他线程等待。
数据预热 数据加热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。
转载自:https://juejin.cn/post/7242924789656436773