java进阶--数据库篇(Redis)

 如有不足,还望指正,不胜感激,共同学习进步。。

                                   

目录

Redis

Redis是什么?

Redis的应用场景

Redis数据类型

String(字符串)

hash(哈希)

list(列表)

set(集合)

zset(有序集合)

Redis常见问题

雪崩

穿透

击穿

Redis优缺点

优点:

缺点:

Redis持久化

RDB:

AOF:

哨兵模式


Redis

Redis是什么?

        Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

Redis的应用场景

        缓存、消息队列、分布式锁、计数器、排行榜、点赞签到打卡、计数器、限流等

Redis数据类型

        Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

String(字符串)

        string 是 redis 最基本的类型,你可以理解成与 Memcached 一模一样的类型,一个 key 对应一个 value。

        string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象。

        string 类型是 Redis 最基本的数据类型,string 类型的值最大能存储 512MB。

        redis 127.0.0.1:6379> SET jt "江涛博客"
        OK
        redis 127.0.0.1:6379> GET jt
        "江涛博客"

        在以上实例中我们使用了 Redis 的 SET 和 GET 命令。键为 jt,对应的值为 江涛博客

注意:一个键最大能存储 512MB。

hash(哈希)

        Redis hash 是一个键值(key=>value)对集合。

        Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。

        DEL jt  删除前面测试的key,报错"(error) WRONGTYPE Operation against a key holding the wrong kind of value"

        redis 127.0.0.1:6379> HMSET jt field1 "Hello" field2 "World"
        "OK"
        redis 127.0.0.1:6379> HGET jt field1
        "Hello"
        redis 127.0.0.1:6379> HGET jt field2
        "World"

        实例中我们使用了 Redis HMSET, HGET 命令,HMSET 设置了两个 field=>value 对, HGET 获取对应 field 对应的 value

        每个 hash 可以存储 232 -1 键值对(40多亿)。

list(列表)

        Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。

        redis 127.0.0.1:6379> lpush runoob redis
        (integer) 1
        redis 127.0.0.1:6379> lpush runoob mongodb
        (integer) 2
        redis 127.0.0.1:6379> lpush runoob rabbitmq
        (integer) 3
        redis 127.0.0.1:6379> lrange runoob 0 10
        1) "rabbitmq"
        2) "mongodb"
        3) "redis"

        列表最多可存储 232 - 1 元素 (4294967295, 每个列表可存储40多亿)。

set(集合)

        Redis 的 Set 是 string 类型的无序集合。

        集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。

        sadd 命令

        添加一个 string 元素到 key 对应的 set 集合中,成功返回 1,如果元素已经在集合中返回 0。

        redis 127.0.0.1:6379> sadd runoob redis
        (integer) 1
        redis 127.0.0.1:6379> sadd runoob mongodb
        (integer) 1
        redis 127.0.0.1:6379> sadd runoob rabbitmq
        (integer) 1
        redis 127.0.0.1:6379> sadd runoob rabbitmq
        (integer) 0
        redis 127.0.0.1:6379> smembers runoob

        1) "redis"
        2) "rabbitmq"
        3) "mongodb"

        注意:以上实例中 rabbitmq 添加了两次,但根据集合内元素的唯一性,第二次插入的元素将被忽略。

        集合中最大的成员数为 232 - 1(4294967295, 每个集合可存储40多亿个成员)。

zset(有序集合)

        Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。

        不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。

        zset的成员是唯一的,但分数(score)却可以重复。

        zadd 命令

        添加元素到集合,元素在集合中存在则更新对应score

        zadd key score member 
        redis 127.0.0.1:6379> zadd runoob 0 redis
        (integer) 1
        redis 127.0.0.1:6379> zadd runoob 0 mongodb
        (integer) 1
        redis 127.0.0.1:6379> zadd runoob 0 rabbitmq
        (integer) 1
        redis 127.0.0.1:6379> zadd runoob 0 rabbitmq
        (integer) 0
        redis 127.0.0.1:6379> ZRANGEBYSCORE runoob 0 1000
        1) "mongodb"
        2) "rabbitmq"
        3) "redis"

Redis常见问题

        redis缓存雪崩、穿透和击穿

雪崩

        雪崩就是指缓存中大批量热点数据过期后系统涌入大量查询请求,因为大部分数据在Redis层已经失效,请求渗透到数据库层,大批量请求犹如洪水一般涌入,引起数据库压力造成查询堵塞甚至宕机。

解决办法:

  1. 将缓存失效时间分散开,比如每个key的过期时间是随机,防止同一时间大量数据过期现象发生,这样不会出现同一时间全部请求都落在数据库层,如果缓存数据库是分布式部署,将热点数据均匀分布在不同Redis和数据库中,有效分担压力,别一个人扛。
  2. 简单粗暴,让Redis数据永不过期(如果业务准许,比如不用更新的名单类)。当然,如果业务数据准许的情况下可以,比如中奖名单用户,每期用户开奖后,名单不可能会变了,无需更新。

穿透

        穿透是指查询一个不一定存在的key,由于缓存是不命中时被动写的,并且处于容错考虑,如果从存储层查不到的数据不写入缓存,导致缓存没有任何意义,在高并发的时候很容易给DB带来压力,有可能会导致挂掉。举个例子,一秒钟有5000个请求,其中有4000个都是黑客发来的恶意请求,这4000个恶意请求缓存查不到DB也查不到,很可能会造成损失。

 解决办法:

  1. 常见的办法就是采用布隆过滤器,将所有可能存在的数据hash到一个bitmap中,一个一定不会存在的key一定会被bitmap拦截掉。
  2. 如果存储层返回null值也将这个结果写入到缓存中,并且设置一个较短的过期时间,在缓存失效前再有请求可以直接从缓存中拿数据

击穿

        缓存击穿,就是说某个 key 非常热点,访问非常频繁,处于集中式高并发访问的情况,当这个 key 在失效的瞬间,大量的请求就击穿了缓存,直接请求数据库,就像是在一道屏障上凿开了一个洞。

 解决办法:

  1. 使用互斥锁,在缓存失效的时候不是立即请求DB,而是先使用缓存工具的某些带返回成功操作的工作去set一个mutexkey,当返回成功是再进行请求DB并且回设缓存,否则重试。
  2. 永远不过期,将热点数据不设置过期时间

Redis优缺点

优点:

  • 读写性能优异, Redis能读的速度是110000次/s,写的速度是81000次/s。

  • 支持数据持久化,支持AOF和RDB两种持久化方式。

  • 支持事务,Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性执行。

  • 数据结构丰富,除了支持string类型的value外还支持hash、set、zset、list等数据结构。

  • 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。

缺点:

  • 数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。

  • Redis 不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。

  • 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性。

  • Redis 较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。为避免这一问题,运维人员在系统上线时必须确保有足够的空间,这对资源造成了很大的浪费。

Redis持久化

RDB:

        是Redis DateBase缩写快照,RDB是Redis默认的持久化方式。按照一定的时间将内存的数据以快照的形式保存到硬盘中,对应产生的数据文件为dump.rdb。通过配置文件中的save参数来定义快照的周期。       

优点:

  • 1、只有一个文件 dump.rdb,方便持久化。

  • 2、容灾性好,一个文件可以保存到安全的磁盘。

  • 3、性能最大化,fork 子进程来完成写操作,让主进程继续处理命令,所以是 IO 最大化。使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 redis 的高性能

  • 4.相对于数据集大时,比 AOF 的启动效率更高。

缺点:

  • 1、数据安全性低。RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候)

  • 2、AOF(Append-only file)持久化方式:是指所有的命令行记录以 redis 命令请 求协议的格式完全持久化存储)保存为 aof 文件。

AOF:

        AOF持久化(即Append Only File持久化),则是将Redis执行的每次写命令记录到单独的日志文件中,当重启Redis会重新将持久化的日志中文件恢复数据。

        当两种方式同时开启时,数据恢复Redis会优先选择AOF恢复。

优点:

  • 1、数据安全,aof 持久化可以配置 appendfsync 属性,有 always,每进行一次 命令操作就记录到 aof 文件中一次。

  • 2、通过 append 模式写文件,即使中途服务器宕机,可以通过 redis-check-aof 工具解决数据一致性问题。

  • 3、AOF 机制的 rewrite 模式。AOF 文件没被 rewrite 之前(文件过大时会对命令 进行合并重写),可以删除其中的某些命令(比如误操作的 flushall))

缺点:

  • 1、AOF 文件比 RDB 文件大,且恢复速度慢。

  • 2、数据集大的时候,比 rdb 启动效率低。

哨兵模式

        哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。

这里的哨兵有两个作用

  • 通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器。

  • 当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机。

        然而一个哨兵进程对Redis服务器进行监控,可能会出现问题,为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。

今天就先写到这,如有帮助,可收藏点赞+关注哦ღ( ´・ᴗ・` )。。。

你的鼓励是我创作的最大动力ღ( ´・ᴗ・` )

你可能感兴趣的:(数据库,Redis,数据库,redis,java)