大家都在学SpringCloud。好像学了SC之后就牛逼了,感觉不可思议。但是微服务只占整个企业级应用的一小部分。微服务引入的问题多于解决的问题,你会遇到各种瓶颈。微服务解决了计算节点的问题,但根源在存储节点。当业务规模越来越大时,存储、编码、管理都会成为问题。接下来说说一些放之四海而皆准的原则,没必要贴上“XX公司最佳实践”的标签。下图是微服务相关的数据膨胀导致的图,简单却不简单。中小公司只要具备这些要素,就可以发挥得很好;对于大公司来说,因为规模大,每个组件都会遇到瓶颈,所谓的专项优化离不开它的本质。那我们开始吧。注意这张图只是主要数据路径的一个子集,其他的还包括CDN、通信层等,这里就不一一列举了。这张图不包含特定字段的具体结构,是一个整体的概览。我们先从数据库容量的瓶颈说起,看看微服务在其中的占比。数据库用户数据存储在数据库中。这么多年,NoSQL并不能消除开发者的恐惧,所以MySQL之类的仍然是大部分公司的首选存储。假设您的业务发展良好,这会更有趣。项目初期,玩sql越多,给后人埋下的坑就越多。因为sql的功能太丰富了,一不小心就会大展身手。你会发现,森林越大,对SQL的标准要求就越高。公司内部严禁使用某些正式宣布的功能。市场发展的很好,报应终于来了。曾经是技能的东西现在变成了负担。慢查询,全文扫描,tricktokill。我想添加缓存,但发现无法启动;想分库分表,但是发现表之间的关系错综复杂。对于小而宽的手表,第一步是将孔洞填满。超过3张表的联合查询服务极有可能不合理。在添加缓存和分库分表之前,还是要重新设计数据表。忘了什么数据库范式吧,我们会有两种表:小表和宽表。小表提供了最基本的数据,一个简单的KV可能就够了。有些联合查询可以直接在程序中循环拼接。在程序中,循环1000次10毫秒的查询比耗时6秒的单个查询要强得多。这就是分布式系统的特点,小批量查询耗时小,比挂在那里更有生命力。宽表通过冗余为重要功能提供通用分析数据。这种表一般字段比较多,写入时通过拼接得到冗余数据,一般用于读多写少的场景。完成这一步后,就可以进行下一步的工作了。分库分表,分库分表很可能会引入某种中间件,因为仅仅把数据库分开是不够的。同时需要HA和FailOver等特性。分库分为垂直分库和水平分库。垂直方面是业务拆分,即根据业务逻辑将一些表拆分到其他库中;横向是容量,即通过分库分表的方式,让数据有一种扩展的方式。数据必须有可衡量的切分维度,否则会过于分散或过于倾斜,影响后续处理。数据同步分合。例如,某些报告服务需要全量数据。不得不说,不同业务通过共享数据库共享数据是一种非常愚蠢的想法。这时候就需要一些数据同步工具了。数据同步组件可以说是一个公司必备的组件。有基于最后更新时间的高延迟同步工具,也有基于binlog的低延迟同步工具。一些公司为了稳定也有所谓的多房间同步。数据同步最怕异常,因为大多数同步都有顺序要求。万事顺遂,皆大欢喜;一旦出现异常,需要通过其他手段来保证异常期间的数据同步和延时。这都是肮脏的工作,自动化有时会适得其反,监控是第一位的。分层数据存储可以预见,即使分库分表,还是会很快达到瓶颈。分库分表之后,你的一些统计功能可能就用不到了,这是一些传统管理系统的硬伤。一个分层的数据存储层是必要的。你的一些业务,一个分支可能用了MySQL,另一个条件就变成了ES。不同的数据库做不同的事情。RDBMS只存储和查询原始数据,是一个平坦快速的数据通道;一个特定的独立高性能数据库做一些聚合和科学计算;分布式类RT存储用于存储一些中等规模的数据,并提供一些延迟搜索功能;海量存储系统,存储系统所有历史记录,并提供离线分析功能。不要认为某种存储类型可以解决所有问题,那是骗人的。存储部分的复杂度不是普通微服务可以比的。谁来保证分层数据存储设计?除了一部分业务通过MQ分发数据,还是依赖于我们的数据同步组件。缓存但是对DB的压力太大了,不得不考虑缓存。缓存不能乱用。有两个原则:一是缓存不能侵入业务,即不能包含业务逻辑;另外就是缓存的命中率一定要高,否则会适得其反。缓存是高并发、高速接口的补充,是系统稳定的必要但不充分条件。除了Redis等外部缓存集群,jvm中的缓存也是一个比较重要的地方。缓存的存在是由于I/O设备的慢。一般放在内存中,断电后消失。缓存涉及源数据库和缓存数据库之间的数据同步。通常,源库更新时,会同时删除缓存中的相关旧数据,以便下次读取时读取到最新的数据。缓存最大的限制是它的容量,而且非常昂贵。如果业务模型固定,部分kv存储采用LevelDB或HBase等方案,会显着节省成本。模块化是时候对项目进行模块化了。毕竟几百个程序员共享一个代码库,风险已经很大了。模块化通常是按照业务线来拆分的。比如支付模块和报表模块的拆分。模块拆分后,相似的模块共享数据库。但是更多的是通过冗余数据来解决,可以将业务解耦,让一部分有问题,另一部分可以很好的运行。就好像隔壁发生了一起命案,第二天就可以正常上班了。需要想办法在模块之间进行交互,比如使用HttpClient、OkHttp等,重要的是统一。统一之后,就会有一个高大上的名字:RPC。一个小模块很可能发展成一个大的业务线,也有可能无人问津。MQ模块之间共享数据或数据交互的另一种方式是MQ。除了调峰等功能,MQ改变的更多的是一种交互方式,一种业务的解耦。几乎每家公司都在使用Kafka,最大吞吐量可达几十万。RabbitMQ、RocketMQ等更多的用在对可靠性要求非常高的场景,但是对机器的消耗比较大。MQ资源一般要求绝对的高可靠性。作为基础设施,一旦出现问题,就会造成非常严重的事故。设计时要考虑异常情况下的数据处理流程和MQ恢复后的补偿策略。合理的做法是将MQ集群设计得小一些,避免不同业务、不同可靠性级别的消息相互影响。MQ应该在业务和功能上相互隔离,实现最小的服务集合。为了避免MQ崩溃对正常业务的影响,非重要环节的MQ不能阻断业务的正常进行。此类消息通常通过异步线程发送。微服务我们使用消息和模块化将系统拆分为多个项目。统一管理这些项目,统一它们的交互方式和对它们的治理,就是微服务的范畴。微服务是标准化多模块项目的过程。非标准服务和微服务系统必须共存一段时间。如何保证新旧服务的更替是一个管理问题。功能组件根据SpringCloud的描述,如果一个服务想要被发现,它需要将自己注册到一个通用注册中心,其他服务可以从同一个地方获取它的实例,然后调用它。真正产生调用的函数是RPC的函数。RPC需要考虑超时、重放、熔断等一系列功能。在一些访问量非常大的节点上,也可以考虑预热。RPC必须能够产生一些统计数据,比如TPS,QPS,TP值等,显然SpringCloud是欠缺的,需要借助外部系统进行分析。外部请求流向内部之前,需要经过一层网关处理。一些常用的操作,比如权限、限流、灰度等,都可以在网关层处理。服务治理微服务最重要的特性是它们的治理能力。服务治理的基础是监控信息。通过统计每次调用的大小、耗时、分布情况,可以得到服务的大致拓扑结构。通常以下信息是最有用的:1、QPS,时间序列的qps分布,最高间隔qps2,平均响应时间,接口平均响应时间,最大和最小耗时3,TP值分布,90%,99%等requests是在x时间内完成的。通过以上信息,可以对服务进行概要分析。是扩容、缩容、专项管理的数据基础。微服务提出的另一个问题是调用链,即一个请求的真实路径。在分布式环境下排错会很困难,调用链可以帮助研发快速定位问题,帮助理解业务的数据流向。服务治理的目的是发现不合理的请求和分配。比如某个界面耗时过长;某个接口有大量请求,需要缓存;某个功能依赖的链太长,需要业务优化。服务治理需要借助大量的外部分析工具,更通用的业务模型需要大数据平台的支持。我们也把监控/告警放在了服务治理的部分。在《这么多监控组件,总有一款适合你》中,我们详细讨论了监控部分的技术选项。日志记录微服务的另一个问题是日志记录过于碎片化。一个核心业务可能有几百个实例,你不可能打开100个终端查看日志。这就涉及到日志的收集。日志收集功能是将分散的日志收集到一个地方,其主要挑战是数据量。通常日志分为两部分,一部分是全量,可以通过定时同步等方式备份到日志堡垒机或者hdfs;另一部分是过滤后的日志,比如一些异常信息,集中到某个处理平台进行告警。许多研发开发人员喜欢将用户行为数据输出到日志文件中。这些日志收集起来之后,会通过流计算或者离线计算得到一些推荐和模型。日志信息已经进入大数据处理的范畴,我们不再过多描述。持续集成如果有一定规模的公司,技术团队有什么系统值得做,那么发布系统算一个。在《发布系统有那么难么?》中,讨论了一种可能的模型。发布系统是一个包裹着一堆脚本的方便的皮肤。一些流程工具、发布验证、CI/CD功能可以方便的添加到自己的发布系统中。在很多微服务推广文章中,虚拟化(Docker)等是没有必要讲的,虚拟化减少了服务编排的时间,可以轻松扩缩容,但是对监控、日志收集、网络拓扑等要求比较高.建议是系统的最后一步,而不是第一步。你的制度是否灵活,还与公司的文化环境有关。如果最后一行审批流程要一两周,那做敏捷持续集成系统就没那么必要了。InfrastructureInfrastructure更多的是指运维系统,它是支撑整个系统健康发展的基石。我倾向于不将基础运维与基础架构分开,因为它们的模型和文化是公司研发环境的基石。其他基础组件,如配置中心、调度中心、分布式锁管理等,都对可靠性有更高的要求。END系统看起来很简单,而且有固定解。但问题是,很多企业从成立到倒闭,玩了这么多年,还是不懂。真可惜。
