今天学习了一点点redis和NIO的知识
先了解到了一些常识,在计算机当中数据是存在磁盘或者内存里的,磁盘有两个指标,寻址的速度是ms毫秒级的,带宽是G或者M级别的,内存的寻址是nm纳秒,在寻址上磁盘比内存慢了十万倍,数据在内存里是优与磁盘的
磁盘有磁道和扇区,一个扇区512字节(byte),这时候就有一个成本问题了,如果都是以最小粒度512来找,那就会有很多512,那我们需要的数据在哪个512里就是个问题,这时候索引的成本就会变大,可能4字节就不够用了,需要有很大的一个区间,才能索引住这么大的范围,所以出现了一个4k对齐,操作系统无论读多少都是最少4k,当数据存在文件里的时候,当数据变大,速度就会变慢,磁盘IO成为瓶颈,这个时候数据库就出现了,数据库的datepage大小正好是4K,当数据库的表里的数据往磁盘里存的时候就用了很多datepage来储存,大小刚好和操作系统能对上,这个时候磁盘读取数据就不用了一个512来读了,直接就可以读4k,减少IO次数,然后就是索引的作用的,索引也是存到datepage里面,当我们单独给某一列设成索引了之后,就单独把那一列存储到索引的datepage里,每一个索引都会指向那一行数据,但是数据量变大,索引占用的资源也会变多,在关系型数据库建表的时候必须给出每一列的类型,每个类型都有对应的字节宽度,这样每个表里的每一行的宽度都定死了,这样有一个好处就是在增删改的时候不用去移动数据,因为每行就是固定的,索引和数据都是存在硬盘当中的,但是当我们查询的时候用到的是在内存里的B+树,内存的速度比硬盘快十万倍,所以在内存准备了b+树,当查询的时候命中索引,就用b+树找到索引,然后把索引从磁盘放到内存解析,然后找到相应的数据的datepage放到内存解析就可以找到相应的数据了,很大程度上减少了IO的次数,分别利用了磁盘的空间大,内存的速度快的特点,这个结构获取数据的速度极快,但是一旦数据量变得特别大,性能就会越来越差,如果表有索引,增删改会变慢,因为索引的位置会发生改变,维护索引的成本就太大了,查询速度要分情况,如果命中了索引,少量查询依然会很快,但是并发量大的时候查询的不同的数据很多,会受硬盘带宽影响速度,那如何解决在并发量大的时候的增删改查的效率问题,这就要用到redis了,需要用到缓存。
Redis
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。 这是redis官方的描述,用的是k,v键值对来存储数据,上面说的多种类型指的是value的类型,还有一个软件叫memcached,他也是键值对储存,但是value是没有类型的,需要用json来储存,但是客户端想通过缓存系统取回v当中的某一个元素,如果是json储存需要返回所有的数据,客户端自己还要写代码去解码json,而redis不仅有类型,每种类型还有对应的方法来获取数据,这就是计算向数据移动,一个获取一大堆数据需要自己来解码,一个只需要调用方法获取想要的少量数据,这就是他们的区别,也是memcached逐渐没落的原因,接下来安装redis。
官网有链接,我把链接直接放上来了
http://download.redis.io/releases/redis-6.0.6.tar.gz
先yum install wget插件下载下来,就可以用上面的连接下载了
下载完解压,tar xf指令,解压完进去,然后make指令,发现报错了提示缺少c语言编译器
1、安装gcc套装:
yum install cpp
yum install binutils
yum install glibc
yum install glibc-kernheaders
yum install glibc-common
yum install glibc-devel
yum install gcc
yum install make
2、升级gcc
yum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
scl enable devtoolset-9 bash
3、设置永久升级:
echo “source /opt/rh/devtoolset-9/enable” >>/etc/profile
然后make distclean,因为编译过程中报错会有一些残留文件,直接make会接着报错,所以要先删除再make
安装完成后回到redis目录用 make install PREFIX=自定义目录这个指令
然后去soft目录,在bin目录下
然后cd redis源码
然后去utils目录
打开这个文件vi /etc/profile
把这两条配置信息加到最后
export REDIS_HOME=/opt/mashibing/redis5
export PATH=
P
A
T
H
:
PATH:
PATH:REDIS_HOME/bin
加完保存再输入下面两条
source /etc/profile
echo $PATH
然后./install server.sh
然后一堆回车就安装完成了
service redis_6379 status启动服务
然后用redis install命令添加redis系列指令
可以用ps -fe | grep redis查看进程
redis是单线程,单进程,单实例的,那么在并发情况下是如何变得很快的呢,当客户端来了链接,所有的连接会先到内核,tcp握手,这时候redis和内核之间使用的是epoll(非阻塞多路复用),知识点什么是epoll?
BIO:
最开始我们的内核只有read命令,客户端会跟内核链接,进行tcp三次握手之后,如果连接成功建立,双方就可以通过套接字进行通信。连接成功后,双方通过输入和输出流进行同步阻塞式通信。
简单的描述一下BIO的服务端通信模型:建立连接之后会有对应的线程/进程(java中是线程,linux中是进程)来read这个文件描述符,tcp三次握手会创建socket,这个socket就是文件描述符,但是socket在这个时期是阻塞的,在read的时候如果数据包没到,那这个线程就要一直等着阻塞着,这时候如果有另外的连接就要创建更多的线程来处理,并且如果只有单颗cpu的话每一个时间片上只能有一个线程在运行,那就算其他线程的数据到了也无法处理,所以整个cpu其实并没有一直在处理真正到达的数据,造成了资源浪费,而且线程更多的话也很耗费成本,这就是早起的BIO
NIO:
BIO调用的read,NIO时期就可以调用Socket方法了,Socket方法有一个type参数,有一个type是nonblock,就是非阻塞的,不阻塞了就不需要创建其他线程,单线程就可以,并且可以创建个循环来read文件描述符,检测文件描述符是否有数据,没有数据就接着read其他文件描述符,这个轮循发生在用户空间,因为是单线程,接收和处理都是这一个线程,所以是同步的,这就是同步非阻塞时期NIO
多路复用NIO
如果NIO出现了非常多的文件描述符,那进程轮循的时候就要调用非常多次的内核,在用户态查询一个文件描述符就是一个系统调用,频繁的内核态和用户态的切换,造成了很大的成本,那么如何减少这个成本,这时候就需要内核向前发展,在内核增加了一个系统调用select,每一个连接就是一个文件描述符,进程可以直接把获取到的所有的文件描述符统一的发给内核,内核进行select,对就绪的文件描述符进行标记,然后把描述符再返回给进程,进程检查哪些文件描述符被标记就绪,然后把标记好的文件描述符再read传出去,这样就可以减少内核态和用户态的切换,但是本质还是同步非阻塞。
epoll
上面的模式,还是比较麻烦,需要先给内核,然后内核再把数据返回给线程,线程自己还要有一个空间来放这些文件描述符,传给内核的时候,内核也需要一个空间来拷贝这些文件描述符,那直接创建一个共享空间让内核和进程都可以访问,也不需要内核再去拷贝,这就是一个新的调用MMAP,当有这个共享空间之后,在里面放一个红黑树,一个链表,用户空间把所有的文件描述符往到共享空间的红黑树里放,然后内核来判断哪些文件描述符的数据到达了,然后把到达的文件描述符放到链表里,用户空间发现链表有数据了就可以取出,然后再read出去, mmap结合sendfile(零拷贝)就是kafka技术,先用mmap共享空间接收网卡传来的数据写到文件里,然后用sendfile技术把文件的数据传给消费者。
这就是redis为什么单线程单进程单实例也会这么快的原因,而且因为是单进程单线程所以他是有“顺序”的,是按照每个链接内的命令顺序来处理