Redis教程

redis

本文主要是介绍redis,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

redis


redis  典型的 nosql 数据库,key-value

nosql (not only sql):非关系型数据库。nosql不依赖于业务逻辑方式存储,而以简单的key-value模式存储。因此大大的增加了数据库的扩展能力。

特点:1.不遵循SQL标准

   2.不支持ACID

   3.远超与sql的性能

nosql的使用场景:1.对数据高并发的读写。2.海量数据的读写。3.对数据高扩展性的

nosql的不适用场景:1.需要实物支持。2.基于sql的结构化查询存储

常见的nosql数据库:redis  mongoDB

 

redis安装成功之后

 

 

redis中默认16个数据库。初始默认使用0号库。

dbsize :查看当前数据库key的数量

flushdb  清空当前库

flushall  通杀全部库

select   转换库

debug reload  服务器运行过程中重启

shutdown save :关闭服务器时保存

redis 登陆方式1:redis-service   将日志信息直接打印到控制台

  登陆方式2:nohup redis-service  redis-conf &

 

 redis 换端口号登录: redis-service  --port 端口号

     启动时:    redis-cli  -p  端口号

 

redis 键 (key)


 

 

 

 

 

 

 

 

 

redis 字符串 (String)


 

String 是redis中最基本的数据类型,一个redis中字符串value最多可以是512M,String类型是二进制安全的,可以包含任何数据。比如jpg图片或者序列化的对象。

 

 

 

 

 

redis原子性:原子操作是指不会被线程调度机制打断的操作

1.java中i++是否为原子操作
不是
2.i=0;两个线程分别对i进行++100次,值是多少?
2-200

 

 

 

 

 

redis String的数据结构:简单的动态字符串

 

redis列表(List)


 

单键多值

redis列表是简单的字符串列表,底层是双向列表。从左边/右边插入值

 

 

 

 

 

 

 

 

 

 

 

 

 

 redis中list数据结构:快速列表(quicklist)

数据比较少的情况下:还用一块连续的内存存储,这个结构是ziplist(压缩列表)

数据比较多的情况下:使用quicklist

 

redis集合(set)


redis中set是String类型的无序集合,底层是一个 value为null的hash表。

 

 

 

 

 redis set数据结构:字典。字典是用哈希表实现的。

 

 

redis 哈希(hash)


 

redis  hash 是一个键值对集合。

redis  hash 是一个String类型的Field和value的映射表,hash适合于存储对象,类似于java中Map<String,Object>

 

 

 

 

 

 

 hash数据结构两种:

数量少,长度短:ziplist;否则使用hashtable。

 

 

 

redis有序集合zset(sorted set)


 

redis有序集合是一个没有重复元素的字符串集合。与普通集合set不同的是,有序集合中的每个成员都关联了一个评分(score),集合中的成员是唯一的,但评分是可以重复的。 

 

 

 

 

 

 zset数据结构(底层使用了两个数据结构):
1.hash:hash的作用就是关联元素value和权重score,保障元素value的唯一性,可以通过元素value找到score值。

2.跳跃表:目的在于给元素value排序,根据score的范围获取数据。

 

redis 6中的发布与订阅

是一种消息通信模式。

 

 

redis 新数据类型


BitMaps:本身不是数据类型,实际上就是字符串(key-value),它可以对字符串的位进行运算。可以把BitMaps想象为只存0或1的数组,数组的下标在BitMaps中叫做偏移量。

在第一次初始化BitMaps时,假如偏移量非常大,那么整个初始化过程会比较慢,可能会造成Redis阻塞。

 

 BITPOS:返回指定值0或1在指定区间第一次出现的位置。

 bitop  【and/or】 【存储key】 【key1】 【key2】

 

 

hyperloglog:做基数统计(基数:不重复数值的个数)

 

 

 

redis中jedis的使用(用java代码操作redis)

@Test
    public void testJedis(){

        //连接redis
    Jedis jedis = new Jedis("192.168.11.128", 6379);

        //操作redis
        /*操作string
        jedis.set("name","hyy");
        String name = jedis.get("name");
         System.out.println(name);
         */
        
    //操作list
    jedis.lpush("list1","a","b","c");
    jedis.rpush("list1","x","y","z");
    List<String> list1 = jedis.lrange("list1", 0, -1);
    for (String s : list1) {

        System.out.println(s);
    }

    //关闭连接
        jedis.close();


    }

@Test
    public void testJedis1(){

        //连接redis
        Jedis jedis = new Jedis("192.168.11.128", 6379);

        //操作redis
        jedis.hset("hash1","a1","a1");
        jedis.hset("hash1","a2","a2");
        jedis.hset("hash1","a3","a3");

        Map<String, String> hash1 = jedis.hgetAll("hash1");
        System.out.println(hash1);



        //关闭连接
        jedis.close();
    }

 

 

jedis案例:模拟验证码登录

package com.gym;

import org.junit.Test;
import org.w3c.dom.ranges.Range;
import redis.clients.jedis.Jedis;

import java.util.Random;

/**
 * @author 郭玉敏
 * @create 2021-11-14-13:03
 * @create 明天吃烤肉
 */
public class PhoneCode {
    public static void main(String[] args) {
        verifyCode("19155977383");

        getRedisCode("19155977383","775461");

    }

    //验证码校验

    public static void getRedisCode(String phone,String code){
        //从redis中获取验证码
        Jedis jedis = new Jedis("192.168.11.128",6379);
        String codeKey = "VeriftCode"+phone+":code";
        String s = jedis.get(codeKey);
        //判断
        if (s.equals(code)){
            System.out.println("成功");
        }else{
            System.out.println("field");
        }


    }


    //2.每个手机只能发送三次,验证码发到redis中,设置过期时间
    public static void verifyCode(String phone){

        //连接redis
        Jedis jedis = new Jedis("192.168.11.128",6379);

        //拼接key
        //手机发送次数
        String countKey = "VeriftCode"+phone+":count";

        //验证码key
        String codeKey = "VeriftCode"+phone+":code";


        //每个手机只能发送三次
        String count = jedis.get(countKey);
        if (count == null){
            //没有发送次数,第一次发送
            //设置发送次数为1
            jedis.setex(countKey,24*60*60,"1");
        }else if (Integer.parseInt(count) <= 2){
            jedis.incr(countKey);

        }else if (Integer.parseInt(count) > 2){
            System.out.println("发送次数超过三次");
            jedis.close();
            return;
        }

        //发送的验证码放到redis里面去
        String vcode = getCode();
        //过去时间120秒
        jedis.setex(codeKey,120,vcode);
        jedis.close();



    }




    //1.生成6位数字验证码
    public static String getCode(){
        Random random = new Random();

        String code="";
        for (int i=0;i<6;i++){

            int rand = random.nextInt(10);
            code += rand;
        }
        return code;

    }
}
检验 验证码

 

 

 

 redis持久化


redis持久化:利用永久性存储介质将数据进行保存,在出现问题时,进行数据恢复。

redis持久化的意义:保证数据安全,防止数据丢失

 

持久化方案:

 

RDB启动方式——save指令(手动执行一次保存操作)

save指令的执行会阻塞当前redis服务器,直到当前RDB过程完成为止,可能会造成较长时间的阻塞。

bgsave指令:在后台执行保存操作。

 

自动执行保存: save  second  changes

second:监控时间范围内

changes:监控key的变化量

在conf文件中进行设置

 

RDB三种启动方式对比:

 


 RDB优点:

 

 

 

AOF


 RDB存储的弊端:

  • 存储数据量较大,效率较低。 基于快照思想,每次读写都是全部数据,当数据量巨大时,效率非常低。
  • 大数据量下的IO性能较低。
  • 基于fork创建子进程,内存产生额外消耗。
  • 宕机带来数据丢失风险。

 

AOF:以独立日志的方式记录每次写命令,重启时再重新执行AOF文件中命令达到恢复数据的目的。AOF相较于RDB就是  改记录数据为记录数据产生的过程。

AOF写数据的三种方式

  1. always(每次):每次写入操作均同步到AOF文件中,数据零误差,性能较低。
  2. everysec(每秒):每秒将缓冲区的指令同步到AOF文件中,数据准确性较高,性能较高。系统宕机的情况下,丢失一秒的数据。
  3. no(系统控制):整个过程不可控。

 

AOF工作原理:

 

 

 

 

 

 

 

 

事物


redis执行指令过程中,多条连续执行的指令被干扰,打断,插队。 

redis事物:一个队列中,一次性、顺序性、排他性的执行一系列的命令。

 

事物的基本操作:

1.开启事物:multi

      设置事物的开启位置,执行此命令后,后续的所有指令均加入到事物中

2.执行事物: exec

      设定事物的结束位置,同时执行事物,与multi成对出现,成对使用。

 加入事物中的命令并不会马上执行,而是等exec之后才执行。

3.取消事物:discard

      终止事物的进程,发生位置在multi~exec

 

 

基于特定条件的事物执行——

1.对key添加监视锁:watch key1【key...】

2.取消对所有key的监视:unwatch

注意:必须要在事物开始之前进行watch,如果watch的内容发生了改变,watch后面事物就不会执行了。

 

 分布式锁

使用setnx设置一个公共锁:setnx  lock-key  value

    1.有值返回设置失败,不拥有控制权,排队或等待

    2.设置成功的,拥有控制权,进行下一步具体业务操作。

通过 del  释放分布式锁

 

 防止忘记关锁/redis宕机

  expire lock-key  second

  pexpire  lock-key  milliseconds

锁的时间不要设置过长,锁时间设定推荐:最大耗时*120%+平均网络延迟*110%

 

 

 删除策略


 删除策略:

  1. 过期数据
  2. 数据删除策略
  3. 逐出算法

 

过期数据

  • xx具有时效性的数据
  • -1 永久有效的数据
  • -2 已经过期的数据 或 被删除的数据 或 未定义的数据

 

数据删除策略:定时删除、惰性删除、定期删除

 

定时删除:用时间换空间

  优点:节约内存,到时就删除

  缺点:CPU压力大,无论现在CPU此时的负载高不高,均会占用cpu。

 

惰性删除:(用空间换时间)数据到达过期时间,不做处理。等下次访问数据时:发现未过期,返回数据。

                            发现已过期,删除,返回不存在

优点:节约cpu性能,发现必须删除时才删除。

缺点:内存压力大,出现长期占用内存的数据。

 

定期删除:redis启动服务器初始化时,读取配置server.hz,默认为10

 

每秒钟执行server.hz次serverCron() --> databasesCron()【一个一个检查完】 -->activeExpireCycle()【检查任意一个】

  • activeExpireCycle()对每个expire[*]逐一检测,每次执行250ms/server.hz参数current_db用于记录activeExpireCycle()进入那个expire[*] 执行
    • 对某个expire[*]检测时。随机挑选W个key检测器
      • 如果key超时,删除key
      • 如果一轮中删除的key的数量>W*25%,循环该过程
      • 如果一轮中删除的key的数量<W*25%,检查下一个expire[*],0-15循环。
      • W取值:ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP属性值

 

定期删除:周期性抽查存储空间

  • 周期性轮询redis库中的时效性数据,采取随机抽取的策略,利用过期数据占比的方式删除频度。
  • 特点一:CPU性能占用设置峰值,检测频度可以自定义设置
  • 特点二:内存压力不是很大,长期占用内存的冷数据会被持续清理

 

 

 

 逐出算法


 当数据进入redis中,内存不够了怎么办?(不包含过期数据导致的内存不足)

redis使用内存存储数据时,在执行每一个命令之前,会调用freeMemorylfNeeded 检测内存是否充足,如果不满足新加入数据的最低存储要求,redis要临时删除一些数据为当前指令清理存储空间。清理数据的策略称为逐出算法。

逐出算法不是100%清理出足够的可使用空间,如果不成功则反复执行。当对所有数据尝试完毕后,如果不能达到内存清理的要求,将出现错误信息。

 

最大可使用内存:maxmemory

每次选取删除数据的个数:maxmemory-samples

    选取数据时并不会全库扫描,导致严重的性能消耗,降低读写性能。

删除策略:maxmemory-policy

    达到最大内存后,对被挑选出来的数据进行删除的策略。

 

 

 

 

 

 

修改redis.conf 核心配置文件


 

 

 

 

 

 

 

 

 

 

 

 

面试(企业级解决方案)


 

缓存预热:

 

 

 

 

缓存雪崩:就是瞬间数据量过大,导致对数据库服务器造成压力。

 

 

 

 

 

 

缓存击穿:就是单个高热数据过期的瞬间,数据访问量较大,未命中redis后,发起了大量对同一数据的数据库访问,导致对数据库服务器造成压力。应用策略应该在业务数据分析与预防方面进行,配合运行监控测试与即时调整策略,毕竟单个key的过期监控难度较高,配合雪崩处理策略即可。

 

 

 

 

缓存穿透:缓存击穿访问了不存在的数据,调过来合法数据的redis数据缓存阶段,每次访问数据库,导致对数据库服务器造成压力,

 

 

 

 

 

 

 

 

 

 

 

性能指标监控

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

这篇关于redis的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!