从性能角度看系统架构

系统架构

  漏斗原理:请求在网络传输过程当中,越日后,请求慢慢的会减小,因此说到数据库服务器的请求量会比在Web服务器的少css

 

1、基本架构

一个系统的网络拓扑图:咱们常说的服务器是软硬件结合的一个概念,服务器服务器,只有硬件没软件其实不能称之为一个完整的服务器java

 

 

 

一个问题:什么是 to B ,什么是  to C?nginx

  有些人可能会说,B就是browser,C就是Client。可是实际上真的是如此么???web

  其实C就是面向用户,好比说淘宝、QQ、饿了么、美团、大众点评等对咱们我的来说,就是个 to C 的产品,客户端;可是,面向商家的就是 to B(bussiness) 端 ,好比淘宝有商家平台,B不是说一个浏览器,好比说QQ,是个客户端。redis

  

 

  基本的系统架构就是上图,可是当咱们的请求加多,日活增多,请求会发到哪里???其实第一步是打在了网络上!因此网络加速发展了,可是最终的请求量所有打到了服务器上,早期就引入了一个名词,叫——负载均衡,早期通常用apache作负载均衡,可是单机只能支持1W的并发,Nginx官方的介绍是支持20W的并发sql

2、负载均衡

  分为两种:硬负载,软负载。那么什么叫硬负载,什么叫软负载呢?(左图硬负载、右图软负载)mongodb

 

 

  硬负载(F5):就是企业单位,事业单位通常用到的,叫 F5 。直接在服务器和外部网络间安装负载均衡设备,这种设备咱们一般称之为负载均衡器。因为专门的设备完成专门的任务,独立于操做系统,总体性能获得大量提升,加上多样化的负载均衡策略,智能化的流量管理,可达到最佳的负载均衡需求。 通常而言,硬件负载均衡在功能、性能上优于软件方式,不过成本昂贵,好比最多见的就是F5负载均衡器。数据库

  优势:可以直接经过智能交换机实现,处理能力更强,并且与系统无关,负载性能强更适用于一大堆设备、大访问量、简单应用apache

  缺点:成本高,除设备价格高昂,并且配置冗余.很难想象后面服务器作一个集群,但最关键的负载均衡设备倒是单点配置;没法有效掌握服务器及应用状态.浏览器

  硬件负载均衡,通常都无论实际系统与应用的状态,而只是从网络层来判断,因此有时候系统处理能力已经不行了,但网络可能还来 得及反应(这种状况很是典型,好比应用服务器后面内存已经占用不少,但尚未完全不行,若是网络传输量不大就未必在网络层能反映出来)

  软负载Nginx、lvs、proxy):把请求分发到软件上。

  优势:基于系统与应用的负载均衡,可以更好地根据系统与应用的情况来分配负载。这对于复杂应用是很重要的,性价比高,实际上若是几台服务器,用F5之类的硬件产品显得有些浪费,而用软件就要合算得多,由于服务器同时还能够跑应用作集群等。

  缺点:负载能力受服务器自己性能的影响,性能越好,负载能力越大。

  综述:对咱们管理系统应用环境来讲,因为负载均衡器自己不须要对数据进行处理,性能瓶颈更多的是在于后台服务器,一般采用软负载均衡器已很是够用且其商业友好的软件源码受权使得咱们能够很是灵活的设计,无逢的和咱们管理系统平台相结合。

  Nginx的图能够这样理解:这三个服务器,所放置的代码都是一致的,链接的数据库,也是一致的,不然个人数据就不知道跑到哪里去了。。。Nginx至关因而处理请求的流向,至关于秩序的维护者

  

 

  这样,能够处理20W的用户并发,可是若是个人请求再很大呢???那就作 Nginx 集群,Nginx 下面再套 Nginx 去分发请求,可是咱们通常小公司用不到

 

3、数据库

那么,在 Web 服务器能处理这些请求的前提下,这些请求所有发送到一个数据库服务器,数据库访问量大一个服务器能抗住么???用户量大加机器,数据库要怎么弄?

  结论:数据库也作集群组

  方式:

  一、数据库备份

  早期都是用数据库的备份,就是我有两个数据库服务器 A 和 B ,挂了 A 我还有 B 在撑着,定时把数据库备份到其余数据库。这样数据库是有丢数据的现象的,通常晚上备份,可是丢数据总比没有的强

  二、数据库读写分离

  如今都是对数据库进行读写分离。主库负责写(insert、delete、update),从库负责读。通常读操做更多,因此读操做的机器通常会更多。这样数据库的压力会减轻

 

  

问题:写操做在 A 服务器,查询的是 B 服务器。怎么在 A、B 这几个服务器怎么数据同步???怎么下降同步的延迟?
  方式: 数据库主从同步
  用一个二进制文件传输,主库有了数据以后,备份到二进制文件内,全部的从库从二进制文件内读;
  用户操做主库,往二进制文件内追加写(往末尾写,不复写不改写),全部的从库对这个二进制文件是追加读。用这种方式 ,进行同步,可是这样必定是有延迟。
  全部有时候咱们删了一个东西,加一条数据,或者修改什么东西,可是数据没有及时更新,界面上咱们刷一下也没更新。可是过一下子,再刷新,就显示正常了。这是数据读写分离,未及时同步形成的。
  主从读写分离 解决数据库请求量大问题;但解决不了, 数据量大问题,好比说我数据库搞100台,也不能解决单表数据量大的问题


数据量大的问题是个啥子问题呢?好比说我一个单表A内,有100W条数据,去里面找1条数据;一样的一个表B,只有1W条数据,相比较起来在B表内找这条数据和在A表内查找,确定是在B表内检索起来更快。那么这个问题要怎么解决呢?
  涉及到数据库索引,打比方说,1W条数据,找一条数据,怎么找?一条一条去找从头找到尾,去核对……机器的处理速度很快,1W条数据可能比较快;可是若是100W条数据,从头找到尾那就得卡死了。。。那么什么是索引呢?好比我说从中间开始找,从中间往前面你开始找,再从中间日后面找。索引就是划定一个范围去找,简单理解。
  那咱们举个例子,新浪,假设新浪微博,日活1000W,天天往数据库内写一条数据,那么一天就是1000W条数据,那么1个月呢?就是3个亿,若是存在一个数据库,一个表内,拿去查询就得宕机了(查询的时候在内存里面查,内存满了就宕机了,由于查询不仅是一个用户在查)。
  13年开始,解决数据量大的问题:数据库拆库分表。把1套数据库,拆成图内的4套库,每一个库的数据量是以前的1/4,也能够拆成更多份;每一个表也能够拆表,好比拆成1/4,那么单表量就变成了1/16。拆库分表在zhuangbility课程学习

 

4、微服务

  咱们用淘宝举例子:简单说一个业务:好比说帐户系统,用户系统。用户系统不只仅是帐户系统,是个大核心,对接多少东西?支付宝、天猫、阿里云、阿里妈妈、饿了么、web系统等……因此不只仅是一张表能把它存完,那些积分,收货地址,收藏等。除了用户系统,还有些商品模块,商品的展现模块有不少东西:库存,分类,价格,销量等等。检索模块,搜索不仅是搜索,里面有不少内容在里面,广告、销量排名等等。还有不少小业务:订单,购物车,支付,消息等。这些小的业务就叫作微服务。

  若是这些服务在一个系统内实现,一个服务出了问题,那么整个系统都得崩溃。天猫双11上次的事件,改不了收件地址;退款退不了。这些个别功能使用很差使,并没影响到其余公司功能的使用,登陆==>搜索==>下单==>付款都没问题。把大的业务,拆分红一个一个的服务,减小系统的耦合度。下降由单个功能的故障引发整个系统不可用的可能性。

  用户的集群,商品功能的集群,订单的集群,搜索的集群,整个构成个大的淘宝/天猫
  用户内集群,商品内集群,订单内集群,搜索的集群……组成一个大的应用集群
  
  那么这些模块对系统提供的都是接口,好比说搜索到商品,两个服务之间确定有接口调用,那么用什么取保证接口调用访问呢?为了方便接口与接口间调用,接口间调用使用Zookeeper进行相互调用,这里咱们加入一个Zookper的集群。
  Zookeeper内有两个模块:生产者,消费者。生产者是什么意思呢?
  就是说搜索服务内有那些接口,订单服务呢有哪些接口,所有注册到Zookeeper,别的系统才有可能访问到这个接口;消费者:谁能访问哪个接口。这样保证了整个系统接口的安全性以及可靠性。
  有哪些接口在生产者内,谁能访问在消费者内。Zookeeper应该在Nginx和应用服务器之间。nginx-》zookeeper-》应用集群。。。zookeeper能够理解为将请求分给哪一个接口
  

5、缓存

  咱们以前讲为何要参数化,是为了不数据库查询缓存。关系型数据库自己有缓存,指的是咱们查询出一条数据,会生成一条查询计划,存在数据库的缓存内,下次咱们查询语句假设如出一辙,就会命中这个缓存,就能够很快地返回出要的查询数据。
  可是咱们这里要将的数据库缓存跟上面提到的不是一个东西。有不少东西在中间常常被访问到。关系型数据库是存放在磁盘的,不是在内存的,存放在内存重启会失效。某些数据在访问过程当中用户常用到,就会被放到内存里面,想要更快就能够用链表形式存,那就更快。这里咱们在数据库服务器和应用服务器之间会设置一个缓存系统,是存在应用服务器集群以及数据库服务器集群之间的,通常是 redis,redis是非关系型数据库,用链表,key-value形式存在,查询起来超级快。咱们这里也考虑作个集群。这样的话,用户的请求过来,直接在redis内查,查不到再去数据库内查。
  那么引入这种非关系型数据库的前提是什么?
  是redis内存在的数据,命中率要很是高。若是命中率不高,还要去关系型数据库内查,还不如我直接去查关系型数据库。高命中表明有不多次直接取查询关系型数据库,通常来说命中率要高达99%以上才算合格。可是redis全部的数据是在内存里面的,那么每次启动,数据会被清空,要关系型数据库从里面推数据。
  那么假设我没有命中,从关系型数据库内返回的数据是直接给应服务器么?并不会,它会先经过redis同步一份,再给应用服务器,这样redis下次的命中率就高了。
  redis除了要有高命中率,也要考虑数据的失效,内存毕竟是有限的,因此先保存近redis的数据就先出内存。在这个前提下,redis会对数据进行按期检查,假设一个数据在多长时间内没有被访问到,或者说访问的次数没达到某个标准,那么这个数据也会被踢出redis,这叫清除非活跃数据。
  

 

 6、消息系统

  Kafka,消息中心。什么叫消息中心呢?

  好比说在淘宝上支付商品完成,对系统来讲要作哪几件事?

  生成订单,订单号;通知商家,库存-1;通知商家发货等等,这些全部看不见的业务逻辑,得有一个统一的人去告诉别人,若是消息只发一条,那么假设通知商家库存减一,那么可能就不能通知发货。
  这个kafka就是生成消息的,是一个统一的通知渠道。其余人来拿消息是有顺序的。这样就能保证消息的一致性、完整性、顺序性。顺序性也是很重要的,消息是堆积在kafuka内的,好比说我登陆获取验证码A,手机没获取到,没收到我再发一次验证码B,结果后面的验证码B先发到手机上。支付信息,我先支付,生成的订单确实后一个支付者的订单,这就乱套了,都是由kafuka管理的。有不少相似的管理系统,不必定是kafuka。
 

 7、图片服务器&文件服务器

  图片是存在哪?放在数据库?若是在数据库要从数据库读地址,再去DNS地址内找图片再显示?每一个公司都有图片服务器,专门是负责处理图片压缩,拉伸放大,存储等。

 

  文件服务器DFS(存入数据,报表之类的)好比说,淘宝的销量表,不多是实时生成的,那样查询太慢了,是存储在服务期内的。好比说小米的双11销量表,客户从哪儿买的?分布的城市,买的型号,价格等等;其余厂商也是如此。若是要都是去数据库查询,那不就完蛋了。那么确定是先生成,再展现,数据文件存储在文件服务期内。文件服务器常见的是DFS
  

   

  MongoDB:存大数据,并且不是常见的数据,好比你朋友圈的数据。存在磁盘,存历史数据用,一个页面/一个接口可能会查多个或多种数据库
  通常什么样的数据存储在 mongodb? etl标签、用户开户的注册抓取的通信录等隐私数据、地址等
 

8、CDN节点加速

  国内最出名的cdn两家是哪两家?蓝汛 网宿

  也是一种缓存,缓存的是啥?通常来说是缓存图片,怎么缓存?

  把那些图片存在就近的那个地域的服务器上,不一样的用户区请求服务器,就从就近的服务器取,而不是从最大的那个后台的服务器取;好比说广州的请求,就在南方这边的服务器上取,而不是从北京的终端后台。cdn存的是静态的资源,某些一段时间不变的东西,js,css那些;能够看下f12,域名不是本身的基本是从cdn节点取

  

  

  好比说百度的首页:有些js,图片,这个域名都不是baidu,因此是存在cdn节点上的

  

 

  请求经过DNS域名解析,解析成一个ip:port这个ip:port是Nginx的域名和端口,不是的话那就直接访问到后面的应用服务器了。Nginx是负载均衡,请求来了,分发给后面的服务器,Nginx干了活可是不处理请求的业务逻辑,只是分配任务。请求分发到注册中心(配后台有哪些接口的,这些接口谁能调用它?),而后看接口是谁配的,给接口的提供者,而后再处理业务逻辑注册,而后去数据库里面查有没有这个用户,给出相应提示。这里咱们没用到redis,由于不是重复的,注册一次就好了。那么什么会用到redis?天猫首页的商品,那些首页的商品金额等。也就是用户会频繁点击,用户访问量大的东西。哪里用到kafuka呢?日过作了某件事,对其余的服务有通知,有影响,那么就须要kafuka,好比典型的下单付款等。这意思是,不是每一个业务逻辑都得走完服务器全部东西。

   整个架构:

   以上算是一个比较成熟的系统,应用服务期内并无彻底写完,不一样的服务内部也有不一样的内部架构,要深刻理解而且记住,对于不理解的内容,中间件等的原理还得本身深刻去理解。

系统分析

1、响应时间

  响应时间是哪些的和?N1+N2+N3+N4+A1+A2  

  若是说响应时间过长,有多是 N一、N二、N三、N4 的也多是 A一、A2 的问题,也有多是Client的 A3 太慢,试想若是 A3 发1W个请求,有可能会阻塞,可是咱们作性能测试会默认忽略掉这块东西

  服务端的接口处理的时间实际上是分为两部分的,一是接口自己响应的时间,二是去数据库查数据的时间之和:=A1+A2+N2+N3

  

  继续拆分时间:
  请求发到webserver以前,要有空闲线程才能进行处理,因此真正进行执行以前,会有等待空闲线程的等待时间,有了空闲进程以后,才能进去读代码

  读代码以后,读到请求数据库的语句时,这个线程就会挂起,须要找到空闲的程序与数据库的链接池,才能把请求发到数据库内,容器里面通常配20-30个,120个最大

  数据库自己也有链接池,通常1800(黄线)

 

   

  假设空闲线程,拿到请求,就必定会立刻处理么?不必定,要看服务器的CPU,内存,磁盘(硬件),假设线程空闲,可是CPU满了,是不会当即去读代码的,得有空闲的片。CPU在内存里面干活,若是内存满了,CPU也没办法干活;磁盘满了,也干不了活DB Server也是以来与硬件资源,资源充足才能继续,不足也没办法处理
 
 
  过程详解:上图,将响应时间拆解,请求到了web容器,经过tomcat,这个代码来了不必定立刻执行,要有空闲线程,而后开始读代码,读到sql语句,而后就去进行链接数据库,数据库的链接池(蓝色)有可能会排队。过去了以后,线程会被挂起。可是过去了以后还要进入数据库自己的链接池,要有空闲的数据库链接池(黄线),可是数据库链接池通常很大,因此用虚线,时间能够忽略。取完了sql的值,再返回到tomcat内,那个挂起的线程再进行执行。这里也要进行链接池链接,可也能会排队。web服务器处理完后再返回给用户Client端。
  以上的全部的环境都没考虑硬件环境,cpu,内存,磁盘也会制约软件的运行。
 
 
  还有个JVM-java虚拟机,在tomcat里面
  tomcat是java跨平台的,new是要占内存的,java里面的new都是将类去实例化,也就是对象,这些对象所有占了内存,占满了再new是new不动的,后面的代码就读不动了。内存就会崩溃。
  GC回收就是将没用的对象,回收掉,也就是把内存回收
 
  结合到上边,内存没了,就得垃圾回收,也就是GC
  

 

响应时间太慢,可能的缘由在哪???  

一、自身的Client端产生请求阻塞(CPU排队/带宽满了)

二、网络传输时间过长/网络带宽是否有瓶颈(带宽能上传多少,要除以8,好比说100Mbps,一秒只能上传100/8Mb)

三、web应用服务器里面的问题分如下几点:

  • 服务器的CPU/内存/磁盘是否是符合条件;  CPU满了,内存满了,磁盘满了不够资源后面的就不用看了,应为软件运行的基本环境都不具有,而后往下走
  • web容器tomcat没有空闲线程/进程; 有空闲线程才能处理,若是都繁忙,容器内没有线程处理,都满了,在容器池那里就得排队,没问题再往下走
  • 代码的业务逻辑实现好坏; 进入到web服务期内,才开始读代码,读到代码的业务逻辑实现太烂了也可能会影响运行的时间
  • 若是请求须要请求数据库,须要看应用程序跟数据库服务器没有空闲的链接池,是否要进行排队; 有数据库交互要看web和db之间有没有空闲的链接池通道,没有也得排队
  • 应用服务器与数据库服务器链接,网络是否通畅;  若是这俩不在一个服务器上,也是用网络链接

四、DB服务器

  • 数据库自己的链接池够不够
  • 这里面的CPU、内存、磁盘分析
  • 数据库的执行效率过低

五、web服务器容器内没有进行垃圾回收(GC),没有足够的内存去执行代码

六、返回的网络以及带宽

怎么分析问题所在?

  1. 拿到系统结构图,分析出架构的数据流向
  2. 根据系统架构画出业务请求的数据流图
  3. 根据数据流画出流程节点中可能存在的问题节点以及出现问题的可能性:易出现问题的9点
  4. 经过依次监控数据,排查以上问题是否存在
  5. 若是排查了节点,改了还有问题,重复第4步
  6. 能够经过经验作一些小的手段帮助本身快速排查问题

  这里单单拎出第6点分析

  有可能存在问题的点(紫色):负载机性能瓶颈,网络带宽,硬件资源,线程池/进程池,数据库链接池,代码逻辑,SQL执行效率,数据库自己链接池, JVM---9点

  排查,从咱们能拿到数据的地方去先排查,由简至难。

  关于代码,让开发加日志。业务里面能够加日志,帮助定位业务问题。性能里面加日志,帮咱们定位性能消耗在哪一个时间。那怎么加呢?在web服务器上打印出时间戳  

  性能测试加日志:定位哪一段时间比较长(时间日志)
  比方说登陆的代码:
  t1,t2为时间戳,用时为(t2-t1),整个接口的时间
  

  t4-t3是sql的执行时间

  

  

  

例如:
一、测出的登陆接口响应时间=10s,接口时间为8s,sql时间为7s
  那么,核心的问题在于==>sql慢了(sql查询时间+网络+数据库链接池)==》定位到了问题
二、接口=8s,sql=1s
  核心问题在于代码业务逻辑问题/GC/链接池
三、接口=1s,sql=0.7s
  那么是哪里的问题?反正跟代码没问题,那么是代码以前的问题:负载机/网络/容器链接池
 
log4j,记录全部的数据库操做日志

 

有个更复杂的问题:
A调用B,B调用C怎么测?
隔离法。
先测C;再测B,把C接口mock掉;那怎么把C mock 掉?其实至关于B调用C的返回结果,把C接口的返回结果固定就能够,这个能够依赖于 MockServer工具,某个ip:port返回固定值/变化值;
A测试就把B Mock 掉,再测A的性能

 

结论:

负载均衡解决的是用户请求流量大的问题;
数据库读写分离解决的是数据库请求量大的问题;
拆库分表解决数据库数据量大的问题;
相关文章
相关标签/搜索