• 从性能角度看系统架构


    系统架构

      漏斗原理:请求在网络传输过程中,越往后,请求慢慢的会减少,所以说到数据库服务器的请求量会比在Web服务器的少

    一、基本架构

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

     

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

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

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

      

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

    二、负载均衡

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

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

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

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

      硬件负载均衡,一般都不管实际系统与应用的状态,而只是从网络层来判断,所以有时候系统处理能力已经不行了,但网络可能还来 得及反应(这种情况非常典型,比如应用服务器后面内存已经占用很多,但还没有彻底不行,如果网络传输量不大就未必在网络层能反映出来)

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

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

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

      综述:对我们管理系统应用环境来说,由于负载均衡器本身不需要对数据进行处理,性能瓶颈更多的是在于后台服务器,通常采用软负载均衡器已非常够用且其商业友好的软件源码授权使得我们可以非常灵活的设计,无逢的和我们管理系统平台相结合。

      Nginx的图可以这样理解:这三个服务器,所放置的代码都是一致的,连接的数据库,也是一致的,否则我的数据就不知道跑到哪里去了。。。Nginx相当于是处理请求的流向,相当于秩序的维护者

      

      这样,可以处理20W的用户并发,但是如果我的请求再很大呢???那就做 Nginx 集群,Nginx 下面再套 Nginx 去分发请求,但是我们一般小公司用不到

    三、数据库

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

      结论:数据库也做集群组

      方式:

      1、数据库备份

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

      2、数据库读写分离

      现在都是对数据库进行读写分离。主库负责写(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课程学习

    四、微服务

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

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

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

    五、缓存

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

     六、消息系统

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

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

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

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

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

     

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

       

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

    八、CDN节点加速

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

      也是一种缓存,缓存的是啥?一般来讲是缓存图片,怎么缓存?

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

      

      

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

      

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

       整个架构:

       以上算是一个比较成熟的系统,应用服务期内并没有完全写完,不同的服务内部也有不同的内部架构,要深入理解并且记住,对于不理解的内容,中间件等的原理还得自己深入去理解。

    系统分析

    一、响应时间

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

      如果说响应时间过长,有可能是 N1、N2、N3、N4 的也可能是 A1、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
      

     

    响应时间太慢,可能的原因在哪???  

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

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

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

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

    4、DB服务器

    • 数据库本身的连接池够不够
    • 这里面的CPU、内存、磁盘分析
    • 数据库的执行效率太低

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

    6、返回的网络以及带宽

    怎么分析问题所在?

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

      这里单单拎出第6点分析

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

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

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

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

      t4-t3是sql的执行时间

      

      

      

    例如:
    1、测出的登录接口响应时间=10s,接口时间为8s,sql时间为7s
      那么,核心的问题在于==>sql慢了(sql查询时间+网络+数据库连接池)==》定位到了问题
    2、接口=8s,sql=1s
      核心问题在于代码业务逻辑问题/GC/连接池
    3、接口=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的性能

    结论:

    负载均衡解决的是用户请求流量大的问题;
    数据库读写分离解决的是数据库请求量大的问题;
    拆库分表解决数据库数据量大的问题;
  • 相关阅读:
    d3操作svg路径动画,及dom移动
    新时代前端必备神器 Snapjs之弹动效果
    threejs 鼠标移动控制模型旋转
    玩转SVG线条动画
    CSS也能计算:calc
    CSS两种盒子模型:cntent-box和border-box
    解决Jquery中click里面包含click事件,出现重复执行的问题
    区块链踩坑之基础扫盲及搭建以太坊网络私有链(单节点)
    微信朋友圈转发第三方网站带缩略图实现
    物流一站式查询之快递100篇
  • 原文地址:https://www.cnblogs.com/xiaowenshu/p/10133856.html
Copyright © 2020-2023  润新知