Redis(十)--关于redis的一些常见问题

Redis(十)–关于redis的一些常见问题

这篇博客的内容主要包括:

  • 1,redis的线程模型是什么?
  • 2,memcached的相关知识:
  • 3,那你为什么选择Redis的缓存方案而不用memcached呢(memcached与redis有什么区别)
  • 4,为什么单线程的redis比多线程的memcached效率要高?
  • 5,使用过Redis分布式锁么,它是怎么实现的?
  • 6.使用过Redis做异步队列么,你是怎么用的?有什么缺点?
  • 7.Redis的并发竞争key问题如何解决?
  • 8,redis的并发上限?
  • 9,redis官方为什么不提供windows版本?
  • 10.redis如何做内存优化?
  • 11,若redis正在给线上的业务提供服务,那使用keys指令会有什么问题?
  • 12,单线程的redis如何利用多核的CPU?
  • 13,为什么redis需要把所有数据放入到内存中

1,redis的线程模型是什么?

Redis确实是单进程单线程的模型,因为Redis完全是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章的采用单线程的方案了(毕竟采用多线程会有很多麻烦)

==>Redis是单线程的,为什么还能这么快吗?

第一:Redis完全基于内存,绝大部分请求是纯粹的内存操作,非常迅速,数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度是O(1)。

==>Redis将所有数据放在内存中,非数据同步正常工作中,是不需要从磁盘读取数据的,0次IO。内存响应时间大约为100纳秒,这是Redis速度快的重要基础

第二:数据结构简单,对数据操作也简单。
第三:采用单线程避免了不必要的上下文切换和竞争条件,不存在多线程导致的CPU切换,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有死锁问题导致的性能消耗
第四:使用多路复用IO模型,非阻塞IO

–>I/O多路复用实际上是指**多个连接的管理可以在同一进程。多路是指网络连接,复用只是同一个线程**。在网络服务中,I/O多路复用起的作用是一次性把多个连接的事件通知业务代码处理,处理的方式由业务代码来决定

在I/O多路复用模型中,最重要的函数调用就是I/O 多路复用函数,该方法能同时监控多个文件描述符(fd)的读写情况,当其中的某些fd可读/写时,该方法就会返回可读/写的fd个数。

在这里插入图片描述
Redis使用epoll作为I/O多路复用技术的实现,再加上Redis自身的事件处理模型将epoll的read、write、close等都转换成事件,不在网络I/O上浪费过多的时间。实现对多个FD读写的监控,提高性能。

在这里插入图片描述

举个形象的例子吧。比如一个tcp服务器处理20个客户端socket。

A方案:顺序处理,如果第一个socket因为网卡读数据处理慢了,一阻塞后面的都完了。。。

B方案:每个socket请求都创建一个分身子进程来处理,不说每个进程消耗大量系统资源,光是进程切换就够操作系统累的了。

C方案(I/O复用模型,epoll)将用户socket对应的fd注册进epoll(实际上服务器和操作系统之间传递的不是socket的fd而是fd_set的数据结构),然后epoll只告诉哪些需要读/写的socket,只需要处理那些活跃的、有变化的socket fd的就好了。这样,整个过程只在调用epoll的时候才会阻塞,收发客户消息是不会阻塞的

2,memcached的相关知识:

(1)memcached的介绍:

memcached是一个自由、源代码开放,高性能分布式的内存对象缓存系统,用于动态web应用以减轻数据库的负载。她通过在内存中缓存数据和对象来减少数据库的次数,从而提高了网站访问速度

memcached是一个存储键值对的hashmap,在内存中对任意的数据(比如字符串,对象等)所使用的key-value存储,数据可以来自数据库调用,API调用,或者页面渲染的结果。

(2)memcached的工作原理:

由于它的工作机制是在**内存中开辟一块空间,然后建立一个hashtable**,memcached管理这些hashtable,所以,速度非常快。

(3)memcached的作用:

使用memcached的网站一般流量是比较大的,为了缓解数据库的压力,让memcached**作为一个缓存区域,把部分信息保存在内存中,在前端能够迅速的进行读取**。那么一般的焦点就是集中在如何分担数据库压力和进行分布式,毕竟单机的memcached的内存容量是有限的。

(4)memcached的设计思想:

  • 简单key/value存储:服务器不关心数据本身的意义及结构,只要是可序列化数据即可。存储项由“键、过期时间、可选的标志及数据”四个部分组成;
  • 功能的实现一半依赖于客户端,一半基于服务器端:客户端负责发送存储项至服务器端、从服务端获取数据以及无法连接至服务器时采用相应的动作;服务端负责接收、存储数据,并负责数据项的超时过期;
  • O(1)的执行效率. O(1)的标准:恒定不变, o(1)特性使得10000个连接和1个连接的查询速度是一样的。 (memcached依赖于libevent实现从而实现O(1))
  • 清理超期数据:默认情况下,Memcached是一个LRU缓存,同时,它按事先预订的时长清理超期数据;但事实上memcached不会删除任何已缓存数据,只是在其过期之后不再为客户所见;而且,memcached也不会真正按期限清理缓存,而仅是当get命令到达时检查其时长

==>缓存与数据库如何保持同步
在service层新增,修改和删除操作时,将更改的数据写入数据库,并将操作的数据在缓存中标记,等待下次读取时再从数据库中加载到缓存中

(5)memcached的使用场景:

在动态系统中减少数据库负载,提升性能,做缓存,适合多读少写大数据量的情况(如大量查询用户信息、好友信息、文章信息等)。它的一个**总原则是将经常需要从数据库读取的数据缓存在memcaced中**,这些数据也分为几类:

  • 经常被读取并且实时性要求不强可以等到自动过期的数据。例如网站首页最新文章列表、某某排行等数据。也就是虽然新数据产生了,但对用户体验不会产生任何影响的场景。这类数据就使用典型的缓存策略,设置一过合理的过期时间,当数据过期以后再从数据库中读取。当然你得制定一个缓存清除策略,便于编辑或者其它人员能马上看到效果。
  • 经常被读取并且实时性要求强的数据。比如用户的好友列表,用户文章列表,用户阅读记录等。这类数据首先被载入到memcached中,当发生更改(添加、修改、删除)时就清除缓存。在缓存的时候,我将查询的SQL语句md5()得到它的 hash值作为key,结果数组作为值写入memcached,并且将该SQL涉及的table_name以及hash值配对存入memcached中。 当更改了这个表时,我就将与此表相配对的key的缓存全部删除。

(6)不适用场景:

  • 缓存对象的大小大于1MB;
  • key的长度大于250字符(可以把一些key先md5再存储);
  • 应用运行在不安全的环境中Memcached为提供任何安全策略,仅仅通过telnet就可以访问到memcached。如果应用运行在共享的系统上,需要着重考虑安全问题;
  • 业务本身需要的是持久化数据。

3,那你为什么选择Redis的缓存方案而不用memcached呢(memcached与redis有什么区别)

  • 存储方式上memcache会把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。redis有部分数据存在硬盘上,这样能保证数据的持久性
  • 数据支持类型上:memcache对数据类型的支持简单,只支持简单的key-value,,而redis支持五种数据类型
  • 使用底层模型不同:它们之间底层实现方式以及与客户端之间通信的应用协议不一样。redis直接自己构建了VM机制,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。
  • value的大小:redis可以达到1GB,而memcache只有1MB。

4,为什么单线程的redis比多线程的memcached效率要高?

  • redis支持更丰富的类型(支持更复杂的场景):redis不仅仅支持简单的K/V类型的数据,同时还提供list、set、hash、zset、string等数据结构的存储,memcached支持简单的数据类型string
  • redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用,而memcached把数据全部放入内存中
  • 集群模式:memcached没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据,但redis目前是原生支持cluster模式的
  • memcached是多线程,非阻塞IO复用模型,redis使用单线程的多路IO复用模型

5,使用过Redis分布式锁么,它是怎么实现的?

先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放

==>问?如果在setnx之后执行expire之前进程意外crash或者要重启维护了,那会怎么样?

这样的话,锁就得不到释放了,但是好像set指令有非常复杂的参数,这个应该是可以同时把setnx和expire合成一条指令来用的

==>下面是比较详细的解释:

redis实现分布式锁基于setnx命令,因为在redis中key是保证唯一的,所以当多个线程同时创建setnx时,只要谁能够创建成功谁就能获取到锁。

  • set命令:每次set时,可以修改原来的旧值
  • setnx命令:每次setnx检查key是否已经存在,若已经存在就不会执行任何操作,返回0,反之,新增该key
  • 获取锁的时候:当多个线程同时创建setnx key,只要谁能够创建成功谁就能够获取到锁
  • 释放锁:可以对该key设置一个有效期可以避免死锁的现象。

6.使用过Redis做异步队列么,你是怎么用的?有什么缺点?

一般使用list结构作为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试

==> 问?可不可以不用sleep呢?
答:list还有个指令叫blpop,在没有消息的时候,他会阻塞住直到消息到来

==>问?能不能生产一次消费多次呢?
答:使用pub/sub主题订阅者模式,可以实现1:N的消息队列。

==>问?pub/sub有什么缺点呢?
答:在消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如rabbitmq等。

==>问?redis如何实现延时队列?
答:使用sorted set(也就是有序集合),拿时间戳作为score,消息内容作为key调用zadd来生产消息,消费者用zrangebyscore指令获取N秒前的数据轮询进行处理

缺点:

消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如rabbitmq等。

7.Redis的并发竞争key问题如何解决?

这个问题的意思是大概是:同时有多个子系统去set一个key。

答案:

  • (1)若对这个key操作,不要求顺序。这种情况下,准备一个分布式锁,大家去抢锁,抢到锁就做set操作即可,比较简单。

  • (2)若对这个key操作,要求顺序。如:key1-value1,key2-value2,key3-value3,期望按照这个顺序key1-value1,key2-value2,key3-value3变化,这种时候我们在数据写入的数据库的时候,需要保持一个时间戳,假设时间戳如下:

    系统A key1{value1 3:00}
    系统B key1{value2 3:05}
    系统C key1{value3 3:10}
    若系统B先抢到锁,将key1设为{value2 3:05},接下来系统A抢到锁,发现自己的value1的时间戳早于缓存中的时间戳,那就不做set操作了,以此类推。

  • (3)其他方法,比如利用队列,将set方法变成串行访问也可以

8,redis的并发上限?

上限来自于你的 redis可以使用的内存大小(假如redis有三个节点,每个节点可使用的最大1G内存,那你的缓存的上限小于3G。)

9,redis官方为什么不提供windows版本?

因为目前linux版本已经相当稳定,而且用户量很大,无需开发windows版本,反而会带来兼容性问题。

10.redis如何做内存优化?

尽可能使用散列表(hashes),散列表(是说散列表里面存储的数少)使用的内存非常小,所以,你应该尽可能的将你的数据模型抽象到一个散列表里。比如你的web系统中有一个用户对象,不要为这个用户名称,姓氏,邮箱,密码设置单独的key,而是应该把这个用户的所有信息存储到一张散列表里面。

11,若redis正在给线上的业务提供服务,那使用keys指令会有什么问题?

因为redis是单线程的,keys命令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕服务才能恢复。这时可以使用scan指令,scan指令可以无阻塞的提供出指定模式的key列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接使用keys指令长。

12,单线程的redis如何利用多核的CPU?

因为redis是单线程,所以同一时刻只有一个操作在进行。所以耗时的命令会导致并发的下降。==>可以启动多个实例,组成master-master或master-slave或cluster,这样的话就可以使用多核的CPU

13,为什么redis需要把所有数据放入到内存中

redis为了达到最快的读写速度将数据都读入内存中,并通过异步的方式将数据写入磁盘。所以redis具有快速和数据持久化的特征。若不将数据放入内存中,磁盘IO速度会严重影响redis性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值