redis入门学习

1.redis基础

redis有16个数据库 默认使用第0个 
默认端口6379
redis基于内存 瓶颈是机器内存和网络带宽 单线程的

为什么redis单线程效率高?
redis所有数据在内存上 多线程cpu会上下文切换 耗时操作 
对于内存系统来说 多次读写在一个cpu上效率最高

基本命令(记住):
select 3    //切换到第3号数据库
dbsize    //查看该数据库存有多少个数据
keys *    //查看数据库所有的key
flushdb    //清空该数据库数据
flushall //清空所有数据库的数据
exists name //是否存在name这个key 存在1 不存在0
move name 1 //将name这个key移除 1表示当前库
expire name 1 //name这个key 10秒后过期
ttl name    //查看key剩余过期时间
type name  //查看key的类型

 

2.String字符串

基本命令
append key "hello"    //往key追加字符串hello key若不存在就新增
strlen key    //获取字符串长度
incr key    // 自增1 相当于i++
incrby key 8 //自增8 相当于i+=8
decr key    //自减1
decrby key 8   //自减8

getrange key 0 3  //截取字符串 相当于substring
setrange key 1 xx //替换字符串 相当于replace


//重点(常用)
setex key 30 "hb"   //添加值并设置过期时间
setnx key "hb"    //不存在key添加 存在key添加失败(分布式锁中常用到)
mset k1 v1 k2 v2    //批量添加
mget k1 k2        //批量获取
msetnx k2 v2 k3 v3 //同上是批量添加 若k2或k3只要有已存在key就添加失败
getset key v1    //先取得key的值并设置新的值 

 

3.List

redis的list就是栈 链表 后进先出 push进 pop出 但可以从左或从右添加元素
list命令基本是l开头的

基本命令
lpush key  one   //从左边添加元素
rpush key  one   //从右边添加元素
lrange key 0 1    //获取起始到终止位置的元素 0 -1是所有的元素
lpop key     //从左边移除第一个元素
rpop key    //从右边移除第一个元素
lindex key 0    //获取下标0的元素
llen key    //获取list的长度
lrem key 1 one  //移除list中1个value为one的值
ltrim key 1 2    //只保留list中下标1到2的值 其它值被删除

rpoplpush key key1    //把key最右边元素剪切到key1中
exists key        //是否存在key
lset key 0 value1      //更新操作 将下标0的值替换为value1 下标0无值报错
linsert key before value1 insvalue  //list中value1的值前加上一个元素 这个元素的值为insvalue.  其中before/after往前/后插入

 

4.Set

set命令基本s开头

基本命令
sadd myset value1    //添加元素
smembers myset    //获取set中所有值
sismember myset value1    //set中是否包含value1这个元素
scard myset        //获取set元素个数
srem myset value1    //移除set中指定的元素
srandmember myset 2  //随机抽选set集合指定个数的元素
spop myset    //随机删除set中的元素
smove myset1 myset2 value1    //set集合myset1中的value1剪切移动到myset2中
sdiff myset myset1    //取第一个集合与第二个集合的差集(1集合有2集合没有)
sinter myset myset1    //取第一个集合与第二个集合的交集(2个集合都有的元素 共同好友这个做)
sunion myset myset1    //取并集(2个集合整合)

 

5.hash

hash命令基本h开头

hset myhash key1 value1    //添加hashmap
hget myhash key1            //获取hashmap
hmset myhash k1 v1 k2 v2    //批量添加hashmap
hmget myhash k1 k2            //批量获取hashmap
hgetall myhash                //获取hash所有值(kv都显示)
hdel myhash key1        //删除

hlen myhash    //获取hashmap个数
hexists myhash k1    //hashmap中指定字段是否存在
hkeys myhash    //获取所有key
hvals myhash    //获取所有values

hincrby myhash k1 1    //自增1
hsetnx myhash k1 v1    //不存在创建

存对象如用户对象
 用string: set user:1:name hb
 用hash:  hset user:1 name hb       
用hash更好一点

 

6.zset(有序集合)

就把它看成linkhashset

基础语法
基本是z开头
zadd myzset 1 v1 2 v2    //添加元素(可以批量添加)
zrange myzset 0 -1    //正序显示所有元素(zrevrange是反序)
zrangebyscore myzset -inf +inf [withscores]   //按-无穷到+无穷排序显示(inf是无穷的意思 []可选 withscores也打出下标 )

zrem myzset two    //移除元素
zcard myzset        //获取集合元素个数
zcount myzset 1 3    //获取指定区间的元素个数


与set命令的api基本一致
应用范围:
    排行榜//数量存下标 能排列显示排行信息

 

 

7.geospatial

地理位置 可以推算位置信息和距离

命令geo开头
//南北极无法导入 一般情况下直接下载地理位置信息导入到redis

geoadd mygeo 116.40 39.90 beijin    //添加地理位置
geoadd mygeo 121.47 31.23 shanghai 121.47 31.23 shanghai1    //也可以批量添加
geopos mygeo shanghai    //获取指定城市的经纬度

geodist mygeo beijin shanghai km [withcoord]    //两地间距离(m米 km千米 mi英里 ft英尺子) 
georadius mygeo 120.3 30.2 1000 km [withcoord] [withdist] [count 1]    //获取以指定经纬度为中心半径1000km范围内的元素 
//withcoord显示元素的坐标 withdist显示到中心的距离 count允许显示元素的个数

georadiusbymember mygeo shanghai 100 km //同上 中心坐标改为指定的元素


//geo底层其实就是zset 因此可以用zet命令处理geo
zrange mygeo 0 -1    //显示地图所有元素
zrem mygeo shanghai    //移除指定元素

  

8.Hyperloglog 基数

基数(不重复的元素)
如{1,3,5,7,8,7}基数是{1,3,5,7,8}
应用场景:如网站访问统计人数,同一人多次访问算一人
    传统方式:set保存用户id 存大量用户id比较麻烦 因为目的只是为了计数
    Hyperloglog:基数统计算法 且占用内存固定 只需12kb 但有0.81%错误率

基本语法
pf开头
pfadd mypfkey a b c d e d //添加
pfcount mypfkey        //统计基数数量 5
pfmerge mypfkey3 mypfkey2 mypfkey1    //mypfkey3的值为mypfkey1和2的并集


注:Hyperloglog有容错率0.81% 不允许容错的话就不能用

 

8.Bitmaps

位存储
操作二进制 只有0和1两种状态

基本命令
setbit mybit 0 1    //在第一位置添加1
getbit mybit 0        //获取第一位的值
bitcount mybit        //统计值为1的数量

 

9.事务

原子性:要么同时成功 要么同时失败 
一致性:事务的执行使得数据库从一种正确状态转换成另外一种正确状态
隔离性:在事务正确提交之前,它可能的结果不应该显示给其他事务
持久性:事务正确提交之后,其结果将永远保存在数据库之中

redis事务不保证原子性 保证一致性 顺序性 排他性

redis事务流程:
1.开启事务 2.依次输入redis命令 3.执行事务


基本命令
multi    //开启事务
exec    //事务结束 开始执行

discard    //取消事务 事务队列中的命令都不会执行

 

10.乐观锁

悲观锁:无论什么情况都会加锁
乐观锁:不会加锁 只有在更新字段的时候会去判断期间是否有人改过数据 用watch监控
mysql的乐观锁是version监控

如:
乐观锁付款事务正常流程:
set money 100
set out 0
watch money    //监控money 若money变了 下面事务exec执行失败
multi
decrby money 20    
incrby out 20
exec        //事务成功会自动解锁
//如果事务提交失败应该是money被改了 执行下面失败的流程
unwatch    //解锁
watch money //再加锁 锁定money的最新值
...            //继续把事务走一遍

 

11.jedis

添加依赖:
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.2.0</version>
        </dependency>

测试:
Jedis jedis = new Jedis("127.0.0.1",6379);
jedis.get("key");

-------------------------------------------------------------------

springboot整合
springboot2.x后jedis被替换为lettuce
1.添加依赖:
     <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
2.yml中添加配置:
    spring.redis.host
    spring.redis.port等
3.注入:
    @Autowired
    private RedisTemplate redisTemplate;
   操作: redisTemplate.opsForValue().get("");//操作string
                       opsForList().         //操作list
    等
测试:redisTemplate.opsForValue().set("name1","springboottest");
到redis服务器发现插入的key乱码 其实不是乱码 是因为RedisTemplate默认了使用jdk序列化 
用代码获取都是正常的 只是用命令在服务器上看不太方便
//4 5都是企业级开发需要的方式 4.配置一个自己的RedisTemplate配置类处理序列化问题 所有key采用string序列化 value采用json 具体详情看项目中的测试类RedisConfig 再测试: redisTemplate.opsForValue().set("name2","springboottest"); 到redis服务器发现插入的key是name2了 value是\"springboottest\" 5.使用原生redisTemplate的api不太方便 可以自己封装一个工具类 详细的看测试类中utils中的RedisUtil jedis采用直连 多线程不安全 还需使用jedis pool连接池 BIO模式 lettuce采用netty 实例多线程中共享 不存在线程不安全情况 可以不使用线程池减少线程数量 NIO模式

 

 

12. redis.conf配置文件详解

学习看redis.conf
打开redis.conf
1.# units are case insensitive so 1GB 1Gb 1gB are all the same.
redis对大小写不敏感

2.# include /path/to/local.conf
# include /path/to/other.conf
类似spring的import include 能包含其它的配置文件

3.NETWORK
bind //允许访问的ip
protected-mode yes  //保护模式 默认开启 若关闭则允许所有外部访问 开启则允许bind的ip访问
port    //端口设置

4.GENERAL 通用配置
daemonize yes    //守护进程 默认no yes允许退出继续在后台运行
logfile /usr/local/bin/config/redislog.log    //日志文件路径
databases 16    //数据库数量
always-show-logo yes    //启动是否显示redis logo

5.SNAPSHOTTING快照
持久化 在规定时间内执行多少次操作能持久化到文件 .rdb .aof
redis是内存数据库 没有持久化数据断电丢失

save 900 1    //900秒内至少1个key修改 就进行持久化操作
save 300 10
save 60 10000

stop-writes-on-bgsave-error no //若持久化失败是否停止工作
rdbcompression yes    //是否压缩rdb文件 压缩会消耗cpu资源
rdbchecksum yes    //保存rdb文件时是否校验
dir ./                 //rdb文件保存目录


6.REPLICATION 主从复制

7.SECURITY 安全
# requirepass foobared 登录redis密码 默认没有密码
设置登录密码2种方式
1.在配置文件加requirepass 1234
2.redis-cli命令输入 config get requirepass    //查密码
                          config set requirepass "1234" //设置密码 
                          //设置密码后发现所有命令没权限了
                          auth 1234//登录

8.CLIENTS 限制
# maxclients 10000    //允许连接redis最大客户端的数量
# maxmemory <bytes>    //redis配置最大内存容量
# maxmemory-policy noeviction    //内存到上限处理策略

9.APPEND ONLY MODE  aof模式
appendonly no        //默认不开启aof模式(用rdb模式)
appendfilename "appendonly.aof"    //aof持久化文件名称
appendfsync everysec    //每秒同步一次(可能丢失1秒数据)
# appendfsync always    //每次修改都同步(消耗性能)
# appendfsync no        //不同步
    

 

13.Redis持久化

rdb:

rdb保存的文件名是dump.rdb
1.触发生成rdb备份文件的规则:
    1.配置文件中配置的规则满足触发 如save 900 1(900秒内有改过1次key)
    2.flushall
    3.shutdown退出redis时

2.恢复rdb文件数据
把rdb文件放到redis启动目录下自动恢复rdb中数据

优点:
1.适合大规模数据恢复
2.对数据完整性要求不高

缺点:
1.需要一定的时间 若意外宕机 最后一次修改数据没有了
2.子进程去生成rdb 会暂用一定的内存

aof:

aof保存的文件名是appendonly.aof
aof将所有的命令都记录下来 可以看成记录命令的日志文件 恢复的时候将全部命令执行一遍重新构建
redis.conf 中appendonly yes开启aof

aof文件生成规则:
# appendfsync always  //每次修改同步生成
appendfsync everysec  //每秒同步生成
# appendfsync no    //不生成
    
注:若aof文件错误 redis启动会报错 
修复aof文件方式:redis-check-aof --fix appendonly.aof

优点:
1.appendfsync always  //每次修改同步生成   数据完整性好
appendfsync everysec  //每秒同步生成         数据完整性较好 但可能会丢失最后1秒数据

缺点:
1.aof远大于rdb 修复速度比rdb慢
2.aof运行效率比rdb慢 

 

扩展:
1.redis只做缓存的话 不用弄持久化
2.同时开启rdb和aof 优先载入aof 因为aof数据更完整

 

14.redis发布订阅

SUBSCRIBE runoobChat    //订阅
PUBLISH runoobChat "Redis PUBLISH test"    //发布

只能做一些简单的发布订阅
复杂的用消息中间件mq做

 

15.redis主从复制

主从复制:将一台redis服务器的数据复制到其它redis服务器 主节点(master/leader) 从节点(slave/follower)
数据只能由主节点到从节点 主节点写 从节点读(读写分离)
80%的压力是读取 把读取的压力放到从节点

主从复制主要作用
1.数据冗余:主从复制实现了数据热备份 是持久化外的一种数据冗余方式
2.故障恢复:主节点出问题 可以由从节点提供服务 以快速恢复。是一种服务冗余
3.负载均衡:主从复制配合读写分离 主节点写入 从节点读取 写少读多的情况下分担负载 提高性能


环境配置
redis-cli查看主从复制的信息: info replication
显示role就是这台redis是主机(master)或从机(slave)


--------------------------------------------------------------------
配置主从机方式(假设配置一主二从):
1.配置主从机需要改的配置(redis.conf)(就是把主从机的配置信息和其它主从机区分开): //3个redis.conf都需要配置
port         //redis端口区分开
pidfile    //pid命名区分开
logfile    //区分log命名
dbfilename    //rdb文件命名区分
2.配置好后3台默认都是主机 那么选2台当从机 从机需要选定一台当它的主机 //重点
在从机中的redis-cli中输入slaveof 127.0.0.1 6379 //即让自己由主机变从机 它主机的地址是127.0.0.1 6379
slaveof no one  //本机作为从机失效 恢复为主机
3.步骤2是通过命令配置主从 不是永久的
在redis.conf中配置
# replicaof <masterip> <masterport>
写入对应的ip 端口就好了
如果主机有密码则在下面配置
# masterauth <master-password>

注:1.主机只负责写 从机只负责读
    2.主机写入的从机都会同步数据
    3.主从复制虽然用slaveof命令的方式每次重启都需要重新配置 但还是比
    在配置文件中配置更好一点 因为若出现某一台宕机 可以用命令快速的
   切换主从 

 

16.哨兵模式

主从模式中如果主机宕机 得手动切换主从(把其中一台从机换成主机) 人工处理耗时  所以优先考虑哨兵模式
哨兵是一个独立的进程 其原理是哨兵发送命令监控多个redis实例 监控是否宕机
redis-sentinel
一个哨兵可能有问题 可以用多个哨兵对多个redis服务监控 哨兵间也互相监控
(用哨兵模式建议6个服务器 1主2从3哨兵)

配置哨兵方式:
1.建一个哨兵配置文件sentinel.conf
#sentinel monitor 被监控名称 host ip 1//1是多少个哨兵认为主机宕机时开始投票选一台从机当主机 host ip是主节点的redis
sentinel monitor myredis 127.0.0.1 6379 1
2.启动哨兵
redis-sentinel sentinel.conf


再次梳理流程:
新建哨兵配置文件 配置哨兵监听的主节点主机 主节点宕机后被至少1个哨兵监听到时进行投票(被多少个哨兵监听到宕机是上述配置文件中定义的) 投票算法会选择一台从节点作为新的主节点 若宕机的那台主机恢复了 哨兵会自动把宕机的主机变更为从机


优点:
1.哨兵基于主从复制 所有主从复制的优点都有
2.故障可以转移 高可用性
3.哨兵模式就是主从复制的升级版 手动到自动

缺点:
1.不容易在线扩容 
2.哨兵模式全局配置内容比较多

 

17.redis缓存穿透和雪崩

缓存穿透(查不到导致):用户查一个数据 缓存没有导致查数据库 数据库也没有导致重复查询
查询很多时导致给数据库造成很大压力 这就是缓存穿透
解决方式:
1.数据库没有的数据redis缓存设空对象 减轻数据库压力
2.布隆过滤器
//布隆过滤器是一个数据结构 对所有可能的查询的参数以hash存储 在控制层进行校验 不符的丢弃以缓解redis及数据库的压力


缓存击穿(查量太大缓存过期导致):是比缓存穿透更严重一级 一个热词用户搜索量非常大 但redis的key过期 就在过期的这一瞬间高并发都到数据库 服务器这一瞬间没抗住
解决方式:
1.key设不过期
2.分布式锁 每个key只用一个线程去查询数据库 其余的等待



缓存雪崩:某一段时间 缓存集体失效或redis宕机
解决方式:
1.停掉一些服务保证主要服务可用 如双11退单服务停用
2.数据预热 预先将可能大部分访问的数据访问一遍加载到缓存中
3.redis高可用 就是多设几台redis
4.限流降级 缓存失效的话通过加锁或队列控制读写访问数据库的线程 如对某一key只允许一个线程查询

 

posted @ 2021-01-15 01:06  小白小白小白小白  阅读(121)  评论(0编辑  收藏  举报