1、在设计系统时,应该多思考 墨菲定律
1. 任何事都没有表面上看起来那么简单。
2. 所有的事做起来都会比你预计的时间长。
3. 可能出错的事总会出错。
4. 如果你担心某种情况发生,那么它就更有可能发生。
2、在划分时,也要思考康威定律。
1. 系统架构是公司组织架构的反映。
2. 应该按照业 务闭环进行系统拆分/组织架构划分,实现闭环、高内聚、低耦合,减少沟通成本。
3. 如果沟通出现问题,那么就应该考虑进行系统和组织架构的调整。
4. 在合适时机进行系统拆分,不要一开始就把系统/服务拆得非常细,虽然闭环,但是每个人维护的系统多,维护成本高。
3、架构演变
一个成熟的大型网站系统架构并不是一开始就设计的非常完美的,世上没有完美的架构,也不是一开始就具备高性能、高可用、安全性等特性,而 是随着用户量的不断增加、业务功能的扩展逐步完善演变过来的。在这个过程中,开发模式、技术架构等都会发生非常大的变化。而针对不同的业 务特征的系统,会有各自的侧重点,比如像淘宝这类网站,要解决的是海量商品搜索、下单、支付等问题;像腾讯,要解决的是数亿级别用户的实 时消息传输;百度所要解决的是海量数据的搜索。每一类的业务都有自己不同的系统架构。 我们以电商系统的发展演变为例,分析架构演变历程。 关注的是数据量、访问量提升,网站结构发生的变化,而不是具体关注业务功能点。其次, 这个过程是为了让大家更好的了,解网站演进过程中的一些问题和应对策略。 假如我们系统具备以下功能: 用户模块:用户注册和管理 商品模块:商品展示和管理 交易模块:创建交易及支付结算
3.1、单机负载
3.2、数据库服务器和应用服务器分离
3.3、利用缓存改善网站性能
3.4、使用集群改善应用服务器性能
3.5、数据库压力变大,数据库读写分离
3.6、使用NoSQL和搜索引擎缓解读库的压力
3.7、使用CDN和反向代理提高网站性能
3.8、将应用服务器进行业务拆分
3.9、数据库的水平、垂直拆分
3.10、服务拆分
3.1单机负载
公司刚创业那会,老板兴致勃勃的租了一间民宅,买了一台服务器。然后大伙几个就开干了。 大伙把所有软件和应用都部署在一台机器上,这样就完成一个简单系统的搭建,这个时候的讲究的是效率。 我们在一台机子上装了lnmp,下图描述了我们这台服务器
3.2、数据库服务器和应用服务器分离
随着网站的上线,访问量逐步上升,服务器的负载慢慢提高,在服务器还没有超载的时候,我们应该做好规划,提升网站的负载能力。假如代码层面的优化已经没 办法继续提高,在不提高单台机器的性能,增加机器是一个比较好的方式,投入产出比非常高。这个阶段增加机器的主要目的是讲 web 服务器和 数据库服务器拆 分,这样不仅提高了单机的负载能力,也提高了容灾能力。并且根据服务器的用途配置不同的硬件,达到最佳的性能效果。
3.3、利用缓存改善网站性能
在硬件优化性能的同时,同时也通过软件进行性能优化,在大部分的网站系统中,都会利用缓存技术改善系统的性能,使用缓存主要源于热点数据的存在,大部分 网站访问都遵循28原则(即80%的访问请求,最终落在20%的数据上),所以我们可以对热点数据进行缓存,减少这些数据的访问路径,提高用户体验。
3.4、使用集群改善应用服务器性能
随着访问量的继续增加,单台应用服务器已经无法满足需求。在假设数据库服务器还没有遇到性能问题的时候,我们可以增加应用服务器,通过应用服务器集群将 用户请求分流到各个服务器中,从而继续提升负载能力。此时多台应用服务器之间没有直接的交互,他们都是依赖数据库各自对外提供服务。应用服务器前面部署 负载均衡服务器调度用户请求,根据分发策略将请求分发到多个应用服务器节点 ,另外,我们还可以增加缓存服务器集群, 来提高访问速度并降低mysql等数据库的压力
3.5、数据库压力变大,数据库读写分离
架构演变到这里,并不是终点。上面我们把应用层的性能拉上来了,但是数据库的负载也在慢慢增大,那么怎么去提高数据库层面的负载呢?有了前面的思路以 后,自然会想到增加服务器。但是假如我们单纯的把数据库一分为二,然后对于后续数据库的请求,分别负载到两台数据库服务器上,那么一定会造成数据库不统 一的问题。 所以我们一般先考虑读写分离的方式, 。 分库分表不是这个阶段要考虑的,是数据库优化的终极技能,因为会带来一些难题,所以能不用就不用
3.6、使用NoSQL和搜索引擎缓解读库的压力
数据库做读库的话,常常对模糊查找效率不是特别好,像电商类的网站,搜索是非常核心的功能,即便是做了读写分离,这个问题也不能有效解决。那么这个时候 就需要引入Nosql和搜索引擎了。对于海量数据的查询和分析,我们使用NoSQL数据库加上搜索引擎可以达到更好的性能。并不是所有的数据都要放在关系型数据中。 常用的NoSQL有MongoDB、HBase、Redis,搜索引擎有Lucene、Solr、Elasticsearch。
3.7、使用CDN和反向代理提高网站性能
假如我们的服务器都部署在广州的机房,对于长沙的用户来说访问是较快的,而对于北京的用户访问是较慢的,这是由于长沙和北京分别属于电信和联通的不同发 达地区,北京用户访问需要通过互联路由器经过较长的路径才能访问到成都的服务器,返回路径也一样,所以数据传输时间比较长。对于这种情况,常常使用CDN解决,CDN将数据内容缓存到运营商的机房,用户访问时先从最近的运营商获取数据,这样大大减少了网络访问的路径。比较专业的CDN运营商有蓝汛、网宿。 而反向代理,则是部署在网站的机房,当用户请求达到时首先访问反向代理服务器,反向代理服务器将缓存的数据返回给用户,如果没有缓存数据才会继续访问应 用服务器获取,这样做减少了获取数据的成本。反向代理有Squid、Nginx。
3.8、将应用服务器进行业务拆分
随着业务进一步扩展,应用程序变得非常臃肿,这时我们需要将应用程序进行业务拆分,如百度分为新闻、网页、图片等业务。每个业务应用负责相对独立的业务 运作。业务之间通过消息进行通信或者共享数据库来实现
3.9、数据库的水平、垂直拆分
我们的网站演进的变化过程,交易、商品、用户的数据都在同一个数据库中,尽管采取了增加缓存,读写分离的方式,但是随着数据库的压力持续增加,数据库的 瓶颈仍然是个最大的问题。因此我们可以考虑对数据的垂直拆分和水平拆分
3.10、服务拆分
这时我们发现各个业务应用都会使用到一些基本的业务服务,例如用户服务、订单服务、支付服务、安全服务,这些服务是支撑各业务应用的基本要素。我们将这些服务抽取出来利用分布式服务框架搭建分布式服务。阿里的Dubbo是一个不错的选择
4、理解分布式 集群 微服务
4.1、分布式
分布式服务顾名思义服务是分散部署在不同的机器上的,一个服务可能负责几个功能,是一种面向SOA架构的, 服务之间也是通过rpc来交互或者是webservice来 交互的。逻辑架构设计完后就该做物理架构设计,系统应用部署在超过一台服务器或虚拟机上,且各分开部署的部分彼此通过各种通讯协议交互信息,就可算作分 布式部署,生产环境下的微服务肯定是分布式部署的,分布式部署的应用不一定是微服务架构的,比如集群部署,它是把相同应用复制到不同服务器上,但是逻辑功能上还是单体应用。
“数据库服务器”和“应用服务器”分离 实际就是一种分布式的方式部署;服务之间的职责各有不同;
4.2、集群
集群就是多个服务之间的职责相同,对于集群来说如果一个节点出现了问题,那么就可以让其他的节店顶上
4.3、微服务
微服务关注:架构设计方式;分布式关注:系统部署方式(两者概念不同) 主要是基于项目的业务模块进行细节化的拆分;
把整个项目可以基于模块,功能拆分为单独的系统
5、高并发下拆分的原则
在系统设计初期,是做一个大而全的系统还是按功能模块拆分系统,这需要根据环境权衡;如果项目只是一个人就不要拆分,如果是项目比较大如京东,淘宝这样 的系统访问量是非常大的,而且设计时投入的资源足够就可以按功能拆分系统
系统维度:按照系统功能业务拆分,比如商品系统、购物车、结算、订单系统等。
功能维度:对一个系统进行功能再拆分,比如,优惠券系统可以拆分为后台券创建系统、领券系统、用券系统等。
读写维度:根据读写比例特征进行拆分。比如,商品系统,交易的各个系统都会读取数据,读的量大于写,因此可以拆分成商品写服务、商品读服务;读服务可以考 虑使用缓存提升性能:写的量太大时,需要考虑分库分表;有些聚合读取的场景,如商品详情页,可考虑数据异构拆分系统,将分散在多处的数据聚合到一处存储, 以提升系统的性能和可靠性。
模块维度:比如,按照基础或者代码维护特征进行拆分,如基础模块分库分表、数据库连接池等:代码结构般按照三层架构 (Web、Service、 MODEL)进行划分。
AOP维度:根据访问特征,按照AOP进行拆分,比如,最典型的例子就是权限,配置
6、消息队列/rpc/restful
restful
HTTP上有各种各样的REST,因为没有强制执行的标准。开发人员可以自由选择以JSON、XML或某种自定义格式形成请求有效负载。
REST over HTTP(S)仅意味着使用REST架构风格并通过HTTP(S)发送请求
消息队列
消息队列用来解耦不需要同步调用的服务或者订阅一些自己系统关心的变化。使用消息队列可以实现服务解耦(- 对多消费)、异步处理、流量削峰/缓冲等。比 如,电商系统中的交易订单数据,有非常多的系统订阅该数据,比如,订单生产系统、定期送系统、订单风控系统等等。如果订阅者太多,那么订阅单个消息队列就会成为瓶颈,此时,需要考虑对消息队列进行多个镜像复制。
使用消息队列时,还要注意处理生产消息失败,以及消息重复接收时的场景。有些消息队列产品会提供生产重试功能,在达到指定重试次数还未生产成功时,会对外通知生产失败。这时,对于不能容忍生产失败的业务场景来说,一定要做好后续的数据处理工作,如持久化数据要同时增加日志、报警等。对于消息重复问题,特别是一” 些分布式消息队列,出于对性能和开销的考虑,在一些场景下会发生消息重复接收,需要在业务层面进行防重处理。
rpc
1. 超时和重新连接需要处理服务器崩溃,即使使用了面向连接的协议(TCP)
2. 不指定服务和客户机的绑定,具体由实现人员决定
3. RPC实现的强制性要求: 被调用过程的唯一规范 响应消息与请求消息匹配的规定 对调用方进行服务身份验证的规定,反之亦然
如何选择:
RestFul:一般是对外提供服务提供给web端或者其他系统调用
rpc:实时性强 要实时返回数据用rpc, 比如查看商品列表,订单列表等等,通过rpc同步实时获取数据。
mq队列:下单那里,牵涉到减库存,发短信等,这些东西用户并不需要你实时返回,用户也不关心,就放到队列mq里面,采用异步的方式处理就行了。
7、数据异构 数据闭环 数据聚合
7.1、数据异构
订单分库分表一般按照订单ID进行,如果要查询某个用户的订单列表,则需要聚合多个表的数据后才能返回,这样会导致订单表的读性能很低。此时需要对订单表 进行异构,异构一套用户订单表,按照用户ID进行分库分表。另外,还需要考虑对历史订单数据进行归档处理,以提升服务的性能和稳定性。而有些数据异构的意 义不大,如库存价格,可以考虑异步加载,或者合并并发请求。
7.2、数据闭环
如商品详情就需要获取:商品品牌,商品价格(要求实时性),图片,店铺,评价等等;这些数据在微服务的拆分下可能会分为如“用户服务,商品服务,交易服务,评价服务,店铺服务,订单服务”
实现数据闭环,如商品详情页,因为数据来源太多,影响服务稳定性的因素就非常多。最好的办法是把使用到的数据进行异构存储,形成数据团环.
7.3、数据聚合
把数据从多个数据源数据聚合
8、缓存银弹
8.1、浏览器缓存
8.2、App客户端缓存
8.3、接入层缓存
8.4、并发化
9、高可用原则
除了对服务可用性的追求,微服务架构一个绕不过去的问题就是服务雪崩。 在一个调用链路上,微服务架构各个服务之间组成了一个松散的整体,牵一发而动全身, 服务雪崩是一个多级传导的过程,首先是某个服务提供者不可用,由于大量超时等待,继而导致服务调用者不可用,并且在整个链路上传导,继而导致系统瘫痪。
9.1、限流
限流的目的是防止恶意请求流量,恶意攻击,或防止流量超出系统峰值的策略
思路:
1. 恶意请求流量只访问到cache
2. 对于穿透到后端应用的流量可以考虑使用NGINX的limit模块处理
3. 对于恶意IP可以使用nginx deny进行屏蔽。
9.2、降级
就是原本需要考虑高实时性相应数据,但是因为服务扛不住改为读缓存;或者需要获取的数据很多但是没有办法处理好则选择降级返回少量数据。
9.3、熔断
如果某个目标服务调用慢或者有大量超时,此时熔断该服务的调用,对于后续调用请求,不在继续调用目标服务,直接返回,快速释放资源。 服务隔离与前面的三个略有区别,我们的系统通常提供了不止一个服务,但是这些服务在运行时是部署在一个实例,或者一台物理机上面的, 如果不对服务资源做隔离,一旦一个服务出现了问题,整个系统的稳定性都会受到影响!服务隔离的目的就是避免服务之间相互影响。 一般来说,隔离要关注两方面,一个是在哪里进行隔离,另外一个是隔离哪些资源。
后续笔记 需要VIP级别才可以看了~~~