概述
技术作为业务的支撑,它永远是伴随着业务的发展而发展,我们需要不断的学习新的技术去解决新的问题。
但是伴随着年龄的增长,我们能够投入的时间和精力越来越少,掌握科学的学习方法,使用自己的思维方式、对技术的理解层次、系统的知识体系去包容新的技术就十分重要。
目的
满足业务的增长,根据不同的业务规模选择适用的架构。
概念
分布式
what
系统中不同功能的服务部署到不同的服务器上。
why
主要是为了解决业务增长带来的性能问题。
how
比如把tomcat服务和数据库服务分别部署到不同的服务器上。
集群
what
同一功能服务部署在不同的服务器上,对外统一提供服务。
why
提供高可用:集群中的某个节点出问题不影响集群提供的服务。
提高性能:解决单机性能瓶颈,多个节点可以通过负载均衡的方式共同承担外部的访问。
how
把zookeepe中的Master和Slave分别部署在不同的服务器上,共同组成一个整体对外提供配置服务。
case
服务按照预估TPS,把同一服务用tomcat分别部署在多台服务器上,统一对外提供数字商品服务。
高可用
what
服务中部分节点失效时,其他节点能够接替它继续提供服务,则认为服务高可用。
集群是保证服务高可用的解决方案。
why
异常场景下,不影响用户使用。
how
通过集群可用保证高可用。
负载均衡
what
外部请求可以均匀的分发到多个节点上,使系统中的每个节点能够均匀的处理请求,则认为系统是负载均衡的。
why
高可用;高性能;
how
通过使用Nginx,采用负载均衡算法,实现nginx反向代理的服务器达到负载均衡。
反向代理
what
外部请求进入系统,代理服务器把请求转发到某台服务器上,对外部请求来说只有代理服务器与之交互,此时代理服务器实现的是反向代理。
why
通过反向代理可以实现负载均衡。
how
nginx反向代理配置,通过nginx实现反向代理。
演进
单机架构
what
把系统所需要的所有资源都部署在同一台服务器上。
why
- 简单。
- 用户少,业务小。
- 性能要求不高。
how
tomcat、mysql等都部署在一台服务器上
case
淘宝早期网站架构:应用量与用户数较少,可以把tomcat和数据库部署到同一台服务器上。浏览器往www.taobao.com发起请求时,首先经过DNS服务器把域名转换为实际ip地址10.102.4.1,浏览器转而访问ip对应的tomcat。
第一次演进:tomcat与数据库分开部署
目的
解决服务和数据库竞争资源的问题。
what
tomcat和数据库分开部署
why
用户增长,tomcat和数据库之间相互竞争资源(CPU,内存,网络等),单机性能不足以支撑业务。
how
分布式部署。
第二次演进:引人本地缓存和分布式缓存
目的
解决数据库压力过大造成性能瓶颈的问题。
what
在项目中加入本地缓存,外部增加分布式缓存。
why
- 并发读写造成数据库压力较大。
- 缓存热门商品信息或热门商品的html页面等,缓存能把绝大多数请求在读写数据库前拦截掉,大大降低数据库压力。
how
- 本地缓存使用memcached。
- 外部增加分布式缓存使用redis。
引发的问题
- 缓存和数据库一致性问题。
- 缓存穿透:缓存和数据库中都没有数据。
- 缓存击穿:热点key数据失效,访问落到数据库中。
- 缓存雪崩:大量key同一时间失效;redis服务器宕机引发大量key失效;
第三次演进:引人反向代理实现负载均衡
目的
解决单个服务无法满足大量用户访问的性能瓶颈。
what
在多台服务器上分别部署tomcat,使用反向代理软件(Nginx)把请求均匀分发到每个tomcat中。
why
解决单机的性能瓶颈。
how
通过Nginx反向代理内部的tomcat服务。
引发的问题
- session共享。
- 文件上传下载问题。
- 单个数据库性能造成瓶颈。
第四次演进:数据库读写分离
目的
解决单个数据库性能瓶颈问题。
what
把数据库划分为读库和写库,读库可以有多个,通过同步机制把写库的数据同步到多个读库中。
why
解决读写在一个数据库造成的性能问题。
how
- 划分1个写库和多个读库。
- 写库通过同步机制把数据同步到多个读库中。
- 需要读最新的数据,可以在缓存中多写一份数据,通过读缓存来获取最新的数据。
- 使用数据库中间件Mycat,可通过它来组织数据库的读写分离和分库分表,客户端通过它来访问下层的数据库;还可以解决数据同步,数据一致性的问题。
引发的问题
写库和读库的数据一致性问题。
第五次演进:数据库按业务分库
目的
解决不同业务间相互竞争数据库造成的性能瓶颈问题。
what
垂直拆分数据库,按照业务拆分成不同的数据库。
why
- 解决不同业务竞争同一个数据库的问题。
- 可以使用分而治之的原则,不同的业务可以区别对待,数据访问量大的,可以多部署几台数据库服务器。
引发的问题
- 分布式事务。
- 业务间数据无法直接关联分析。
第六次演进:大表拆分为小表
目的
解决单表数据量太大,性能低的问题。
what
当大表数据超过500万行或者2G,需要通过水平分表,把一张大表水平拆分成多张小表。
why
- 解决大表性能低的问题。
- 数据均匀的分发到不同的数据库中的小表中,可以通过数据库水平扩展的方式来提高性能。
how
- 比如可以通过商品ID进行hash,路由到对应的表中存储、查询。
- 针对支付记录,可以按照小时创建表,每个小时表还可以拆分成更小的表,使用用户id或者记录编号来路由数据。
- 可以通过Mycat来拆表和访问控制。
- MPP数据库架构:大规模数据并行处理架构。
- 比如Greenplum、TiDB等。
- 这些MPP数据库能把一个查询解析成分布式的执行计划分发到每台机器上并行执行,最终由数据库本身汇总数据进行返回。
第七次演进:使用LVS或F5使多个Nginx负载均衡
目的
解决单个nginx性能瓶颈。
what
通过网络第四层的负载均衡解决方案,来实现多个Nginx的负载均衡。
why
LVS或F5使用四层的TCP/IP协议,可以支持更丰富的网络协议,性能远高于Nginx。
how
- 单机的LVS可用支持几十万个并发请求。
- LVS是单机版的软件,若LVS所在服务器宕机则会导致整个后端系统都无法访问,需要加备用节点。
- 可使用keepalived软件模拟出虚拟IP,然后把虚拟IP绑定到多台LVS服务器上,浏览器访问虚拟IP时,会被路由器重定向到真实的LVS服务器,当主LVS服务宕机时,keepalived软件会自动更新路由器中的路由表,把虚拟IP重定向到另外一台正常的LVS服务器,从而达到高可用的效果(集群)。
- nginx高可用:多个nginx通过keepalived实行高可用。
第8次演进:通过DNS轮询实现机房间的负载均衡
目的
- 解决单个LVS的性能瓶颈。
- 解决不同地区,服务器机房距离不同,导致了访问的延迟会明显不同的问题。
what
- DNS服务器中配置一个域名对应多个IP地址。
- 每个IP地址对应到不同的机房里的虚拟IP。
- 当用户访问www.taobao.com时,DNS服务器会使用轮询策略或其他策略,来选择每个IP供用户访问。
- DNS轮询虚拟IP,可实现机房间的负载均衡,至此,系统可做到机房级别的水平扩展,千万级到亿级的并发量都可通过增加机房来解决,系统入口处的请求并发量不再是问题。
why
- 一个域名可以配置多个IP地址。
- 单个虚拟IP地址对应的服务器集群,并发量会达到性能瓶颈。
- DNS轮询IP地址,可以达到多个机房的负载均衡。
how
- 域名配置多个虚拟IP。
- DNS轮询域名下的多个ip,访问均匀分发到不同的ip。
第九次演进:引入NoSQL数据库和搜索引擎等技术
目的
业务场景复杂化(检索、分析等需求越来越丰富),普通关系型数据无法满足。
what
外部添加分方式文件系统、NoSQL数据库、搜索引擎等来解决复杂查询、全文检索等查询变慢,导致性能低的问题。
why
解决大数据查询变慢、复杂统计变慢、全文检索变慢等性能问题。
how
- 对于海量文件存储,可通过分布式文件系统HDFS解决。
- 对于key value类型的数据可以通过HBase和Redis等方案解决。
- 对于全文检索场景,可通过搜索引擎ElasticSearch解决。
- 对于多维分析场景,可以通过Kylin或Druid等方案解决。
引发的问题
- 组件增多导致系统复杂度变高,维护成本变高。
- 运维难度变大。
- 数据一致性问题。
第十次演进:大应用拆分成小应用
目的
解决应用太大,包含太大的业务,业务的升级迭代苦难,代码开发维护变难。
what
- 按照业务板块来划分应用代码,使单个应用的职责更清晰。
- 业务之间可以独立升级迭代。
why
- 解决代码开发、维护困难的问题。
- 解决升级迭代困难的问题。
- 每个业务可合理使用资源。
how
- 按照业务功能维度划分应用。
- 使用分布式配置中心zookeeper解决公共配置的问题。
引发的问题
公共配置问题。
第十一次演进:复用的功能抽离成微服务
目的
解决公共服务模块,由应用单独管理导致相同代码存在多份的问题,导致公共功能升级,所有的应用都得升级,比如升级支付,导致所有和支付相关的业务都得升级。
what
如果用户管理、订单、支付、鉴权等功能在多个应用中都存在,那么可以把这些功能的代码单独抽取出来形成一个单独的服务来管理,这样的服务就是微服务,应用和服务间通过HTTP、TCP或者RPC请求等多种方式来访问公共的服务,每个单独的服务都可以由单独的团队来管理。
why
- 解决多个应用维护多份公共功能的代码。
- 解决单个应用代码复杂度高的问题。
- 微服务独立迭代,提高整体工作效率。
how
- 使用微服务架构。
- 使用Dubbo、SpringCloud等框架实现服务治理、限流、熔断、降级等功能,提高服务的稳定性和可用性。
引入的问题
服务注册发现、治理、限流、熔断、降级等。
第十二次演进:引入企业服务总线ESB屏蔽服务接口的访问差异
目的
通过ESB统一进行访问协议转换,应用统一通过ESB来访问后端服务,服务于服务之间也通过可以通过ESB来相互调用,以此降低系统的耦合度。
场景
比如目前的商品系统需要去访问物流中包裹的位置,但是包裹位置模块提供的服务是socket服务,我们的商品使用的是http调用方式,这个时候就可以通过加一个ESB模块来完成http协议与socket协议之间的转换。
引入的问题
- 多个服务部署在单个环境上运行环境冲突的问题。
- 大促获得需要动态扩缩的问题。
第十三次演进:引人容器化技术实现运行环境隔离与动态服务管理
目的
- 解决动态扩缩容的场景。
- 简化部署和运维。
what
- 目前最流行的容器化技术是Docker,最流行的容器管理服务是Kubernets(K8S),应用/服务可以打包为Docker镜像,通过K8S来动态分发和部署镜像。
- Docker镜像可理解为一个能运行你应用/服务最小的操作系统,里面放着应用/服务的运行代码,运行环境根据实际的需要设置好。
- 把整个“操作系统”打包成一个镜像后,就可以分发到需要部署相关服务的机器上,直接启动Docker镜像就可以把服务运行起来,使服务的部署和运维变得简单。
why
- 无需在服务器上配置运行环境。
- docker镜像打包好,在服务器上启动就好,方便扩缩容(针对大促场景)。
how
在大促之前,可以在现有的机器集群上划分出服务器来启动Docker镜像,增强服务的性能,大促过后就可以关闭镜像,对集群上的其他服务不会造成影响。
第十四次演进:以云平台承载系统
目的
解决资源利用率低的问题:容器化技术可以解决动态扩缩问题,但是机器还需要公司自身来管理,在非大促的时候,会闲置着大量的机器资源来应对大促,机器自身成本和运维成本都极高,资源利用率低。
what
- 云平台就是海量机器资源,通过统一的资源管理,抽象为一个整体,在之上可安心动态申请硬件资源(CPU、内存、网络等),并且之上提供统一的操作系统,提供常用的技术组件(如Hadoop技术栈,MPP数据库等)供用户使用,甚至提供开发好的应用。
- IaaS
基础设施即服务:对于于机器资源统一为资源整体,可动态申请硬件资源的层面。 - PaaS
平台即服务:对应于提供常用的技术组件方案系统的开发和维护。 - SaaS
软件即服务:对应于提供开发好的应用或服务,按功能或性能要求付费。
why
- 可以在云平台临时申请更多的资源,结合Docker和K8S来快速部署服务,在大促结束后释放资源,真正做到按需付费,资源利用率大大提高。
- 提高资源利用率.
how
系统可部署在公有云上,利用公有云的海量机器资源,解决动态硬件资源的问题。
总结
设计原则
N+1设计
what
系统中每个组件都应做到没有单点故障。
why
保证每个组件高可用。
回滚设计
what
系统升级时出现错误可用即时回滚到之前的版本。
why
确保系统可用向前兼容。
how
- 功能层面考虑向前兼容。
- 脚本层面设计成可回滚的。
禁用设计
what
提供控制具体功能十分可用的配置,在系统出现故障时能够快速下线功能。
why
- 保证系统可用性,即使止损。
- 兼容之前的版本。
how
配置为新功能配置开启开关,开关可动态配置。
监控设计
what
监控功能相关指标,信息。
why
即时发现问题,分析问题,解决问题。
how
设计阶段就应该考虑如何监控。
case
- 运行时日志打印。
- 大盘监控。
多活数据中心设计
what
在多个地区建立数据中心,保证在一个机房断电的情况下系统依然可用。
why
保证系统异常情况下高可用。
采用成熟的技术
what
使用目前市场上成熟的解决方案。
why
刚开服或者开源的技术往往存在很多隐藏的bug,出了问题没有商业支持可能会是一个灾难。
资源隔离
what
为单个业务划分一定的资源,避免单个业务占用系统的全部资源。
why
避免业务间相互影响,导致其他业务服务不可用。
how
可以使用docker容器技术进行资源隔离。
架构能水平扩展
what
系统中各个组件,包括整个系统可以线性的增加。
why
系统只有做到水平扩展才能有效避免性能瓶颈问题。
非核心则购买
what
非核心的功能可以付费购买三方提供的服务。
why
非核心功能如需要占用大量的研发资源才能解决,则考虑购买成熟的产品。
使用商用硬件
why
- 商用硬件能有效降低硬件故障的几率。
- 遇到问题可以得到及时的商业技术支持。
快速迭代
what
系统应该开发小功能模块,尽快上线进行验证,早日发现问题大大降低系统交付的风险。
why
降低交付风险。
how
开发小功能模式,尽快上线验证。
无状态设计
what
服务接口应该是不记录状态的,当前接口的访问不依赖于接口上次的访问状态。
why
避免异常情况导致的状态出错,出现服务调用失败或错误的问题。
how
如果需要记录状态,把状态数据放到数据库等持久性组件中,接口查询判断。