Redis学习

java学习 专栏收录该内容
7 篇文章 0 订阅

Linux下Redis安装

  • 下载redis源码

  • 安装编译器

    yum install gcc-c++

  • 解压

    tar -zxvf redis-5.0.7.tar.gz

  • 把解压文件copy到/usr/local/src下

    cp -r /root/software/redis-5.0.7 /usr/local/src/redis

  • 编译依赖项

    cd /usr/local/src/redis/deps

    make hiredis lua jemalloc linenoise

  • 编译

    cd /usr/local/src/redis

    make

  • 安装

    mkdir /usr/local/redis

    make install PREFIX=/usr/local/redis/

  • 后台启动

    修改配置文件

    daemonize yes

  • 进入sql

    redis-cli

  • 退出sql

    quit

  • 停止redis

    redis-cli shutdown

    pkill redis-server

  • redis性能测试工具

    redis-benchmark

Redis原理

  • 单进程单线程
    • 采用多路I/O复用技术可以让单个线程高效处理多个连接请求
    • 因为多进程可能涉及到锁,线程切换消耗cpu,单进程不存在线程安全问题
  • 默认16个数据库,下标从0开始,默认使用0号库
  • select命令切换数据库
  • 常用命令
    • dbsize: 查看当前数据库key的数量
    • flushdb: 清空当前库
    • Flushall: 清空所有库

Redis数据类型

  • 字符串
    • 所有的key都必须是字符串
  • list
    • 类似双向列表
  • hash
    • 类似Map
  • set
    • 无序不可重复
  • zset
    • 有序不可重复

Redis常用命令

  • keys * 获取所有的key
  • select 0 选取0号库
  • move myString 1 将当前数据库key移动到1号库
  • flushdb 清除指定库
  • randomkey 从当前数据库中随机返回
  • type key 类型
  • del key 删除key
  • exist key 判断是否存在key
  • expire key 10 10秒key过期
  • pexpire key 1000 1000毫秒过期
  • persist key 删除过期时间
  • ttl key 查看还有多少秒过期

String类型相关命令

  • set k1 v1
  • get k1
  • getrange k1 0 -1 字符串分段,取0到-1,-1是从后往前数
  • getset name new_cxx 设置值,返回旧值
  • mset k1 v1 k2 v2 批量设置
  • mget k1 k2 批量获取
  • setnx k1 v1 不存在就插入
  • setrange k1 index v1 从index开始用v1替换value
  • incr k1 递增
  • incrby k1 10 递增10
  • decr k1 递减
  • decrby k1 10 递减10
  • incrbyfloat k1 0.5 递增0.5
  • append k1 v1 追加
  • strlen 长度
  • object encoding k1 得到k1的类型
    • string里有三种编码
    • int 用于能够副作用64位有符号整数表示的字符串
    • embstr 用于长度小于等于44字节
    • raw 用于长度大于44字节

###List常用命令

  • lpush mylist a b c 左插入
  • rpush mylist x y z 右插入
  • lrange mylist 0 -1 取出数据集合
  • lpop mylist 弹出集合最后一个元素
  • rpop mylist 弹出第一个元素
  • llen mylist 长度
  • lrem mylist count value 删除
    • count>0 从表头开始向尾搜索,移除与value相等的元素
    • count<0 从表尾向头搜索,移除与value相等的元素
    • count=0 移除表中所有与value相等的元素
  • lindex mylist 0 取指定索引的值
  • lset mylist 2 n 指定索引设置值
  • ltrim mylist 0 4 对一个list进行修剪,保留指定区间内的值,前闭后闭
  • linsert mylist before a a1 在元素a之前插入a1
  • linsert mylist before b b1 在元素b之后插入b1
  • rpoplpush list list2 转移列表的最后一个元素到新列表

Hash常用命令

  • hset myhash name cxx 给哈希表中的字段赋值,如果hash表不存在,一个新的hash表将被创建进行hset操作,如果字段已经存在,新值会覆盖旧值
  • hget myhash name
  • hmset myhash name cxx age 25 note ‘notes’
  • hmget myhash name age note
  • hgetall myhash 获取所有的
  • hexists myhash name 是否存在
  • hsetnx myhash score 100 设置不存在的,如果存在则不做处理
  • hincrby myhash id 1 递增
  • hdel myhash name 删除
  • hkeys myhash 获取所有key
  • hvals myhash 获取所有value
  • hlen myhash 长度

Set常用命令

  • sadd myset redis
  • smembers myset 数据集合
  • srem myset set1 删除
  • sismember myset set1 判断元素是否在集合中
  • scard key_name 个数
  • sdiff | sinter | sunion 差集|交集|并集
  • srandmember 随机获取集合中的元素
  • spop 从集合中弹出一个元素

Zset常用命令

  • zadd zset 1 one
  • zadd zset 2 two
  • zadd zset 3 three
  • zincrby zset 1 one 增长分数
  • zscore zset two 获取分数
  • zrange zset 0 -1 withscores 范围值
  • zrangebyscore zset 10 25 withscores 指定范围的值
  • zrangebyscore zset 10 25 withscores limit 1 2 分页
  • zrevrangebyscore zset 10 25 withscores 指定范围的值
  • zcard zset 元素数量
  • zcount zset 获得指定分数范围内的元素个数
  • zrem zset one two 删除一个或多个元素
  • zremrangebyrank zset 0 1 按照排名范围删除元素
  • zremrangebyscore zset 0 1 按照分数范围删除元素
  • zrank zset one 获取成员的下标
  • zrevrank zset one 获取成员反下标
  • zinterstore

Redis常用配置

  • 默认情况下,如果redis最后一次的后台保存失败,redis将停止接收写操作,这样以一种强硬的方式让用户知道数据不能正确持久化到磁盘
  • daemonize yes 配置守护进程
  • port 6379 更改端口号
  • bind 127.0.0.1 绑定主机ip
  • timeout 0 客户端闲置多长时间后关闭连接,0表示不关闭
  • database 16 设置数据库的数量,默认0-15,共16个
  • save <seconds> <changes> 指定在多长时间内有多少次更新操作,就将数据同步到数据文件
  • redcompression yes 存储至本地数据库是是否压缩数据,默认采用LZF压缩
  • dir ./ 指定本地数据库存放目录
  • slaveof <masterip> <masterport> 从机设置主机的ip和端口号
  • masterauth <master-password> 主机密码保护,从机连接主机时的密码
  • requirepass foobared 设置redis连接密码
  • maxclients 10000 同一时间最大客户端连接数
  • maxmemory <bytes> redis可以使用的最大内存,达到内存上线,redis会试图移除内部数据
    • 默认使用noeviction算法,不进行移除,针对写操作返回错误信息
  • appendonly no 是否启用aof持久化
    • rdb和aof两种持久化模式
      • rdb在一个时间段会将redis中的数据同步到硬盘
      • aof会将操作数据库的命令保存到日志文件
  • appendfilename appendonly.aof 指定更新日志文件名,默认为aof
  • appendfsync everysec 指定更新日志条件(no | always | everysec)
  • vm-enabled no 是否启用虚拟内存机制,将访问量少数据的放到磁盘,访问量多的数据放到内存
  • vm-swap-file /tmp/redis.swap 虚拟内存文件路径
  • vm-max-memory 0 将所有大于vm-max-memory的数据存入虚拟内存,0表示所有value都存在磁盘
  • vm-page-size 32 存储分页
  • vm-pages 134217728 设置swap文件中的page数量
  • vm-max-threads 4 设置访问swap文件的线程数
  • glueoutputbuf yes 设置在向客户端应答时,是否把较小的包合并,默认开启
  • hash-max-zipmap-entries 64 指定在超过一定的数量或者最大的元素超过某一临界值时,采用一种特殊的hash算法
  • activerehashing yes 指定是否激活重置hash,默认开启
  • include /path/to/local.conf 指定包含其他的配置文件,可以在统一主机上多个redis实例之间使用同一份配置文件

Redis持久化

  • rdb
    • 以指定时间间隔自行数据集的时间点快照
    • 提高redis性能
  • aof
    • 记录服务器接收的每个写入操作,将在服务器启动时再次播放,重建原始数据集
    • 保证数据准确性

Redis事务

  • 一组命令的集合
  • ACID: 原子性,一致性,隔离性,持久性
  • discard 取消事务
  • exec 执行所有事务块内的命令
  • multi 标记一个事务的开始
  • unwatch 取消watch命令对所有key的监控
  • watch key [key…] 监视一个或多个key,相当于乐观锁
    • 监控了key,如果key被修改了,后面一个事务执行失效

Redis复制

  • 复制原理: 从机启动成功连接到主机后会发送一个sync命令,主机接到命令会启动后台存盘进程,同时收集所有接到的用于修改数据集的命令,在后台进程执行完毕后,主机将传送整个数据文件到slave以完成一次完全同步
  • 配置从机
  • slaveof 127.0.0.1 6379
  • 从机会同步主机所有数据,不只是切入点之后的数据
  • 从机不可写
  • 主机宕机后,从机原地待命;主机重启之后,可以继续正常使用
  • 从机可以再配置从机
  • slaveof no one 使当前数据库停止与其他数据库的同步,转成主数据库

哨兵模式

  • 后台监控主机是否故障,故障了会根据投票数自动将从机转为主机,主机回来会变为新主机的从机

  • 配置

    sentinel monitor mymaster 127.0.0.1 6379 1
    sentinel auth-pass mymaster 123456
    
  • redis-sentinel sentinel.conf 启动哨兵

  • 一组sentinel可以同时监控多个master

  • 主机将数据同步到从机会有延迟

Redis集群 高可用高并发

  • 哈希槽

  • 集群配置

    • port 7000
    • cluster-enabled yes
    • cluster-config-file nodes.conf
    • cluster-node-timeout 5000
    • appendonly yes
  • 搭建集群

    redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 --cluster-replicas 1
    
  • 使用集群

    redis-cli -c -p 7000
    

Java连接Redis

  • 使用Jedis连接

Spring集成Redis

  • 创建项目

  • 配置redis

    <!--声明配置对象-->
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxIdle" value="20"></property>
        <property name="maxTotal" value="25"></property>
        <property name="minIdle" value="10"></property>
    </bean>
    
    <!--声明jedispool-->
    <bean id="jedisPool" class="redis.clients.jedis.JedisPool">
        <constructor-arg name="poolConfig" ref="jedisPoolConfig"></constructor-arg>
        <constructor-arg name="host" value="127.0.0.1"></constructor-arg>
        <constructor-arg name="port" value="6379"></constructor-arg>
        <!--<constructor-arg name="timeout" value="5000"></constructor-arg>-->
    </bean>
    
  • 连接redis

    public class TestRedis {
      public static void main(String[] args) {
        ApplicationContext context = new 				ClassPathXmlApplicationContext("classpath:application*.xml");
        JedisPool jedisPool = context.getBean(JedisPool.class);
        Jedis jedis = jedisPool.getResource();
        String k1 = jedis.get("k1");
        System.out.println(k1);
        jedis.close();
        jedisPool.close();
      }
    }
    

Redis实现缓存

  • 缓存切面

    private final static String POINT_ALLMENU = "execution(* com.wushang.service.impl.MenuServiceImpl.queryAllMenu(..))";
        private final static String ALL_MENU_KEY = "all_menu";
        @Autowired
        private JedisPool jedisPool;
        @Around(value = POINT_ALLMENU)
        public Object cacheAllMenu(ProceedingJoinPoint proceed) throws Throwable {
            //先从redis取
            Jedis jedis = jedisPool.getResource();
            String json = jedis.get(ALL_MENU_KEY);
            if (null == json) {
                System.out.println("缓存里没有数据,去查询数据库并存入缓存");
                Object o = proceed.proceed();
                jedis.set(ALL_MENU_KEY, JSON.toJSONString(o));
                return o;
            } else {
                System.out.println("已从缓存找到数据,直接返回");
                return JSON.parseArray(json, Menu.class);
            }
        }
    

Spring+Redis实现秒杀

  • 页面倒计时
  • 计时结束用户可点击
  • 一个用户点击相当于开启一个线程(模拟1000个线程)
  • 把商品初始化到redis,使用list

SpringBoot中使用Redis

  • 配置

    #redis配置
    spring:
      redis:
        host: 127.0.0.1
        port: 6379
        jedis:
          pool:
            max-active: 25
            max-idle: 20
            min-idle: 10
    
  • 使用StringRedisTemplate,不可存对象

  • 使用RedisTemplate

    • 键值需要序列化,值使用Jackson的序列化方式(容量小,json数据格式)

         redisTemplate.setKeySerializer(new StringRedisSerializer());
         redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
      

SpringBoot使用Redis做缓存

  • 修改仓库管理项目缓存为redis
    • 添加依赖
    • 修改yml配置
  • 使用注解方式操作redis
    • 开启注解: @EnableCaching
    • 修改Service
    • 修改ServiceImpl
    • 添加缓存注解
    • 创建配置类,修改redis序列化方式
  • 注意点
    • 缓存保存的是当前注解所在方法的返回值
    • @Resource和@Autowired的区别: @Resource通过名称注入,@Autowired通过类型注入,使用@Autowired注入RedisTemplate<String,Object>失败是因为IOC容器中的RedisTemplate默认为RedisTemplate<Object,Object>
    • 要注意缓存中和数据库中的数据一致,避免脏读(@Cacheput,@CacheEvict),不可重复读,幻读

Redis键值设计原则

  • 使用 : 拆分
  • 值使用json串存储

缓存穿透

一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就去数据库里查找,一些恶意的请求会故意查询不存在的key,请求量很大,就会对后端系统造成很大的压力

  • 避免
    • 对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert之后清理缓存
    • 对一定不存在的key进行过滤,可以把所有的可能存在的key放到一个大的Bitmap中,查询时通过该Bitmap过滤
    • 也可以使用流行的bloom filter 布隆过滤器

缓存雪崩

当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,会给后端系统带来很大的压力,导致系统崩溃

  • 避免
    • 在缓存失效后,通过加锁或队列来控制读取数据库写缓存的线程数量,比如对某个key只允许一个线程查询数据和写缓存
    • 做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期
    • 不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀分布
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值