Redis分布式集群实战(一)——基础知识(Redis入门知识点)

一、Redis概述

1.1 什么是Redis?

redis是一个高性能的、开源的key-value数据库,而且redis是一个NOSQL类型数据库(非关系型的数据库),是为解决高并发、高扩展,大数据存储等一系列的问题而产生的数据库解决方案,它还可以用作:数据库、缓存和消息中间件。但是,它也不能替代关系型数据库,只能作为特定环境下的扩充。

redis是一个以key-value存储的数据库结构型服务器,它支持的数据结构类型包括:字符串(String)、链表(lists)、哈希表(hash)、集合(set)、有序集合(Zset)等,也被人们称为数据结构服务器。为了保证读取的效率,redis把数据对象都存储在内存当中,它可以支持周期性的把更新的数据写入磁盘文件中 。而且它还提供了交集和并集,以及一些不同方式排序的操作。

1.2 为什么要使用Redis?

平常做Web小项目时都是直接使用mysql等数据库,在磁盘上进行数据的存取,由于一般的系统任务中通常不会存在高并发的情况,所以没什么问题,但是一旦涉及大数据量的需求,比如商品抢购使得主页访问量瞬间极大的时候,如果仅仅使用数据库来保存数据,会因为磁盘读/写速度太慢而造成数据库系统瘫痪。

项目中使用Redis的目的,主要从性能和并发两个角度去考虑的:

  • 性能:在碰到需要执行耗时特别久,且结果不频繁变动的SQL,就特别适合将运行结果放入缓存,这样,后面的请求就去缓存中读取,请求使得能够迅速响应。
  • 并发:在大并发的情况下,所有的请求直接访问数据库,数据库会出现连接异常。这个时候,就需要使用的的Redis的做一个缓冲操作,让请求先访问到的Redis的的,而不是直接访问数据库。

Redis的优势和特点

  1. redis数据读写速度非常快,Redis能读的速度是110000次/s,写的速度是81000次/s ,因为它把数据都读取到内存当中操作,而且redis是用C语言编写的,是最“接近“”操作系统的语言,所以执行速度相对较快。
  2. redis虽然数据的读取都存在内存当中,但是最终它支持数据持久化到磁盘当中,即可以将内存中的数据异步写入到硬盘中,同时不影响继续提供服务。
  3. redis提供了丰富的数据结构
  4. redis的所有操作都是原子性,支持事务,所谓的**原子性就是对数据的更改要么全部执行,要么全部不执行**。
  5. redis支持主从复制,主机会自动将数据同步到从机,可以进行读写分离

1.3 NoSQL 技术

当任务存在高并发涉及大数据量的需求,比如天猫双11、抢红包、抢演唱会门票时候,单一使用数据库来保存数据的系统会因为面向磁盘,磁盘读/写速度比较慢的问题而存在严重的性能弊端,一瞬间成千上万的请求到来,需要系统在极短的时间内完成成千上万次的读/写操作,这个时候往往不是数据库能够承受的,极其容易造成数据库系统瘫痪,最终导致服务宕机的严重生产问题。

为了克服上述的问题,项目通常会引入NoSQL技术,这是一种基于内存的数据库,并且提供一定的持久化功能RedisMongoDB是当前使用最广泛的NoSQL,而就Redis技术而言,它的性能十分优越,可以支持每秒十几万此的读/写操作。

  • MySQL(关系型数据库)需要把数据存储到库、表、行、字段里,查询的时候根据条件一行一行地去匹配,当查询量非常大的时候就很耗费时间和资源,尤其是数据是需要从磁盘里去检索
  • NoSQL(非关系型的数据库): 存储原理非常简单(典型的数据类型为k-v),不存在繁杂的关系链,不需要像mysql那样需要找到对应的库、表(通常是多个表)以及字段。
NoSQL数据可以存储在内存里,查询速度非常快。
NoSQL在性能表现上虽然能优于关系型数据库,但是它并不能完全替代关系型数据库。
NoSQL因为没有复杂的数据结构,扩展非常容易,支持分布式

1.4 Redis的应用

  • 存储 缓存 用的数据;
  • 需要高速读/写的场合使用它快速读/写

1、缓存

在日常对数据库的访问中,读操作的次数远超写操作。当我们使用SQL语句去数据库进行读写操作时,数据库就会去磁盘把对应的数据索引取回来,这是一个相对较慢的过程。

如果我们把数据放在 Redis 中,也就是直接放在内存之中,让服务端直接去读取内存中的数据,那么这样速度明显就会快上不少,并且会极大减小数据库的压力,但是使用内存进行数据存储开销也是很大的,限于成本的原因,一般我们只是使用 Redis 存储一些常用和主要的数据,比如用户登录的信息、热点新闻、门户主页面等。

扫描二维码关注公众号,回复: 9248093 查看本文章

一般而言,在使用 Redis 进行存储的时候,我们从以下几个方面来考虑:

  • 数据常用吗?命中率如何? 如果数据不常用,缓存命中率很低,就没有必要写入缓存;
  • 是读操作多,还是写操作多? 如果写操作多,频繁需要写入数据库,也没有必要使用缓存;
  • 数据大小如何? 如果要存储几百兆字节的文件,会给缓存带来很大的压力,这样也没有必要;

2、 Redis 读操作逻辑

在这里插入图片描述

  1. 当第一次读取数据的时候,读取 Redis 的数据就会失败,此时就会触发程序读取数据库,把数据读取出来,并且写入 Redis 中;
  2. 当第二次以及以后需要读取数据时,就会直接读取 Redis,读到数据后就结束了流程,这样速度就大大提高了。

3、Redis 写操作逻辑

在这里插入图片描述

可见写操作不仅要写入数据库,还要同时写入Redis,因此如果写次数远大于读次数那么就没有必要使用 Redis。

4、高速读/写(只使用Redis,事后再更新数据库)

高并发的情况为了追求极致的速度,只读写Redis,等高并发请求结束后再将Redis上的数据同步到数据库中,此时,一次请求操作的流程图如下:
在这里插入图片描述

  1. 当一个请求到达服务器时,只把业务数据在 Redis上进行读写,而没有对数据库进行任何的操作,这样就能大大提高读写的速度,从而满足高速响应的需求
  2. 但是这些缓存的数据仍然需要持久化,也就是存入数据库之中,所以在一个请求操作完 Redis 的读/写之后,会去判断该高速读/写的业务是否结束,这个判断通常会在秒杀商品为0,红包金额为0时成立,如果不成立,则不会操作数据库;如果成立,则触发事件将 Redis 的缓存的数据以批量的形式一次性写入数据库,从而完成持久化的工作。

1.5 缓存穿透、缓存击穿、缓存雪崩

1、缓存处理流程

前台请求,后台先从缓存中取数据,取到直接返回结果,取不到时从数据库中取,数据库取到更新缓存,并返回结果,数据库也没取到,那直接返回空结果。
在这里插入图片描述

2、缓存穿透

缓存穿透:缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大,流量大时数据库会挂掉。

解决方案:

  • 接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
  • 从缓存和数据库中没有取到,这时也可以将key-value对写为key-null(空值),缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击

3、缓存击穿

缓存击穿:一个存在的key,在缓存过期的一刻,此时有大量的请求,同时读缓存没读到数据,又同时去数据库去取数据,这些请求就击穿到DB,造成瞬时DB请求量大、压力骤增。

解决方案:

  • 设置热点数据永远不过期。
  • 加互斥锁

4、缓存雪崩

缓存雪崩:缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机

解决方案:

  • 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
  • 如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。
  • 设置热点数据永远不过期。

1.6 Redis读写使用单线程+多路I/O复用模型

原因:

  • redis是基于内存的,内存的读写速度非常快(纯内存)。
  • redis是单线程的,解决了数据存储的顽疾 数据并发安全,还省去了很多上下文切换线程的时间(避免线程切换和竞态消耗)
  • redis使用多路复用技术,可以处理并发的连接(非阻塞IO)。

在mysql等数据库技术中需要进行磁盘I/O,等待I/O时间很长,应该把CPU让给其他线程进行存取,所以用多线程存取效率更高。而redis不需要磁盘I/O,性能瓶颈不在CPU而在内存大小和网络带宽上,因此用单线程+多路复用技术足够了。

1、并发安全

多个并发体在同一段时间内访问同一个共享数据,共享数据能被正确处理。
并发不安全的后果:
举个例子:卖票超售,设想有一家电影院,有两个售票窗口,售票员售票时候先看一下当前剩余票数是否大于0,如果大于0则售出票。此时票数剩下一张票,两个售票窗口同时来了顾客,两个售票人都看了一下剩余票数还有一张,不约而同地收下顾客的钱,余票还剩一张,但是却售出了两张票,就会出现致命的问题。

如何做到并发安全

最主流的办法就是**加锁**,其实售票的整个操作同时间内只能一个人进行,在我看来归根到底加锁其实就是让查询和售票两个步骤原子化,只能一块执行,不能被其他程序中断,让这步操作变成串行化。

2、锁

锁:就是每次进入这段变量共享的程序片段,都要先获取一下锁,如果获取成功则可以继续执行,如果获取失败则阻塞,直到其他并发体把锁给释放,程序得到执行调度才可以执行下去。锁本质:就是让并发体创建一个程序临界区,临界区一次只能进去一个并发体

读锁与写锁

读锁也叫共享锁,写锁也叫排它锁,锁的概念被发明了之后,人们就想着如果我很多个并发体大部分时间都是读,如果变量读取的时候也要建立临界区,那就大题小做了。于是人们发明了读锁,一个临界区如果加上了读锁,其他并发体执行到相同的临界区都可以加上读锁,执行下去,但不能加上写锁。这样就保证了可以多个并发体并发读取而又不会互相干扰。

3、切换上下文

线程每次执行需要把数据从主内存读到工作内存,然而当线程被调度到阻塞的时候,这些工作内存的数据需要被快照到线程上下文中,其实就是一个记录各个线程状态的存储结构,等到线程被唤醒的时候,再从上下文中读取,称之为上下文切换;减少上下文切换操作,也是使用单线程的奥妙

4、多路 I/O 复用

当一个请求来访问redis后,redis去组织数据要返回给请求,这个时间段,redis的请求入口不是阻塞的,其他请求可以继续向redis发送请求,等到redis io流完成后,再向调用者返回数据,这样一来,单线程也不怕会影响速度了

  • 多路:指的是多个网络连接
  • 复用:指的是复用同一个线程

1.7 Redis 的过期策略和内存淘汰机制

1、过期策略

Redis 采用的是 定期删除+惰性删除 策略,删除过期key。

定期删除指redis默认每隔100ms随机抽取一些设置了过期时间的key,检查其是否过期,如果过期就删除。

但是,定期删除可能会导致很多过期key到了时间并没有被删除掉,所以就得靠惰性删除了。

惰性删除key过期的时候不删除,每次从数据库获取key的时候去检查是否过期,若过期,则删除,返回null。

但是实际上这还是有问题的,如果定期删除漏掉了很多过期key,然后你也没及时去查,也就没走惰性删除,此时会怎么样?
大量过期key堆积在内存里,导致redis内存块耗尽,此时我们就需要内存淘汰机制了。

2、内存淘汰机制

volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰

volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰

allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰

allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰

noeviction:禁止驱逐数据,当内存使用达到阈值的时候,所有引起申请内存的命令会报错

设置方式

config set maxmemory-policy volatile-lru

1.8 Redis实现的技术

  • 持久化:持久化是最简单的高可用方法(有时甚至不被归为高可用的手段),主要作用是数据备份,即将数据存储在硬盘,保证数据不会因进程退出而丢失。
  • 复制:复制是高可用Redis的基础,哨兵和集群都是在复制基础上实现高可用的。复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复。缺陷是故障恢复无法自动化;写操作无法负载均衡;存储能力受到单机的限制。
  • 哨兵:在复制的基础上,哨兵实现了自动化的故障恢复。缺陷是写操作无法负载均衡;存储能力受到单机的限制。
  • 集群:通过集群,Redis解决了写操作无法负载均衡,以及存储能力受到单机限制的问题,实现了较为完善的高可用方案。

二、 Mysql和Redis数据库的区别

mysql:关系型数据库,主要用于存放持久化数据,将数据存储在硬盘中,读取速度较慢。
redis:非关系型数据库(NoSQL),也是缓存数据库,即将数据存储在缓存中,缓存的读取速度快,能够大大的提高运行效率,但是保存时间有限

  • 类型上:

mysql是关系型数据库,redis是缓存数据库

  • 作用上:

mysql用于持久化的存储数据到硬盘,功能强大,但是速度较慢

redis用于存储使用较为频繁的数据到缓存中,读取速度快

  • 速度上:

redis的速度:单机读可达10000次/s 写可达5000/s

mysql 经过了这么多年优化 才1000次/S,500次/S

  • 需求上:

mysql和redis因为需求的不同,一般都是配合使用。

三、Memcached和Redis对比

对比内容 具体阐述
性能 平均每一个核Redis在存储小数据时比Mencached性能更高,100k以上时Mencached性能高于redis
内存空间和数据量大小 Memcached可以修改最大内存,采用LRU算法,Redis增加了VM的特性,突破了物理内存的限制
操作方便性 Memcached结构数据单一,仅用来缓存数据,而Redis支持更丰富的数据类型,也可以在服务器端进行丰富的操作,这样可以减少网络IO次数和数据体积
可靠性 Memcached不支持数据持久化,断电或重启后数据消失,但其稳定性是有保证的,Redis支持数据持久化和数据恢复,允许单点故障,但是同时也会付出性能代价
应用场景 Memcached:动态系统中减轻数据库的负担,提升性能,作缓存,适合多读少写,大数据量的情况。Redis:适合于对读写效率要求都很高,数据处理业务复杂和对安全性要求较高的系统
单个key-value的大小 Memcached最大支持1MB。Redis最大支持512MB
  • redis支持更丰富的数据类型(支持更复杂的应用场景):Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储。memcache支持简单的数据类型,String。
  • Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用,而Memecache把数据全部存在内存之中
  • 集群模式:memcached没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据;但是 redis 目前是原生支持 cluster 模式的。
  • Memcached是多线程,非阻塞IO复用的网络模型;Redis使用单线程的多路 IO 复用模型

在这里插入图片描述

发布了125 篇原创文章 · 获赞 25 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/ranrancc_/article/details/103112857