1.数据类型
String类型简介:
String类型是redis最基本的类型,一个key对应一个value,value最大为512M。String类型底层结构叫做简单动态字符串,是可以修改的字符串,类似以Java中的ArrayList。当村粗的value小于1M时,会成倍扩容现有的空间;超过1M时,则每次只会增加1M的空间。最大不超过512M。
String常用命令:
set < key > < value > 添加键值对
setnx < key> < value > 当key在数据库中不存在时,则会添加
setxx < key > < value > 当key在数据库中存在时,则会添加
setex < key > < seconds > < value > 设置key的过期时间,单位为秒
ttl < key > 查看当前key过期剩余时间
get < key > 获取数据库对应key的value
append < key > < value > 将给定的value追加到key的末尾
incr< key > 将key中的数字+1(这里key对应的value必须是数字)
decr< key > 将key中的数字-1(这里key对应的value必须是数字)
incre/decre < key > <长度> 将key对应的value加减 "长度"
mset < key > < value > < key > < value > ... 一次设置多个键值
mget < key > < key > ... 一次获取多个键的值
getrange < key > < start > < end > 获取值得范围,类似于java中的subString(),前包后包
getset < key > < value > 以旧换新
redis列表:
列表是单键多值,按照插入顺序排序的简单字符串列表。它的底层是一个双向链表,对两端的操作性能很高,对中间操作的性能偏低。
list常用命令:
rpush/lpush < key > < value > < value> ... 从右/左边添加插入一个元素
rpop/lpop < key > 从右/左吐出一个元素(值在键在,值光键亡)
lange < key > < start > < end > 根据索引返回列表元素(0,-1表示返回全部元素)
rpoplpush < key1 > < key2 > 将key1右边突出的值追加在key2的右边
lindex < key > < index > 根据索引下表获取元素(从左到右)
llen < key1 > 获取列表长度
linsert < key > before < value > < newvalue > 在value的后面插入newvalue
lrem < key > < n > < value > 从左边删除n个value(从左到右)
lset < key > < index > < value > 将key中下标为index的值替换为value
redisSet列表:
Set数据机构是dict字典,使用hash表实现,类似于java中的hashSet。
set常用命令:
sadd < key > < value > < value> ... 添加元素,重复的元素会被忽略
smembers < key > 查看key的所有元素
spop < key > 随机从key吐出一个元素
srandmember < key > < n > 随即从集合中取出n个值,不会删除
smove < key1 > < key2 > < value > 把集合一个元素一动到另一个集合
sinter < key1 > < key2 > 取两个集合的交集元素
sunion < key1 > < key2 > 取两个集合的并集
sdiff < key1 > < key2 > 取两个集合的差集元素
redisHash:
redisHash是一个键值对集合,这个键值对中的值是:一个filed,对应一个value的映射表,适合存储对象,类似于java中的Map<String,Object>。
hash常用命令:
hset <key> <filed> <value> <filed> <value> ... 给key集合中的filed键赋值value
hget <key> <filed> 从key取出filed的value
hexists <key> <filed> 查看key中是否存在filed
hkeys <key> 列出key中所有的filed
hvals <key> 列出key中所有的value
hincrby <key> <filed> <increment> 为key中的filed加上increment
有序集合Zset:
zset与set相似,不同之处在于有序集合每个成员都会关联一个评分,所有成员按照这个评分从低到高排序,集合中成员是唯一的,评分是可以重复的。
Zset常用命令:
zadd <key> <score1> <value1> <score2> <value2> ...将元素value1,value2添加到key中
zrange <key> <start> <end> [withscores] 返回下标start到end之间的元素,withscores表示带评分
zrangebyscore <key> <min> <max> 返回评分在min到max之间的的成员,从小到大排序
zrangebyscore <key> <max> <min> 返回评分在min到max之间的的成员,从大到小排序
zincrby <key> <increment> <value> 为元素的score加increment
zrem <key> <value> 删除集合下指定value的值
zcount <key> <min> <max> 统计评分区间的元素个数
zrank <key> <value> 返回该值在集合中的排名,从零开始
BitMaps:(redis6新增数据类型)
Bitmaps本身不是一种数据类型, 实际上它就是字符串(key-value) , 但是它可以对字符串的位进行操作。可以把Bitmaps想象成一个以位为单位的数组, 数组的每个单元只能存储0和1, 数组的下标在Bitmaps中叫做偏移量。
常用命令:
setbit <key> <offset> <value> 设置Bitmaps中某个偏移量的值(0或1)
bitcount <key> <start> <end> 统计给定偏移量范围内1的数量
bitop operation (and/or/not/xor) <保存的map> [key1 key2…]
HyperLogLog:
Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。
基数:比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素)为5。 基数估计就是在误差可接受的范围内,快速计算基数。
常用命令:
pfadd <key> < element> [element ...] 往hyperLogLog里添加指定元素,如果执行命令后基数发生变化,则返回1,否则返回0
pfmerge <destkey> <sourcekey> [sourcekey...] 将一个或多个HLL合并后的结果存储在另一个HLL中,比如每月活跃用户可以使用每天的活跃用户来合并计算可得
Geospatial:
GEO,Geographic,地理信息的缩写。该类型,就是元素的2维坐标,在地图上就是经纬度。redis基于该类型,提供了经纬度设置,查询,范围查询,距离查询,经纬度Hash等常见操作。
常用命令:
geoadd<key>< longitude><latitude><member>[longitude latitude member...] 添加地理位置(经度,纬度,名称)
geopos <key><member> [member...] 获得指定地区的坐标值
geodist<key><member1><member2> [m|km|ft|mi ] 获取两个位置之间的直线距离
georadius<key>< longitude><latitude>radius m|km|ft|mi 以给定的经纬度为中心,找出某一半径内的元素
2.发布订阅
redis发布订阅是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息,redis可以订阅任意数量的频道。
subscribe channel1 订阅频道一
publish channel1 hellohello 向channel1发送消息hellohello
3.事务(multi/exec/discard)
redis中事务分两个阶段:1.使用multi将之后的命令依次放入队列中,直到输入exec,redis会将命令队列中的所有命令依次执行,过程中可以使用discard放弃组队。
执行失败的两种情况处理:
1.命令组队中某条指令出错:执行时所有的操作都会取消
2.组队时没出错执行出错时:只有出错的那条指令会取消执行
悲观锁:(Pessimistic Lock)
每次操作数据时都认为别人会来修改,所以每次都加上锁,直到操作完毕才释放,这时下一个操作才能操作数据。类似于关系型数据库中的行锁,表锁,读锁,写锁等。
乐观锁:(Optimistic Lock)
操作数据不会上锁,但会添加一个版本号,当两个操作拿到同一个版本号的数据,但第一个操作更新了数据和版本号,此时第二个操作会先判断自己拿到的版本号和数据现在的版本号是否相同(check-and-set),不相同则不执行。乐观锁多应用于多读的应用类型,可以提高吞吐量
Wacth <key1> <key2> ...:使用wacth监视一个或多个key,如果事务执行之前这个key被其他命令改动,那么事务将被打断。
Unwacth <key1> <key2> ...:取消监视
4.redis持久化
两种持久化方式:
RDB:(redis database)在指定的时间间隔内将内存中的数据集快照写入磁盘,redis默认开启。redis会单独创建一个子线程(fork)进行持久化,将数据写入一个临时文件,待持久化结束后,再用临时文件替换上次持久化的文件(写时复制技术)。这个过程中主进程不会进行I/O操作,如果需要大规模的数据恢复,且对数据完整性要求不是非常敏感则使用RDB方式。缺点就是最后一次持久化后的数据可能丢失。
AOF:(append of file)将redis所有执行过的写命令记录下来,只需追加不需修改,redis启动时会读取该文件重新构建数据,拥有较高的完整性一致性。Redis默认不开启
备份:关闭redis,将备份文件(xxx.rdb/xxx.aof)拷贝到工作目录下,启动redis,备份数据会直接加载,当RDB和AOF同时开启时,Redis会默认加载AOF文件备份(数据不会丢失)
5.主从设置:(一主两从)
1.创建一个文件夹,将redis.conf复制到文件夹当中,再复制3份,加端口号命名:
redis6379.conf
redis6380.conf
redis6381.conf
redis.conf
2.在三个配置文件中写入:
include /home/jiangbb/study/myredis/redis.conf //引入公共部分
pidfile /var/run/redis_6381.pid
port 6381
dbfilename dump6381.db
3.分别启动三个redis服务:redis-server 对应的配置文件目录
4.使用redis-cli -p 端口号 连接到服务器,在从服务器中使用命令 : slaveof 主服务器ip 端口号
将从机变为主机命令:slaveof no one
主从复制原理:
1.当从服务器连接上主服务器后,会向主服务器发送数据同步的消息
2.主服务器接收到消息后,把主服务器的数据持久化,将生成的rdb文件发送到从服务器,从服务器拿到rdb文件后会进行读取
3.每次主服务器进行写操作后,都会主动与从服务器进行数据同步
6.哨兵模式:
如果某一台主服务器挂掉后,系统能够根据投票自动选择一台从服务器将其晋升为主服务器保持系统正常运行。
1.创建sentinel.conf文件,加入sentinel monitor 哨兵名 ip port 最少哨兵同一数量,例:
sentinel monitor mymaster 127.0.0.1 6379 1
2.使用命令redis-sentinel sentinel.conf 启动哨兵模式
新主服务器选择的条件:
1.优先级靠前的(replica-priority 100 数字越大优先级越小)
2.选择偏移量最大的(与主服务器数据的同步率更高)
3.选择runid最小的(redis启动随机生成runid)
7.集群:
使用集群原因:
1.现有容量不够
2.并发写操作压力大时,需要多台主服务器分摊
搭建步骤(模拟6台3主3从):
1.创建6个redis配置文件,加入内容
include /home/jiangbb/study/myredis/redis.conf //引入共公共部分
pidfile "/var/run/redis_6379.pid"
port 6379
dbfilename "dump6379.db"
cluster-enabled yes //开启集群
cluster-config-file nodes-6379.conf //生成的集群配置文件名
cluster-node-timeout 15000
//有端口号的要改为与真实端口对应的端口号
2.启动这6个redis服务,再到redis安装目录下的src目录下执行:
redis-cli --cluster create --cluster-replicas 1 192.168.0.123:6379 192.168.0.123:6380 192.168.0.123:6381 192.168.0.123:6389 192.168.0.123:6390 192.168.0.123:6391
//目的为了将6个服务器组合为3主3从的集群
执行成功后会自动分配集群结构,并询问你是否接受,输入yes ,搭建成功。
3.使用集群方式连接:redis-cli -c -p 6379(端口号),连接成功可以使用 cluster nodes 查看节点信息。
redis集群分配原则:
尽量保证主数据库在不同的ip地址上,每个主库和从库不在一个ip上
Slots(插槽):
1.插槽:redis有16384个插槽,每个节点负责(16384/节点数量)个插槽,数据库每个键都属于这些插槽中的其中一个。集集群使用公式CRC16(key)%16384来确定键存入哪一个插槽。目的为了将大量的写操作压力平均分担到每个节点。
2.命令:
cluster keyslot <key> 查看key在哪个插槽
cluster countkeysinslot <插槽号> 查看某个插槽号下键的数量(只能查看节点插槽范围内)
cluster getkeysinslot <插槽号> <count> 返回count个插槽号中的键
8.redis常见问题:
1.缓存穿透:应用服务器压力变大,redis命中率降低,一直查询数据库
解决方案:
1.对空值缓存
2.白名单访问(使用bitmaps存储可以访问的名单)
3.布隆过滤器(和白名单一样,只不过优化了效率更高)
4.实时监控
2.缓存击穿:极少的时间里,某个key过期,但是大量访问使用到这个key,导致数据库的压力变大
解决方案:
1.预先设置热门数据
2.实时调整
3.使用锁
3.雪崩问题:极少的时间里,大量的key过期,但是大量访问使用到这些key,导致数据库的压力变大
解决方案:
1.构建多级缓存结构
2.使用锁或者队列(不适合高并发)
3.设置过期标志更新缓存(当key快要过期,给他加时间续命)
4.将缓存时间分散开(给key随机加一个续命时间,这样不会集体过期)
9.分布式锁:
使用setnx上锁,del释放锁,锁一直没有释放,设置key的过期时间,自动释放