欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

马哥 44_01 _nginx【攻城狮论坛の免费分享】有大用

Nginx:

IO模型:

        阻塞,当一个进程所发出的IO请求不能得到满足的时候,它必须要一直等待至对方响应的数据已经准备好了,内核一定要把这个数据从IO设备复制到内核缓冲区,再从内核缓冲区复制给这个进程的地址空间以后,才能返回的,而在这期间,我们的进程必须处于等待状态,

        非阻塞,当向内核发出系统调用之后,调用某一个IO之后,它不在那里等待,而是一遍一遍再过来轮询看对方准备好了没有,(非阻塞这种方式是不是性能很差?)

        同步,计算机通信有两种方式,同步和异步,讲drbd的时候,也讲过同步方式,异步方式,(drbd同步,发一个数据必须要等到对方确认以后,对方必须收下来,并且完完整整存储下来之后,才返回)(drbd异步,数据扔出去就不管了,至于对方什么时候收到,什么时候接下来,什么时候进行存储,我们都不管了),,,mysql复制的时候也讲过同步和异步,(mysql异步,我们只需要把数据存在二进制日志文件里面来,什么时候发给从节点,我们是不管的,,,什么时候复制过去,是不是比我们落后,我们是不关心的,,,如果从硬件方面来讲,双方不需要同步时钟信号的??????)(同时是双方必须要同步时钟信号的????????)

        异步,



同步和阻塞是两码事,所以我们有同步阻塞,同步非阻塞,异步阻塞,异步非阻塞几种模型


同步阻塞:

异步阻塞:IO复用

异步阻塞:基于事件驱动的IO  event-driven,,,,,,,也是异步阻塞的一种,,,,,,只不过是前半段不阻塞,后半段阻塞

同步非阻塞:很少用到,性能很差

异步非阻塞: aio 纯粹的异步模型,


如下图,现在有两个设备要进行通信,从左向右发了一连串的010101代码过来,如果不是基于报文的方式来进行发送,而是直接在一个物理设备连接上信号发过来(所谓的机算机通信无非就是发一系列的高电频,低电频),你怎么知道对方发的是1还是0,,比如0.5伏是高电频,0伏是低电频,几个高电频,几个1,必须在时钟频率上取得同步,我们必须工作在同样的时钟频率下,比如时钟频率是1GHz,意味着指的是让1秒/1GHz,就是一个信号,所以它是以时间来评判到底走了多少个1,走过了多少个1秒/1GHz,就是多少个1,所以双方必须要同步时钟信号,不然右边就不能知道左边发过来几个1,,,,,,,,


image.png

如下图,基于IP报文的发送其实就是异步的,我们把包发出去之后,什么时候到达对方,我们没有管过,,,,到对方之后,对方解码,解包之后,知道是什么信号,,,,,为什么呢??因为它自己为了能够实现异步通信,必须要在每一个数据报文之前,加一个协议报文,告诉你,这里面的报文是如何组织的,这个信号是怎么理解的,,,,IP报文事实还是基于物理的异步或同步通信的,,,比如基于以太网的mac地址通信,在两个物理设备之间通信,仍然是同步的或异步的,最终,它们仍然会转化为最底层的同步或异步通信,,,现在的同步或异步机制很多时候已经用在比物理连接更高一级的层次上了,主要是用来判定通信的双方在实现通信的时候,是不是要跟对方建立连接关系,并等待对方能够完完整整的将数据接受下来而等待对方响应的这么一种机制,我们叫做同步,,,异步报文就是我们将数据报文丢上去,就不管你了,至于你什么时候收到,什么时候处理,什么时候响应,那是你的事情,我们不再做关心,

image.png




image.png



1)是同步阻塞

2)是同步非阻塞,性能差,很少用到,,,它的后半段也是阻塞的

3)的中间这一段是不阻塞的,但是每一段是阻塞的



image.png

同步非阻塞指的是 O_NONBLOCK,性能差,很少用到


Nginx:

    支持mmap

    支持event-driven:

            一个进程(一个线程)响应多个请求,进程是单线程进程,内存占用率低,对内存的需求量比apache要小得多,尤其比apache的prefork进程内存小得多 (apache的 prefork,虽然是一个进程响应多个请求,但是一个进程里面是每个线程响应一个请求)

    支持aio


LEMP

    Enginx (FastCGI)+ php-fpm,它不像apache一样,可以基于模块来跟php通信的

nginx 可以与 php-fpm 不在同一个服务器上,

如下图

image.png


如下图

每一个请求,连接进来了(是php文件),我们的nginx发现处理不了,它要转交给后端的php-fpm,在它转交给php-fpm之前,这个连接怎么办?这个连接不能断开,这个nginx连接始终在这里,对nginx进程来讲意味着nginx要维持一段内存空间,里面保存着这个连接的相关信息,(比如说客户端是谁,什么时间连进来的,以及客户端的端口是什么,等等,都需要用一个区域来保留的,,,用户连接请求发进来的时候,是有请求报文的,所以请求数据有可能需要暂存一下的,,我要把里面的数据读进来,读进来之后,分析一下http首部是什么,使用哪种方法请求的,请求的是哪一个资源,发现是php资源,还需要向php-fpm进行转发),转发之后,当,php-fpm返回结果给nginx,,,直到最后nginx里面装着客户端所要求的结果,nginx就构建响应报文,,,,,,,我们又知道基于TCP连接的时候,事实上是两个连接,一个是客户端发,服务器端收(只读管道),,,,,,另一个是服务器端发,客户端收(写管道),,,,,,,所以这是两个不同的管道,,,,,,,,,,,,所以缓冲区两个,一个叫接收缓冲区,一个叫发送缓冲区,,,,,,,,这两个缓冲区可以叫做会话缓冲区,这都是需要内存来维持这些会话信息的,

当一个客户端连进来了,nginx发现所请求的内容是动态的,不是本地能处理的,它就要向后面php-fpm转发,在转发的期间内,客户端都要处于等待状态,而当nginx对背后的应用程序(我们的php)将结果回送过来之后,


image.png

如下图图一,php-fpm把结果给nginx,,,1)把结果缓存一下,交给会话缓冲区,2)直接发送给会话缓冲区  如下图图二,后面的php-fpm自己封装结果都有响应报文,它封装的响应报文通过fast-cgi协议,给我们的前端nginx,,,,如果说客户端自己能够理解fasts-cgi报文的话,那么php-fpm传一位给nginx,nginx传一位给客户端,客户端就直接收到一位了,,,,也就意味着我们的客户端所收到的报文直接来自于fast-cgi服务器的报文,这种通信过程我们称为同步的,我们的nginx实现了透明转发,,,,,,,,,,,,,,,,,,,,,但是很显然,客户端很难理解fast-cgi协议,意味着fast-cgi服务器的响应,只有完完全全送给我们的nginx服务器之后,nginx拆了,再二次封装成为客户端能够理解的方式,因为客户端请求的是http格式,所以nginx要封装为http这种客户端能够理解的方式再回送给客户端,意味着php-fpm所响应的报文,得先接受下来,得先暂存到服务器本地才行,这得又需要内存空间,暂存下来之后,再重新二次封装,再往会话缓冲区里面发,这种方式是异步的,,,,,,,,,,,,(我只是做一个简单的牵线,在直接通信的双方之间,就能够完成数据传输的,这叫同步)  (我牵了线之后,负责将对方的请求暂存下来,如果需要向后端发送,是我自己往后发的,而不是将请求直接送到另一端,,我在中间负责协调员的角色,这叫异步)


图一

image.png

图二

image.png


我们能够将客户端所请求的内容在本地缓存下来,这个速度会快很多,比如说我们的php所处理的结果,第一个用户请求的结果与第二个用户请求的结果是一样的,如下图,,,,,,假如我把第一个用户所请求的内容,他请求的一个php页面,是个主页,而这个主页对大多数用户来讲是一样的,,,,这个主页没有做成静态的方式,于是第一个用户请求进来了,不是直接将用户的请求转发至后端,如下图图一,而是检查本地缓存中有没有,(我这里有个缓存空间),,,,,,如果没有,我们再重新封装请求报文发给cgi服务器,当发给cgi服务器返回过来之后,我们先缓存到本地,然后再封装一个响应报文给客户端,,,,当第二个客户端来请求的时候,一检查缓存,有内容,而且缓存没过期,就直接返回给客户端了,,,正是通过这种异步模型加本地缓存的机制,,,,使得你会发现这样一种情形,前端nginx接进来的时候,发现有1000个连接,但是fastcgi上看到的连接可能只有50个,,,,,,,,如下图图二,,,,,,,这样一来,就大大降低了后端服务器本身所面临的压力,而后端的动态服务器本身,它所能够处理的连接,它的更高的或者说更多的能力是处理动态请求上,,,,,,,,,,我们就通过这种方式把两种角色(nginx和php-fpm)分开,让每一个模块只负责它最擅长的事情,就达到了我们整个系统优化的目的,,,,如果某一天,我们这一台服务器实在抗不住的时候,就可以把这两种角色分开了

图一

image.png

图二

image.png


如下图,于是我们就可以实现在前端做一个nginx,后端做一个php服务器(应用程序服务器,在网站架构设计中,我们称为 app server ),,,,,,,用户的请求到达nginx,由nginx处理所有请求,所有会话都由nginx来建立连接,如果需要维持这个会话的话,也是由nginx使用自己的内存来维持,,,,,,,,,(nginx,淘宝给的一个统计数据,维持10000个非活动连接,即inactive连接,只需要2.5M左右),,,,,,如果把请求直接交给app server,也就是说app server既能够响应web请求??????,又能够处理动态内容的话,,,,,,,那这样子,它本身可能需要为每个连接建立的时候,都需要一个单独的进程,而每个进程,光进程自己自身的开销,可能都需要达到2M左右了,所以它对资源的占用率是非常大的,,,,,,这就是为什么要它们各司其职,来负责一个专门的功能的主要原因,

image.png


前端面临1千个请求,后端某一个app server 可能只有50个, app server 里面所处理的执行程序,都是动态请求,是不是每一个程序都得需要处理数据的,(我们的程序主要是由指令加数据组成的,很多现在的程序都要处理数据的,,所以再后面需要依赖于数据库,用数据库来专门实现数据存储的),如下图,,,,,,假如我们的数据量不是很大,默认情况下,可以把数据库和 app server 放在一起,,,,但是 app server  和数据库软件一般来讲,都是cpu密集型的,(Cpu bound),它们两个对cpu的占用量特别的大,过一段时间之后,如下图,随着连接的增长,前端有5000个了,分发到后端每一个服务器上大概有100个(一个服务器假如只能承受100个),而这100个请求里面,它需要执行大量的程序,还需要查询数据库,,,,就这100个,我们的服务器还抗不住,那该怎么办?那我们把 app server 和 数据库分开,让它们各司其职, app server 如果需要用到内容的话,都要向后端去查询数据库就可以了,但是需要注意的是,如果它俩在同一个主机上,网络连接传输的速度非常快,如果不在同一台主机上,那中间传输数据需要消耗大量的时间,,,那为什么要把app server与数据库分开呢?因为很多时候当前端有5000个请求的时候,一个app server 已经不足以响应了,,,,,假如一个app server 只能承载100个请求,而前端有5000个请求,由nginx转发至后端(假设后端5个app server)大致有500个,那么一个app server就不能满足需要了,就需要5台app server服务器了,5台app server服务器都需要处理数据,那么数据应该保证它们是共享的,所以这就需要一个专门的mysql服务器了,,,,,,,如果说我们需要用到一个共享的 mysql 服务器,那并不是每一个app server所执行的动态请求都需要与数据库打交道的,有些程序执行逻辑在本地就能执行完成,,,,,,,,所以这100个请求里面,可能只有30个需要数据库查询,70个在本地,它只是程序运行逻辑中的内容,不需要与数据库打交道的,,,,就算30个,这五台服务器加起来,就100多个了(150个),,,,一个mysql数据库如果面临大量的读写请求的话,如并发处理 50 个(能每秒 tps 50个,,,,,,,,当然只是普通的pc服务器,如果是另外很强的服务器当然不止50个了,如果数据库设计得好的话,也不止50个,,,,,,,,但一般来讲50-100个是比较常见的这种逻辑,尤其是查询量查询逻辑比较大的话)就不错了,,,,,只能处理50个怎么办?mysql读写分离,我们可以对它做一台从服务器,让一台mysql专门负责写,另一台专门负责读,,,,,再不够,再加一台从就可以了,,,,,但是很多时候,我们的前端的查询量????都是一样的,(前端所查询的内容很多都是一样的),,,,,,,,很多用户登录进来之后,他们所访问的页面,( web 服务器某些个页面总是最受欢迎的),,,所以有些数据可能被反反复复的访问到,如果每次都访问到,都要去查询数据库的话,也不合理,,,,,,,,,所以要将查询的结果缓存下来,,,,,,,,,那该怎么办????假如说有一个交换机,大家都连到交换机上来了,我们还可以使用memcached服务器(memcached本身仅仅是能够提供缓存功能的服务器,所以到底缓不缓存,谁来缓存,怎么缓存,缓存什么时候过期,什么时候清除等等,memcached自身是不管的,,memecached只不过是根据你的请求来帮你做出决策,)( 所以 app server 通过我们的某一个mysql服务器查到的结果,它觉得结果可以缓存,是程序自己把结果缓存到memcached, 下一次程序去找数据的时候,到memcached上去找)(以后每个app server再去查询数据的时候,先去查询memcached,如果memcached没有的话,就联系一个数据库,读过来之后,缓存到memcached,再向客户端响应),,,,所以 memcached 叫做公共缓存(很多节点都可以用,缓存的数据也可以被多节点共同使用的缓存),,,,其实memcached这个组件,加进来之后,它能够大大的提升我们系统的性能的,只要缓存命中率做的足够好的话,这性能提升是非常明显的,,,,,,,


image.png


如下图互联网时代,有句话叫做缓存为王,因为缓存下来的内容是静态的,它的处理逻辑可能在有限的几个cpu时候周期内(比如说3个周期)就能完成,可为了执行一次mysql查询,可能30个时钟周期都完成不了,,,,,,,,,所以这种速度提升的非常快,,,如果我们的命中率特别高,能达到40%左右, 对整体性能的提升都是非常明显的,


image.png


如下图,我们有了 memcached ,可以实现让后端查询的数据缓存下来,供多个app server使用的,,,但是我们还要考虑另外一种情况,就是以一个单个的 app server为例,当某一个用户的请求被发送到第一个app server上,它请求的是一个动态内容,这个app server由于是一个php服务器, php服务器本身所执行的任何一个程序代码得先编译成 op code ,编译以后才能执行的,,,,,当第二个用户请求同样的页面的时候,它仍然需要重新编译 op code,,,,,,,,因为在同一个连接中,我们的opcode


image.png


如下图,我们的app server,以fastcgi方式工作的时候,它是为每一个连接生成一个fastcgi进程的,因此第一个请求,用第一个进程响应,第一个进程编译的op code代码,这个编译的结果只能为第一个进程所使用,所以第一个进程用户的请求,如果多次请求同一个内容的话,op code 缓存下来,就有意义了,,,,,,,但是我们的前端nginx发起第二个请求,第二个请求也在同一个app server上,很显然它使用第二个进程来响应,第二个进程一般来讲不能使用第一个进程的op code,,,,,,,,op code 无法在多个进程之间缓存,要想能够缓存,我们使用xcache,,,,,,,,就是同一个app server上为多个进程之间(或者让多个不同的处理机制)来使用同一个op code缓存,,,,,很显然,编译过程是最消耗cpu时间的,,,,,,,,, 既然第一次编译下来以后,我们能够缓存下来,供其它进程使用,这速度又提升了,,,这就是xcache机制的作用,,,,,memcached,xcache同样都是提供缓存,但是提供缓存的意义是不一样的,,,,,opcode编译完以后,这是一个程序,这个程序一执行,它可能需要查询数据的,所以这个程序编译成op code以后,才需要跟后端交互的,

image.png


如下图,如果前端用户的请求比较多,不管怎么讲,我们最终如果用户请求的内容本地没有的话,都是转交给 app server的,假如有一个 app server 挂了,此前的用户连接被转交给这个 app server 了,(如果我们是一个电商站点的话,每一个app server本身为了维持用户购物车等各种http会话信息,它结合cookie,在我们的应用程序本地服务器要维护一个 session 信息,每一个客户连接都要维护一个session,)    很显然,如果一个客户端第一次请求的时候,我们转交给第5个 app server ,下一次再次请求,我们转交到第1个app server,此前的会话就不能用了,,,,为了能够让此前的会话继续使用,,,,,,,,我们可以使用持久连接,让来自于同一个客户端的请求始终被发到同一个  app server 上来,这样子它此前的会话就一直有效了,但是假如第5个app server挂了,它里面的会话就没有了,,,,,,这个时候客户端用户一刷新,那么这个请求就被发到其它的 app server 上了,这个时候会话信息必然都没有了,,,,,,,,所有持久连接固然可以实现让同一个客户端的请求定向到同一个server上来,使得它的会话可以继续使用,但是由于这个 app server 本身如果出现故障,导致它的会话信息会丢失的,,,,,如果我们有5万个连接,在5台 app server上,那么1台 app server 坏了,就会丢失了1万个连接,,,,,,,,,,,,,,,,


image.png


如下图,如果我们能够实现在各个app server之间共享会话信息,那么任何一个app server挂了,也不会丢失会话信息了,,,,,如果这几个app server可以建一个集群,它的会话信息在内存中直接往上同步????用户请求,请求第一个app server,这个app server在建立会话以后,直接把这个会话通过我们的高可用集群同步到同一集群内的其它任意一个节点,就可以了,,,,,但是这样一来,会有额外的开销,因为这意味着每一个 app server 所建立的会话都需要通过组播的方式通知其它的app server,如果app server不多的话,问题不大,,,,如果有20个app server,每一次都要这样同步,这数据量就有点太大了,,,,,,,所以在小规模中,这种集群机制,确实是可以使用的,但是在很大规模中,不甚理想,

image.png


所以我们可以使用缓存机制,见下图,使用一个公共区域来保存会话信息,而让每一个应用程序服务器可以到这个公共区域上去读这个会话信息,,,,,,,,,,,它的会话信息都是保存到本地的(当然 app server 所运行的机器的内存当中,进程自己的内存当中),由于是自己的内存,只能被 app server 自己所访问,所以只能被当前自己这个app server所使用,,,,,,,,,,,如果我们期望多个app server可以共享会话,怎么办?既然是保存会话,无非是保存在内存当中,如果保存在别的地方的内存当中,是不是就可以了???memcached正是这么一个服务器,所以用户的请求第一次被发到 app server 上的时候,app server需要给这个用户建一个会话,这个会话数据它不再保存到本地了,为了持久,我们的php通常是保存到本地的文件系统上的某个目录下的(以便以后每次进行读取),而且内存中也有一份的,,,,干脆,我们别保存在本地了,我们直接保存在memcached当中,(通过我们的app server请求一下,让memcached给我们缓存下来),,后期哪怕同一个用户通过第二个app server访问的时候,第二个app server会自动的从memcached中找它的相关的会话信息,(因为memcached的 session???中已保存了这个用户的会话信息,)(因为客户端每次访问都会发cookie的,app server根据它的cookie信息,就能够找到对应的session,把这个session读过来,跟用户建立会话???,那么用户的数据本地就有了)

image.png


如下图,但是这样一来,风险就更大了,如果memcached挂了,那么所有的会话信息就全挂了,此时,需要对memcached做高可用,但是memcached中所保存的都是缓存信息,(缓存数据不是关键性数据,它是读取的原始数据),,,所以memcached这样假设,你保存在我这儿的数据都是缓存,都是非关键性的,我这里就算是崩溃了,丢了,你无非就是重建而己,我这里不会使用高可用的,,,,所以memcached本身不支持高可用,,,,想它保存在memcached中的会话信息更可靠的话,得自己想办法解决问题...........我们固然可以把memcached建成高可用服务器,,,,,,,但是事实上,高可用意义并不大,因为它的数据是保存在内存当中的(除非你解决memcached两个进程之间能够通过内存将第一个memcached的缓存通知给另外一个memcached),,,,,,,,,,虽然memcached对高可用的支持并不是很理想,但是memcached也可以实现分布式的功能,也就意味着如果一个memecached不够用的话,你可以做多个memcached,这是memcached的强项,

image.png


如下图,所以 app server 在存数据的时候,可以挑其中一个 memcached 服务器来存,回头我们找数据的时候,还找同一个memcached服务器,,,,,,,,,我们怎么知道是同一个memcached服务器呢?我们需要根据一定的算法来找,,,,,比如说每一个用户建立会话的时候,它可能都有cookie,对cookie可以给它做hash运算,hash运算以后,我们再去除以3,取余,,,,,,,,它的hash结果是一定相同的,除以3,取余的结果也一定是相同的,,,,当然有各种算法,除以3,取余只是一种算法而已,


image.png


memcached 不但能够缓存 app server 从mysql中查询过来的数据,还能够缓存会话,,,所以有人把 memcached 称为万金油,在缓存能力上,它是一个万金油,它也被称为一个银弹??????它能够应付各种情况和场景,只要你需要缓存,而且缓存的是可序列化数据,它都能够实现给你缓存下来,,,,,,什么数据是可序列化数据呢?比如字符串String,各种对象object,(我们的网络所发送的报文都是0 1代码,我发一张图片,图片是什么格式?无论是什么数据,最后都会被抽成一根线,通过网络发送出去的,,只要最终被能够抽成一根线,发到对方,对方还能合并起来,还原成原来的样子的这种数据,我们都称为可序列化数据)(不能序列化的数据,就无法在内存中存储,更别提怎么去传送了),,,,,当然并非所有的数据都是

可序列化的,,,,,,,,,一般来讲,我们的memcached所能够存储的数据通常都是可序列化的数据,就算你能够存图片,也得先把图片转化成字符以后,才能存储,,,当然我们的httpd协议本身就可以转化的(把图片转化成字符串????)


image.png


如下图,缓存的方法,就是在内存中开辟一个很小的区域,每一个缓存对象都需要一个小区域,把数据存下来,将来我们这里缓存了1千万个对象,从这1千万中找其中某1个,怎么找?(我们mysql中查找数据,怎么找的,一定有一个搜索码,我根据哪一个标准去查找,比如我根据姓名=jerry,查找jerry的其它信息,年龄,性别等)从这1千万中找其中某1个,怎么找? 一个一个扒拉扒拉的找,太慢了,,,,它是一个键值存储,key:value存储,它去存储某一个数据的时候,要先给这个数据建一个查找键key,,,,,,,,然后再去存储它的value,,,,,,,,key:value存储通常都是基于hash的方式来存储的,,,,,,,也就意味着,它每存每一个key的时候,这个key本身也需要一个地方去存储,key存储在叫做hash桶(bucket)当中,,,,,,,,那么每一个key到底存在哪个桶里面,可能有n个桶,比如每个桶里面存有100个key,将来我们要去找其中某一个key的话,我们怎么办?作一个hash运算, (hash都有hash函数,做一下运算以后,程序会马上找到你在哪一个桶里面存储),,,找到桶之后,因为桶里面的数据少,在这个桶里面可以快速做一下字符串比较,,,,,,还有可以再二次做一下计算????,立马可以找到那个键了,,,,所以基于这种方式查找,它的速度是非常快的

而且就算有1千个键和1千万个键,有什么区别?1千个键,无非就是从某个桶里面找一次,1千万,无非也是找某一个桶,hash函数计算完之后,它一定会直接定向到桶上面去的,,,,,,所以就算有1千万个缓存对象,和1千个桶的缓存对象,它从中找一个键的速度是一样的,所以这是O(1)的查找思路????要想理解hash算法怎么实现,后门会有一期课,讲mysql索引的,到时会讲hash索引到底是怎么实现的,,,,现在有这个概念就行,,,, hash索引的查找速度是非常快的,,,,我们的memcached就是基于这种方式来存储的,所以它的查找几乎都是O(1)的??????? 速度都是无与伦比的快,无论你存储多少个对象,当然存储太多也不好,就算是O(1)的,也不能过多,因为我每存一个对象,我都是要开辟创建内存,对象过期了,我都得内存回收,,,,,,,,,不同的场景需要的缓存,它的空间是不一样的, 第一次给个2k的内存作缓存,第二次3k,第三次6k,第四次8k,第五次几个字节的,过一会儿你会发现,删了建,建了删,内存中全是缝隙,也就是所谓的碎片了,内存可能会碎片化的,为了避免内存碎片,我们必须要有很好的内存管理策略,这个管理策略需要一定的算法,这个算法就是一个程序,,,,这个程序本身需要不定期的去执行,它的执行就需要消耗cpu时间的,,,所以它(内存管理策略)???的执行每一次都需要这个cpu参与执行的话,都需要额外的开销,,,,,,,,,因此内存的分配和回收,如果你只有一个,十个,百个,都不是大问题,问题是一千万的时候,你的内存需要随时释放和回收,这也是不小的工作

image.png

因为我们并不建议在memcached中缓存过大的数据,如下图,,,,memcached在缓存的时候,它的每一个可缓存对象最大的空间不支持超过1M, 默认最小空间限定只有48个字节,(不能存太小了,一个字节都往里面存,我都要开辟一次内存,创建一个内存数据结构,都不合理,),,,,,,,,,,,,,memcached是C/S架构的,我们的客户端就是应用程序,应用程序请求到memcached里面缓存数据,也就是说应用程序通过协议把数据通过网络传递给memcached服务器,memcached 服务器根据客户端的请求把数据存下来,所以应用程序(或者我们的客户端)可以向我们的服务器端请求不同的指令,,,,,,比如存数据(存缓存,建立缓存),清除缓存,在缓存中附加新数据等等,它有很多的命令,,,,,,讲到安装memcached的时候,再来细细解说一遍, 它到底该怎么工作的,,,,,

各位应该知道,memcached就是这么一个工具,就是一个万金油似的工具,只要你是要存储键值对这一类数据的话,它都可以存,,,,但是有些数据可能不仅仅是键值的,,,,比如存储一个用户信息,有用户名,年龄,性别,身高,还有他到我们的网站上今天浏览了多少个贴子,这些都要记录下来的的,,,,我们为了记录这些信息,该怎么记录?以用户名为键,用户-30(表示年龄),用户-30(表示浏览的贴子数),这个前面的应用程序怎么区别?,,,,,所以仅有键值的这些数据可能无法应付我们的有些场景的需求,因此 memcached 固然很有用,很简单,很高效,但是在有些场景,它应付不过来,尤其是在一个对象下存储多个数据的时候,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,

如果我们可以把多个键值组合在一块,给它起个名,来自定义一个数据结构,会更好一点,如下图,比如有这样一种服务器,当它需要存一个缓存数据的时候,这个服务器能够给我们开辟一个对象,这个对象给它起个名,假如叫张三,它里面是一大堆键值对,里面有很多属性,比如年龄,性别,,,,这里面还都是键值对,年龄(键),对应一个值,,,,性别(键),对应一个值,给这个大对象也做成键值对,对象起个名,叫键,,对象自身所存的数据(本身在内存中所存的数据)叫值,,,,这样子可以存储复杂的数据结构了,,,,象这种可以存储列表的数据结构,像有些服务器就可以提供这种类似的功能,叫做(可能用得比较多的,有很多种,像redis就是提供这种功能的),,,,,,,,它能够存储比memcached更复杂的数据结构,可以提供类似于数据库的功能,它可以存储n个这样的对象,这是张三这个对象,那是李四,王五,这个对象...................每一个用户都有自己的相关数据,你会发现,这每一行数据(姓名,性别,年龄)是独立存储的,,,张三这个人只有年龄和性别,将来又创建一个对象,这个对象里有年龄,性别和浏览贴子的数量,还有家乡地址,,,,随时都可以,,,,mysql也行,只不过每一个字段都要事先建立好,用不着就给它空着,会白白浪费空间的,况且它又不是键值查找的,,,,,我们有了redis这种方式,而且redis把数据直接存在内存里面,它可以过一段时间同步到磁盘上去,也可以实现持久存储的,,,,这跟memcached不一样,memcached是不能持久存储的,,,,所以需要用到复杂数据结构的时候,需要向一个对象存储更多键值数据的时候,我们就可以用到redis了,,,,,,,,,,,,到底用memcached还是redis,要看实际需求,越简单越好,如果只需要进行键值存储,仍然是memcached首选,否则就使用redis,,,,,当然redis只是一种解决方案,,,,,redis本身既能够将这些数据,存到内存里面,还可以保存到磁盘里面,可以使用持久存储,而且保存的数据每一个数据都是一个单独的数据对象,不像memcached仅仅是键值对,,,,,,redis从道理上来讲,是一个database,是个数据库,这种数据库叫做NoSQL,,,,,,,,因为它的数据库不能支持基于sql语句来查找,select来查找,可以使用别的方式来查找,比如NoSQL自己所独有的客户端,它支持自己的查询语句,查询命令,,,,,,,,,而且它所能够存储的数据对象,也是比较独特的,,,,redis精确来讲,与马哥刚刚描述的是有出入的,马哥只是为了简单的能够帮助我们理解问题的,,,,,我们不能把memcached归类到NoSQL里面,因为memcached本身只是个键值存储而已,,,,假设我们用了redis了,有了redis以后,我们服务器功能进一步增强了,而且能够快速的存储很多计数器了,,,,像redis只能存储有限的数据结构?????,就算能持久存储,它也是非结构化数据,所以在使用起来很不方便,,因此通常我们需要一些持久存储,而且将来,我们需要做一些数据挖掘工作的时候,还是仍然需要存储在关系型数据库里面,,,,在有限的时间内,NoSQL取代不了关系型数据库,虽然NoSQL在一些设计上很牛,,,,,,,,,所以NoSQL通常被用来实现某一些特定领域的应用,NoSQL是一种技术,事实上它是一类技术,而不是一种技术,它不像我们的rdbms或者关系型数据库,无论是oracle或者mysql,只要是关系型数据库,概念是一样的,,,,但是NoSQL不是,NoSQL可能有各种各样的类别,,,,,比如它有文档数据库,有图片数据库,有类似于存储键值的像redis这样的数据库,它们还是各种不同类型的数据呢,它们的应用场景是各有不同的,,,,,马哥会找个时间介绍一下常用的NoSQL当中,常用的主流技术,有哪些类别,而每一种技术它的适用场景,或者它最适用在哪个地方,,,,无论哪一种数据库,它们完全可以组合起来,为同一种应用提供功能,,,,比如键值库,可以存储session,可以存储后端数据库的缓存数据,,,,,而我们的redis,用来存储计算器,,,,假如是微博或论坛站点,当前这个微博被转发了多少次,被评论了多少次,这些数据随时需要更新,每次更新都存在mysql里面,那么mysql的压力太大了,因为这种写操作太多了,,,,,所以它们各自有各自的适用领域,,,,,,可能这些技术是揉合起来同时使用的,,,,,,,一个架构师的作用就是揉合,首先,你用哪一种应用来解决问题,其次,这种应用依赖于哪一种硬件????,所以你要服务器选型,我们要用到多少种这种硬件,所以你要做性能评估????,,,,,,,,,,,由此我们既能够存储session缓存数据了,又能够存储计数器了,好像我们的应用程序服务器在一定的程度上都能抗得住了,,,,nginx虽然将动态内容转交给app server上来,但是我们整个网站应用当中,除了动态内容之外,还有很多静态内容,将来我们要根据这个思路设计架构的.

image.png








普通分类: