redis 介绍及NIO原理

前言

首先,我们要知道为什么会出现redis,理由是redis是内存数据库,优点就是数据存储读取快。可以用来做缓存,分布式锁,消息队列等。

我们可以看下redis的排名:https://db-engines.com/en/ranking/key-value+store 因为我们知道redis是kv的数据库,我们访问该网站就可以看到redis稳居榜首
在这里插入图片描述

要系统知道redis的知识就需要去看他的官网https://redis.io/(英文网站),国人可以看下http://redis.cn/(中文网)

一、redis和Memcached对比

早些年,Memcached也很火,也很多人用Memcached,但是后面Memcached逐渐被redis给取代了。理由是,redis的value有类型的概念。当然我不是说redis的数据类型很重要,只是我们可以这样想这个问题。Memcached没有数据类型的概念,那比如我往Memcached中存一个list集合对象。而如果我需要取出list集合的第二个数据,那么需要怎么做?Memcached就需要把list整个集合对象返回给客户端,然后客户端将这个对象强转成list集合对象,然后再取出第二个对象。
大家如果仔细想下我刚说的这个过程,你就会发现两个个问题,
第一个是Memcached所在服务需要把整个list集合对象返回给客户端,是不是意味着网络带宽IO增加,因为如果我直接把list集合的第二个对象返回,那么就会减少网络带宽IO的消耗。
第二个,我客户端还需要自己写代码把Memcached返回的数据强转成list集合对象,是不是很麻烦,学过大数据hadoop的人都知道,我们需要计算向数据移动。这样才能提高性能。
综上所诉redis数据存在类型的概念,减少服务端网络IO消耗,并且减少客户端自己强转数据计算向数据移动了。相比Memcached提高性能不少。

二、redis 的IO模型

redis采用的是epoll的网络IO模型,在讲解这个模型之前,我们先来学习下网络IO的发展历程。我们讨论的范围均在linux操作系统上,fd表示file descriptor文件描述符。在linux中一切皆文件包括网络。任何网络IO的出来调用内核只需传入对应网络IO的fd即可。

2.1 BIO

最开始使用的BIO的网络模型,全称是(blocking I/O)阻塞IO。
在这里插入图片描述
由上图可知,我们将网络IO分为内核态和用户态。用户态就是我们开发人员自己写的程序代码。内核态就是操作系统内部系统的程序代码,一般我们是接触不到,能够接触的是他暴露出来的接口,让我们可以进行调用。
从OSI七层模型来划分的话就是下四层(小于等于tcp传输控制层)属于内核态,上面的三层应用层就是用户态。
上面铺垫完,我们接着描述BIO。BIO就是我们写代码通过调用内核暴露出来的接口,如果一直没有数据到达,那么我们自己写的代码就会一直阻塞在这个接口调用上面,其他事情都做不了。
说到这里,大家也知道,这里会产生浪费,因为我代码这个线程一直阻塞,其他事情都不能做。

2.2 NIO

在这里插入图片描述
由于BIO存在浪费的问题,所以出现了NIO(non blocking I/O)非阻塞IO。这个是怎么做的呢?相当于用户态的代码调用内核态查询网络是否有数据到达,内核会立马返回用户有没有数据,如果有数据,那么用户态会调用内核的read方法读取对应数据,这就是NIO多路复用。
NIO解决了BIO阻塞的问题,但是依然有问题,因为用户态相当写了一个while(true)的死循环频繁调用内核查询是否有网络IO到达。频繁的调用内核成本太高。

2.3 SELECT

在这里插入图片描述
select模型是怎么解决NIO频繁调用内核的问题呢?select模型是这么做的,用户态每次把需要获取的网络IO数据的fd传递给select,然后select自己在内核监听到有数据到达后,就会一次性告诉用户态哪些fd有数据了,然后用户态就会再循环调用内核态的read方法获取对应fd的数据。
看起来select 已经很完美了,但是依然存在几个问题
第一,就是用户态和内核态数据拷贝频繁,降低了系统性能。
第二,用户态一次性把需要关注的fd传递给内核,内核自己还需要开辟一个空间来映射用户态的fd,浪费内存空间。

2.4 epoll

在这里插入图片描述
这里引入两个概念,mmap和零拷贝(sendfile),这些都是操作系统内核帮我们做的事情。
第一,mmap是内存地址映射,大白话讲就是用户态的内存地址空间和内核态的内存地址空间做映射关系。比如上图,在用户态的时候我们有个文件描述符epfd,当我们调用内核态将epfd传递进去后,通过mmap技术,内核就和用户态使用同个epfd来监听数据。不会向select模型那样独立在内核开辟个内存空间存epfd
第二,量拷贝的概念是当数据到达内核后,用户态要来拉取数据进行操作,不用在用户态独立在开辟个空间存这些数据,内核态和用户态共享这块内存空间。对应内核态提供的接口是sendfile.

epoll是这样做的,用户态把fd传递给内核态,内核态提供mmap技术,知道用户态需要监听哪些数据。mmap里面主要有两大块,红黑树结构来存fd,链表来存内核监听到哪些fd有数据,用户态一直监听mmap空间中链表,只要有数据把链表中的fd拿出来,再调用内核的read方法读取数据。这里使用零拷贝技术,所以不用把内核空间拷贝到用户空间,性能得到提高。

2.5 redis单线程能够处理这么高的并发

redis是单进程的,有很多线程,但是处理网络IO的线程只有一个,这是因为redis采用epollo的网络IO模型。我们知道网络IO操作的ms级别,内存操作级别是ns级别。中间相差10万倍左右。
除非你能在1秒内达到10万级别的并发量。像双11秒杀的时候,最高是50w/s的并发量,对于普通公司来说,这基本不可能达到这么高的并发,所以是够用的。

总结

redis是典型的kv内存数据库,我们需要对其原理不断研究。这里想说下不是说BIO就一无是处。像mysql的话,他就比较适合BIO阻塞的没网络模型而不要使用epollo。为什么呢?理由是你想下,如果mysql的请求并发上去了,这个时候,你使用epoll,虽然网络请求IO你提速了,但是磁盘IO就是瓶颈了,因为对mysql频繁的读取写入,一般磁盘是撑不住并发量上去的

  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值