相信大多数人都认同,与其说架构是设计出来的,不如是说抄袭或拼装而成的。所以我们需要熟悉常用的手段或成熟的框架来解决日常工作中的问题。每个架构师工作经历不同、应对过的业务系统不同、兴趣点不同,手头的弹药库也不同。我列举一些自己认为重要的知识点或框架。
1、单机:高性能、高并发手段
1)单机高性能手段:可以上网查询 C10K 问题,获取相关文章。把进程、线程、池、IO 多路复用相关知识点弄清楚。
2)分清楚 IO 密集型和 CPU 密集型场景:一般互联网应用多为 IO 密集型。但是类似:滴滴出行、股市量化投资、在线游戏之类,属于 IO 密集型和 CPU 密集型并存的场景,甚至对响应时间要求也很高。幸好大多数 CPU 密集型应用也是多租户、区域独立性架构,容易扩展拆分。
3)程序访问存储介质或链路快慢:程序肯定要与存储进行消息交换。一定明白,CPU 高速存储器、内存、SSD 硬盘、机械硬盘、同交换机网络、同机房网络、同城网络、同运营商网络等。细节展开很多内容,包含缓存、CDN、多机房等,从细节编程到部署架构的知识点。
2、集群:高性能、高并发相关
1)负载均衡反向代理:其实把 Nginx 了解就可以了。如果是初创小公司,基本使用云上 SLB 负载均衡(Server LoadBalancer)就可以, 如果需要自建机房,有专门运维负责这些工作,到时候补补 LVS、F5 相关技术即可。
2)服务无状态:以微服务为例来说,服务无状态会带来太多的好处,扩展冗余部署服务会很方便。不谈微服务,就说前后端分离,鉴权这块 token 的实现,其实根本目的也是把用户状态剥离出来,实现服务的无状态化。(提个小插曲,估计老人才了解 J2EE EJB 规范,当初居然专门设计了一个 sessionBean 有状态的服务规范)。
3)任务(服务)拆分:可以理解为服务拆解、功能拆解。其实拆分准则很多,可以按照实际需求来权衡。比如:按照人头分、按照功能划分、按照数据库表划分、按照功能重要性划分、按照功能访问频度划分。不过,水平按照 Gateway、逻辑层、数据层、存储层算基本规范了。
4)常用的语言及框架:了解语言特性,如 Node 语言的快速开发、前后端语言一致带来的便利、多路复用回调的原生支持等;go 语言“goroutines”特性带来的编程便利;Java 优秀的生态及开源框架;C++性能优势等。当然技术选型,跟团队及业务成熟度很大关系。
5)缓存:分布式缓存是提升系统性能利器。基本掌握 Redis 即可,需要知晓 Codis 和 Redis 官方集群部署方式。
6)消息队列:消息队列也是常用提升系统性能利器,如业务逻辑异步化、削峰、解耦等。熟悉 Kafka、RocketMQ即可。
3、高可用手段(集群)
高可用手段核心解决思路是冗余部署,同样的服务冗余多份,会带来服务出错通知、服务自动切换、容错等一系列问题。高可用的实现更有技术含量,现在微服务框架服务治理组件,很多在高可用上做创新突破。(高性能冗余部署为了扩展节点,带来更高的处理性能)
1)服务无状态:当某个服务故障时,自动切换到新的服务,不用产生状态丢失等问题。
2)调用方支持超时、重试配置:由于网络抖动等原因,某个服务可能某次调用不可用,调用方需要重试重新调用。当然超时是调用方通用遇到的故障之一,也会有在其它故障发生,然后发起重试的配置。
3)被调用方需要幂等支持:显而易见,无论是重试、还是调用方自动切换到的新的服务, 被调用方服务幂等支持的必备的。
4)服务状态监测:所有服务都可用,那是理想情况。当某个服务发生故障时,整个体系必须知道这个服务有问题了,重试调用多少次也不会成功了。按照微服务框架来说,需要两方知道这个信息:⑴ 服务注册组件。⑵ 服务上游调用方。当然报警让运维技术恢复是常规。
5)服务状态通知:按照微服务架构,服务的状态 在注册中心都会体现。但是注册中心跟服务之间一般是通过心跳来检测的,有时间延时。另外,服务调用方会缓存注册中心数据,其中就包含服务状态。 所以说,从注册中心获取服务状态,是有延时,可能会造成很多无效的请求。 高效的服务状态机制,很难组件化框架化, 所以这块需要高性能、较实时的自研通信机制或高性能集中存储机制保证。具体可以留言讨论或后续文章探讨。
6)调用方智能路由:除了负载均衡以外,当调用方 A1 知晓下游服务 C1 故障后,可以自动切换到 C2 等服务上。另外,通过服务状态通知机制,最好可以告诉 A2、A3,C1 服务故障了,你们别去尝试了。
7)服务故障恢复有,状态通知机制:这部分就比较简单了。注册中心状态变化后,调用方会慢慢更新注册中心元数据,来获取最新状态。当时,如果有更实时的消息机制,时效性会更高。
系统可靠性(牺牲少部分可容忍体验,降低问题到最低)
8)服务(功能)分类:不管是微服务框架也好,单体框架也好,架构师必须对功能、服务进行分类。分类维度很多,比如:重要程度、QPS 量级、是否可以降级停止等等。
9)应用限流:对于一般规模的应用,在 Gateway 层做即可,从源头保护整个应用。对于超大应用(个人没经验),我觉得架构会更加复杂,可能 Gateway 会分为很多层或多个,甚至有业务中台,层次会更复杂。
10)服务降级:服务是在服务分类的基础上的。比如:百度贴吧的发帖功能,信息流广告功能,紧急情况下是可以降级处理的。可以人工或自动执行。其实 限流也是一种特殊的服务降级。(服务可以是个功能、也可以是接口,就看团队内如何达成一致)
11)接口熔断:熔断一般在接口方法级别,因为调用链路很长,容易引起调用雪崩。让某个接口方法出现问题,我们可以按照预定配置处理业务,快速返回预设结果,防止整个链路的奔溃。
12)弹性扩容:弹性扩容是理想的智能运维,但是具体操作也做大厂才会做相关工作。例如新年红包业务,双十一电商业务,秒杀业务,明星结婚对新浪微博的影响等,这些可以预知或未知的突发流量,如果系统可以自动扩容,那将很是完美。其实很多当前 Docker + kubernetes 的使用案例,还只是方便运维工作量,对弹性扩容这块实践感觉不是很好。
4、存储相关
1)关系型数据库:传统的 MySQL 数据需要掌握。如果做互联网业务,对分库分表肯定有需求,关注 NewSQL,如 TiDB,可以避免分库分表的麻烦。
2)NoSQL 存储:Elasticsearch、MongoDB至少掌握一个。笔者对 Elasticsearch 还是比较看好,综合性 文档数据、列式存储、反向索引 都支持,社区生态也很不错。
3)大数据数据库:强烈建议熟悉 HDFS + HBase + openTSDB。如果熟悉时序数据库 openTSDB 设计以后,对了解各个监控系统如 OpenFalcon 有很大的帮助。基本自研监控系统也难度不是特别大了。
4)内存数据库:有些特殊应用使用内存数据会事半功倍。Redis 提供丰富的数据结构及良好特性,并且有很多插件,巧妙使用可以降低业务代码复杂度。
5)消息队列:消息队列也有存储机制,使用得当,也可以当成存储介质使用。例如:kappa 架构、RocketMQ 事务消息支持等。