朱晔的互联网架构实践心得S1E8:三十种架构设计模式(下)前端
【下载本文PDF进行阅读】node
接上文,继续剩下的15个模式。算法
一直有一个说法就是不到没路可走的时候不要考虑数据库分片。有的时候业务量大到单个业务表在通过缓存+队列削峰等措施以后的平均的TPS超过1万,单表实在是扛不住,仍是只能考虑分片手段。数据库
分片前:后端
分片后:设计模式
相信互联网公司90%+确定都使用了这个模式。把静态资源从动态网站中剥离由Nginx等高性能服务器来处理静态资源,而后使用三方CDN对静态资源进行加速,不但减轻了动态网站的负载并且数据在边缘节点加速让用户的访问跟快,使用单独的一个或多个子域名作静态资源还能提升下载资源的并行度提升网页加载的速度。缓存
使用CDN来进行资源加速通常有主动数据传送到CDN存储和在CDN配置回源站拉取两种方式,文件类通常使用主动推送数据,静态资源类通常使用回源方式。在使用CDN的时候考虑下面的问题:安全
在第三第五两篇文章中我都提到了索引表的作法。出于下面的缘由,咱们会考虑索引表:服务器
不过须要考虑一点索引只有在数据区分度高的状况下才能发挥价值,若是90%以上的数据都是相同的值,那么走索引进行查询性能会比全表扫还要差一点。网络
这里说的是不一样的前端配以不一样的专用后端。好比PC网站和APP的后端是两套程序。这种模式是否适合其实仍是看两端的后端提供的数据差别有多大,咱们老是但愿能够尽可能统一一套后端,业务逻辑不用重复写,可是咱们要考虑到PC网站和APP的差别性:
考虑到这些差别,咱们是在一个工程内根据来源作适配,仍是独立两套工程来作独立的后端取决于差别度有多大了。
这个模式从资源节省的角度来讲咱们的计算单元任务能够进行一些合并,减小由于资源限制致使没必要要的开销。
对于分布式服务,咱们趋向于把服务设计为无状态能够任意扩展的,可是在某些业务场景下咱们不得不在服务中选举出一个Leader(Primary节点,Master节点)来作一些不适合重复作的协调管理工做。这个时候咱们须要有算法来作选举。
最多见的实现方式是使用Zookeeper来实现,咱们知道ZK的znode有Sequence和NonSequence两种,前者多个客户端只有一个可建立成功同名节点,后者建立后会自动加上序列号命名多个客户端能够建立多个同名节点,利用这个特性有两种常见实现方式:
在软件设计模式中过滤器构成的管道这种模式很常见(图上的业务逻辑就是Handler,以前的那些Task就是Filter,模式上能够是Filter+Handler也能够是Filter+Handler+Filter也能够是Handler+Filter),无论是Spring MVC框架也好,Netty这种网络框架也好都提供了这样的设计。每个过滤器单独完成一个功能,能够独立插拔随意组合配置成一套管道,不但数据处理的整个过程清晰可见还增长了灵活性。
对于架构上也能够有这样的模式,在数据源进入到业务逻辑处理以前(或以后,或先后),咱们能够配置一系列的数据过滤器完成各类数据转化和处理的任务。Task和Task之间能够是同步调用,也可使用MQ作必定的可伸缩性设计。还能够把过滤器的配置信息保存在配置系统中甚至根据上下文动态构建出管道,实现更灵活的前置或后置流程处理。
这里说的是消息队列的消息消费者是一组对等的消费者,经过竞争方式来拉取数据执行。以前提到过这是MQ的最多见的一种模式,通常而言咱们会部署多个消费节点进行负载均衡,在负载较大的时候能够方便得增长消费者进行消费能力扩容。不过对于这种模式消费者应当是对等的无状态的,在某个消费者在消费失败的时候消息从新回到队列随后可能会被另外一个消费者进行处理。
重试适用于瞬态故障,以后会提到断路器模式,两种模式能够结合使用。首先说说重试的几个发起人:
重试也要考虑几种策略:
这个模式说的是三者的角色:
三个角色相互配合完成复杂的,具备较多远程服务参与的任务,确保任务的最终有效执行。在以前架构三马车一文中说到定时任务的时候提到过一种任务驱动表的模式,说到了一些驱动表的实现细节,其实总体和这个模式是相似的思想。当咱们的一个复杂逻辑有多个步骤构成,每一步都依赖外部服务,这个时候咱们能够选择全程MQ+补偿方式(乐观方式),也能够选择全程任务驱动的被动模式(悲观方式),具体选择取决于更看重可靠性仍是及时性。
资源隔离有好几个层次,能够在进程内部作线程池或队列的隔离,在微服务的服务划分上考虑隔离出单独的物理服务,或是在服务器层面经过虚拟化技术或Docker技术进行资源隔离。隔离了就不会相互影响,可是会有成本、性能、管理便利性方面的开销。实现可以根据需求分析出可能的资源相互影响的点,提早规划隔离每每能够避免不少问题的发生。以前有遇到过几个事故是这样的:
分布式应用环节多网络环境复杂,若是遇到依赖服务调用失败的状况咱们或许能够进行重试期待服务立刻能够恢复,可是在某些时候依赖的服务是完全挂了而不是网络故障没法及时恢复,若是不考虑进行熔断的,可能服务调用方会被服务提供方拖死。这个时候能够引入断路器机制,如图所示断路器通常采用三态实现,瞬间恢复可能会让底层服务压力过大:
实现模式的时候考虑下面注意点:
实现上咱们能够看一下Netflix的Hystrix进行进一步了解。
这个模式说的是失败时必须进行撤销的操做,能够由一组补偿程序来作相应的补偿。在这里我想说的更广一点,在服务调用的时候,调用失败有几种可能:
因此在出现服务调用失败或超时的时候,服务端执行究竟有没有成功客户端是不明确的(只有客户端收到了明确的服务端返回的业务错误才真正表明执行失败),这个时候须要有补偿逻辑来同步服务端的执行状态。若是这样的补偿不可避免并且须要补偿的服务特别多,这样的逻辑逐一来写是一件很烦的事情,咱们能够把这个工做封装成一个补偿中间件来处理:
这样,咱们在服务调用的时候就不须要考虑补偿逻辑的实现,只要实现这个标准便可。
这个模式说的是,在访问敏感资源的时候,咱们能够没必要让应用程序在其中做为一个代理转一层作权限控制,而是生成一个密钥,让用户直接拿着密钥到资源池换数据。
一些CDN在提供资源上传下载服务的时候通常都会提供相似的安全策略,须要实现生成Token才能去使用下载和上传服务,避免了CDN数据被非法利用做为图床的可能。
实现上比较简单,应用程序和资源提供方约定好Token的生成算法,对资源+请求资源的时间+密钥联合在一块儿作签名,资源提供方若是校验到签名不正确或Token过时或资源不匹配都将拒绝服务。
这个模式说的是将身份验证委托给专门的程序或模块来作。使用专门的模块来统一负责登陆受权不只仅能够提供单点登陆的功能,并且服务实现上更简单不须要每次都考虑登陆那套东西。实现上能够看一下Spring Security实现的OAuth 2.0。
总结一下,对于其中的不少模式,咱们能够发现其实在以前的一些介绍或多或少有一些涉及。这里提到的30种模式有些体现的是一些设计细节,有些体现的是一种设计理念,它们大多时候是组合使用的,适合的就是最好的,你们能够细细品味一下每种模式的适合场景,在合适的时候能够想到它或许会有一种豁然开朗的感受。