redis原理、安装
<h1>redis安装总结</h1>
<ul>
<li><a href="https://www.bilibili.com/video/BV1go4y1m7Fd?p=6">https://www.bilibili.com/video/BV1go4y1m7Fd?p=6</a></li>
</ul>
<pre><code class="language-shell">yum install wget
cd ~
mkdir soft && cd soft
wget http://download.redis.io/releases/redis-5.0.5tar.gz
tar xf redis-5.0.5tar.gz && cd redis-src
# 看readme.md文件
yum install gcc
make distclean
make
cd src # 生成了可执行程序
cd ..
make install PREFIX=/opt/mashibing/redis5
vi /etc/profile
#编写内容
export REDIS_HOME=/opt/mashibing/redis5
export PATH=$PATH:$REDIS_HOME/bin
#保存文件
cd utils
./install serve.sh # 可执行一次或多次
service redis_6379 start/stop/stauts > /etc/init.d/***</code></pre>
<ul>
<li>一个物理机中可以有多个redis实例(进程),通过端口区分</li>
<li>可执行程序就一份,在目录中,但是内存中未来的多个实例,需要各自的配置文件,持久化目录等资源</li>
</ul>
<h2>redis原理</h2>
<ul>
<li>
<p>处理用户对数据的操作是单进程,单线程,单实例。</p>
<ul>
<li>还有其他操作调用线程,这个些线程和处理用户数据操作没有关系。</li>
</ul>
</li>
<li>多个客户端的一个或多个连接(socket),通过TCP握手,到达linux内核(kemel)</li>
<li>redis进程和linux内核之间使用的epoll模型,非阻塞多路复用I/O,在内存中处理速度非常快</li>
<li>分布式情况下,只能保证每个连接内,是用户操作数据的顺序,在单进程的单线程内,户对数据的操作是按顺序处理的。
<ul>
<li>在分布式情况下,数据的一致性是最头疼问题。</li>
</ul></li>
</ul>
<h2>nginx启动原理</h2>
<ul>
<li>按照多少个CPU启动多少个进程worker</li>
<li>一个worker进程可以把数据压到CPU的一二三级缓存</li>
<li>每个nginx进程,使用多路复用epoll模型</li>
<li>linux内核kemel的epoll,是同步,非阻塞机制下的多路复用</li>
</ul>
<h2>epoll介绍</h2>
<ul>
<li><a href="https://www.bilibili.com/video/BV1go4y1m7Fd?p=7">https://www.bilibili.com/video/BV1go4y1m7Fd?p=7</a></li>
<li>linux内核kemel的epoll,是同步,非阻塞机制下的多路复用</li>
</ul>
<h2>linux man 命令查看几类文档</h2>
<ul>
<li><a href="https://www.cnblogs.com/chenmingjun/p/8352478.html">https://www.cnblogs.com/chenmingjun/p/8352478.html</a></li>
</ul>
<pre><code class="language-shell">man ls # 标准用户命令
man 1 cd # 标准用户命令
man 2 cd # 系统调用命令
man 4 tty # 设备文件</code></pre>
<h2>Linux操作系统中基础的概念</h2>
<h4>用户空间 / 内核空间</h4>
<ul>
<li>现在操作系统都是采用虚拟存储器,对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方)。</li>
<li>操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。</li>
<li>为保证用户进程不能直接操作内核(kernel),保证内核的安全,操作系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间。</li>
</ul>
<h4>进程切换</h4>
<ul>
<li>为控制进程执行,内核必须有能力挂起正在CPU上运行的进程,并恢复以前挂起的某个进程的执行。这种行为被称为进程切换。</li>
<li>任何进程都是在操作系统内核的支持下运行的,是与内核紧密相关的,并且进程切换是非常耗费资源的。</li>
</ul>
<h4>进程阻塞</h4>
<ul>
<li>正在执行的进程,由于期待的某些事件未发生,如请求系统资源失败、等待某种操作的完成、新数据尚未到达或无新工作做等,则由系统自动执行阻塞原语(Block),使自己由运行状态变为阻塞状态。</li>
<li>进程的阻塞是进程自身的一种主动行为,只有处于运行态的进程(获得了CPU资源),才可能将其转为阻塞状态。当进程进入阻塞状态,是不占用CPU资源的。</li>
</ul>
<h4>文件描述符</h4>
<ul>
<li>文件描述符(File descriptor),用于表述指向文件的引用的抽象化概念。</li>
<li>文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。</li>
<li>当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。</li>
<li>在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。</li>
<li>文件描述符这一概念只适用于UNIX、Linux这样的操作系统。</li>
</ul>
<h4>缓存I/O</h4>
<ul>
<li>缓存I/O又称为标准I/O,大多数文件系统的默认I/O操作都是缓存I/O。</li>
<li>在Linux的缓存I/O机制中,操作系统会将I/O的数据缓存在文件系统的页缓存中,即数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。</li>
</ul>
<h2>I/O多路复用(multiplexing)</h2>
<ul>
<li><a href="https://www.jianshu.com/p/397449cadc9a">https://www.jianshu.com/p/397449cadc9a</a></li>
<li>可以理解为事件循环</li>
<li>事件驱动模型,另一个名字是I/O多路复用
<ul>
<li><a href="https://www.zhihu.com/question/28594409/answer/345897182">https://www.zhihu.com/question/28594409/answer/345897182</a></li>
</ul></li>
<li>本质是通过一种机制(系统内核缓冲I/O数据),让单个进程可以监视多个文件描述符,一旦某个描述符就绪(一般是读就绪或写就绪),能够通知程序进行相应的读写操作</li>
<li>与多进程和多线程技术相比,I/O多路复用技术的最大优势是系统开销小,系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销。</li>
</ul>
<h2>Unix五种IO模型</h2>
<table>
<thead>
<tr>
<th>序号</th>
<th>IO模型</th>
<th>同步异步</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>blocking IO</td>
<td>同步</td>
<td>阻塞IO</td>
</tr>
<tr>
<td>2</td>
<td>nonblocking IO</td>
<td>同步</td>
<td>非阻塞IO</td>
</tr>
<tr>
<td>3</td>
<td>IO multiplexing</td>
<td>同步</td>
<td>IO多路复用</td>
</tr>
<tr>
<td>4</td>
<td>signal driven IO</td>
<td>同步</td>
<td>信号驱动IO</td>
</tr>
<tr>
<td>5</td>
<td>asynchronous IO</td>
<td>异步</td>
<td>异步IO</td>
</tr>
</tbody>
</table>
<h2>常用的I/O复用模型</h2>
<ul>
<li>
<p><a href="https://blog.csdn.net/wteruiycbqqvwt/article/details/90299610">https://blog.csdn.net/wteruiycbqqvwt/article/details/90299610</a></p>
</li>
<li>
<p>select,poll,epoll,都是 Linux API 提供的 IO 复用方式。</p>
</li>
<li>
<p>select</p>
<ul>
<li>仅知道有I/O事件发生,并不知道是哪几个流(可能有一个,多个,甚至全部)</li>
<li>只能无差别轮询所有流,找出能读出数据,或者写入数据的流,对他们进行操作</li>
<li>具有O(n)的无差别轮询复杂度,同时处理的流越多,无差别轮询时间就越长</li>
</ul>
</li>
<li>poll
<ul>
<li>poll本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd(文件描述符)对应的设备状态</li>
<li>fd(文件描述符) File descriptor</li>
<li>没有最大连接数的限制,是基于链表来存储的</li>
</ul></li>
<li>epoll
<ul>
<li>可以理解为event poll,就是事件驱动</li>
<li>不同于忙轮询和无差别轮询,epoll会把哪个流发生了怎样的I/O事件通知我们</li>
<li>epoll实际上是事件驱动(每个事件关联上fd)的,对这些流的操作都是有意义的</li>
<li>文件描述符(fd),也就是新来的连接,通过等待事件(事件驱动),放到epoll的共享空间红黑树中,此时等待事件还是阻塞状态。</li>
<li>再通过等待事件,放到链表中,维护这个事件是可写还是可读,返回到用户共享空间中,此时等待事件非阻塞状态。</li>
</ul></li>
</ul>
<h2>select,poll,epoll的区别</h2>
<table>
<thead>
<tr>
<th></th>
<th>select</th>
<th>poll</th>
<th>epoll</th>
</tr>
</thead>
<tbody>
<tr>
<td>操作方式</td>
<td>遍历</td>
<td>遍历</td>
<td>回调</td>
</tr>
<tr>
<td>底层实现</td>
<td>数组</td>
<td>链表</td>
<td>红黑树</td>
</tr>
<tr>
<td>I/O效率</td>
<td>每次调用都进行线性遍历</td>
<td>每次调用都进行线性遍历</td>
<td>事件通知方式,<br />每当fd就绪,系统注册的回调函数就会被调用,<br />将就绪fd放到readyList里面</td>
</tr>
<tr>
<td>时间复杂度</td>
<td>O(n)</td>
<td>O(n)</td>
<td>O(1)</td>
</tr>
<tr>
<td>最大连接数</td>
<td>1024(x86)或2048(x64)</td>
<td>无上限</td>
<td>无上限</td>
</tr>
<tr>
<td>fd拷贝</td>
<td>每次调用select,<br />都需要把fd集合从用户态拷贝到内核态</td>
<td>每次调用poll,<br />都需要把fd集合从用户态拷贝到内核态</td>
<td>调用epoll_ctl时拷贝进内核并保存,<br />之后每次epoll_wait不拷贝</td>
</tr>
</tbody>
</table>