问题一:异构系统的不标准问题
在软件开发和运维过程中,存在许多标准化问题。例如,软件和应用缺乏统一的标准,通讯协议和数据格式各不相同,开发和运维的过程和方法也不一致。不同的软件和编程语言带来了不同的兼容性问题,以及各自不同的开发、测试、运维标准。这种差异导致我们在开发和运维时采用不同的方法,从而增加了架构的复杂度。
举例来说,有的软件需要通过修改 .conf 文件来更改配置,而另一些则需要调用管理 API 接口。在通讯方面,不同软件采用不同的协议,即使在相同的网络协议中,也可能出现不同的数据格式。不同的技术团队由于使用了不同的技术栈,也会导致开发和运维方式的多样化。这些差异都会使我们的分布式系统架构变得极其复杂。因此,分布式系统架构需要制定相应的规范。
例如,我注意到许多服务的 API 返回错误时不使用 HTTP 的错误状态码,而是返回 HTTP 200,然后在响应体(HTTP Body)中的 JSON 字符串中包含类似 “error, bla bla error message” 的错误信息。这种设计不仅反直觉,而且极大地影响了监控的实现。实际上,现在应该使用 Swagger 等规范来标准化 API。
另一个例子是配置管理。很多公司在软件配置管理中只是采用简单的 key-value 形式,这种灵活性虽然很高,但也很容易被滥用。例如,不规范的配置命名,不规范的值,甚至在配置中直接嵌入前端展示内容。一个合理的配置管理应分为三层:底层和操作系统相关,中间层和中间件相关,最上层则是业务应用相关。底层和中间层的配置不应让用户随意修改,而是通过模板选择。比如,操作系统相关的配置应形成标准模板供用户选择,而非随意修改。只有当配置管理形成了规范,我们才能有效控制各种系统的复杂性。
再比如,数据通讯协议通常包括协议头和协议体。协议头定义了基本的协议数据,而协议体则包含业务数据。我们需要在协议头的定义上制定严格的标准,以便所有使用该协议的团队都遵循同一套规则。这种规范化能够帮助我们更好地进行请求监控、调度和管理。
通过这些规范化措施,我们可以更好地控制分布式系统的复杂度,提高系统的可维护性和稳定性。
问题二:系统架构中的服务依赖性问题
在传统的单体应用中,如果某台服务器宕机,整个应用就会停止运行。然而,这并不意味着分布式架构下就不会出现类似的问题。在分布式系统中,各个服务之间通常存在依赖关系。当依赖链上的某个服务发生故障时,可能会引发“多米诺骨牌”效应,导致一系列连锁反应。因此,在分布式架构中,服务的依赖关系也可能带来许多问题。
一个典型的情况是,非关键业务被关键业务依赖,结果导致非关键业务变得像关键业务一样重要。服务依赖链中常会出现“木桶效应”,即整个系统的服务水平协议(SLA)由表现最差的那个服务所决定。这属于服务治理的范畴。有效的服务治理不仅要求我们定义每个服务的重要程度,还需要清晰地定义和描述关键业务的主要调用路径。没有这样的治理和管理措施,我们将难以有效地运维和管理整个系统。
需要特别注意的是,尽管许多分布式架构在应用层面做到了业务隔离,但在数据库层面却没有。如果一个非关键业务因为数据库问题而导致整个数据库负载过高,可能会拖垮整个系统,导致全站不可用。因此,在数据库层面也需要进行相应的隔离。最佳实践是每条业务线使用独立的数据库。这也是亚马逊服务器的实践之一:系统之间禁止直接访问对方的数据库,只能通过服务接口进行交互。这种做法符合微服务架构的要求。
总而言之,我们不仅要拆分服务,还需要为每个服务分配独立的数据库,从而避免不同服务之间相互干扰。这样才能真正实现业务隔离,提升系统的可靠性和稳定性。
问题三:故障发生的概率更大
在分布式系统中,由于使用的机器和服务数量庞大,故障发生的概率比传统的单体应用更高。虽然分布式系统可以通过隔离来减小故障的影响范围,但由于组件繁多、结构复杂,故障的发生频率反而更高。另一方面,由于管理难度大,系统架构全貌难以掌握,因此错误更容易发生。对于分布式系统的运维而言,这几乎是噩梦般的挑战。随着时间的推移,我们会逐渐认识到以下几点:
运维团队在分布式系统中面临巨大的压力,几乎时刻都在处理各种大小不一的故障。很多大公司试图通过添加大量的监控指标来应对这些问题,有时甚至设置了几万个监控点。但这种做法实际上是“蛮力”策略。一方面,过多的信息会导致信息过载,反而难以获取有价值的洞察;另一方面,服务水平协议(SLA)要求我们定义关键指标(Key Metrics),即最为重要的性能和状态指标。然而,很多公司在实际操作中忽视了这一点。
这种做法反映了运维思维上的惰性,因为它只关注“救火阶段”而不是“防火阶段”。正所谓“防火胜于救火”,我们需要在设计和运维系统时预先考虑故障的发生,即所谓的“设计即为容错”(Design for Failure)。在系统设计中,就应考虑如何减轻故障的影响。如果无法完全避免故障,也应通过自动化手段尽快恢复故障,将影响控制在最小范围内。
随着系统中机器和服务数量的增加,我们会发现人类的局限性逐渐成为管理的瓶颈。人类无法对复杂系统进行面面俱到的管理,这时,自动化手段就显得尤为重要。“人管理代码,代码管理机器,人不直接管理机器”,这一理念意味着我们应通过自动化和代码治理来管理分布式系统的复杂性,将人的作用集中在管理代码和策略上,而将具体的系统操作交由自动化系统执行。这种方式不仅能够提升系统的稳定性和可控性,还能有效减轻运维团队的负担。
问题四:多层架构的运维复杂度更大
通常情况下我们可以将系统分为四个层次:基础层、平台层、应用层和接入层。
对于这四个层次,我们需要明确一点:任意一层出现问题,都会影响整个系统的运行。如果没有一个统一的视图和管理机制,各层的运维就会被割裂,导致更大的复杂性。
许多公司在团队分工上是按照技能进行划分的,比如产品开发、中间件开发、业务运维、系统运维等子团队。这种分工方式会导致每个团队只关注自己负责的部分,造成整个系统缺乏协同,信息不畅。当某个环节出现问题时,整个系统就像“多米诺骨牌”一样,一个故障会引发连锁反应,影响范围不断扩大。
由于缺乏统一的运维视图,团队无法清楚地了解一个服务调用在每个层次和资源中是如何流转的。因此,当出现故障时,定位问题和沟通协调会消耗大量时间和精力。此前我在某云平台工作时曾遇到过类似的情况:从接入层到负载均衡,再到服务层和操作系统层,每个环节的 KeepAlive 参数设置不一致,导致软件的实际运行行为与文档描述不符。工程师在排查问题的过程中屡屡受挫,以为解决了一个问题,结果又出现了新的问题。经过多次反复排查和调试,最终才将所有 KeepAlive 参数设置成一致,耗费了大量时间。
由此可见,分工本身不是问题,问题在于分工后的协作是否统一和规范。这一点尤其值得重视。在系统运维中,确保各层次之间的协调一致、标准化管理以及对系统的整体视图掌握,是避免运维混乱、提高效率和系统稳定性的关键。
本网站的文章部分内容可能来源于网络和网友发布,仅供大家学习与参考,如有侵权,请联系站长进行删除处理,不代表本网站立场,转载者并注明出处:https://www.jmbhsh.com/shenghuokepu/34336.html