热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

是时候思考一下微服务了

微服务在过去几年一直是一个非常热门的话题[1]。何为“微服务的疯狂”,举个例子:众所周知,Netflix在DevOps上的表现非常棒。Netfix可以做微服务。因此:如果我做微服务

?wxfrom=5&wx_lazy=1

微服务在过去几年一直是一个非常热门的话题[1]。何为“微服务的疯狂”,举个例子:众所周知,Netflix在DevOps上的表现非常棒。Netfix可以做微服务。因此:如果我做微服务,我也将非常擅长DevOps。很多情况下,我们盲目的投入巨大的努力来接入微服务模式,然而往往却很少去考虑接入的成本和收益能否有效的帮我们解决当前我们正面临的痛点。
下面,我将详细描述微服务是什么,以及为什么这种模式这么吸引人,最后再聊一些微服务正面临的关键挑战。
如果你正在考虑微服务是否适合你,是否能帮你解决当前面临的问题?那继续往下看,我会用一系列简单的问题来帮你走出你的困惑。这一系列“问题”在文章的最后。
?wxfrom=5&wx_lazy=1
什么是微服务,为什么微服务如此受欢迎?

b2YlTLuGbKDsbJzupnILVFhPtMaRjmvPKYRqTMjibE9pnd8oiawLVrQbOHQe4wBXkBQkzpKCWPKBqWgOLgwccBug

来来来,老司机带你从基础走一波。一个例子:下面这张图是一个假想的视频共享平台的实现方式,左侧是用一个“整体服务”来实现,右侧是多个微服务的形式来实现:
A1HKVXsfHNk8v442xxIkR9IP5Dnxmu10hKvrvkoy5CxH2TIyTFykdymvT222Biavo8wW2icjZnvIMDVLY1cg3ahw
两种系统设计的区别在于左侧是一个整体的大而全的服务。右侧是一组小而多,但每个都是一个具体的服务,每个服务都有特定的角色。
当从系统细节层面来绘制图表时,很容易看出微服务的很多潜在的好处,简单从几个方面来说一下:
独立开发:小型独立组件可由小型独立团队构建。一个小组可以改变“Upload”服务,而不会干扰“Transcode”服务,甚至都不需要知道这个服务。了解组件的时间大大减少,开发新功能也更容易。
独立部署:每个单独的组件都可以独立部署。这样可以以更快的速度和更少的风险发布新功能。比如:“Streaming”组件的修复或功能可以部署,而不需要部署其他组件。
独立的可伸缩性:每个组件可以彼此独立地进行缩放。在需求多并发同时需要发布新的版本时,可以放大“Download”组件,以处理增加的负载,而不必扩大每个组件,这使得弹性缩放更加可行并降低了成本。
可重用性:组件实现一个小的,特定的功能。这意味着它们可以更容易地适用于其他系统、服务或产品。“Transcode”组件可以被其他业务部门使用,甚至可以变成一个新的业务,或者为其他组提供Transcode服务。
从细节层面上来看,微服务模型较之于整体模型的好处显而易见。但是问题来了,如果真的是这样的话 - 为什么微服务模式最近几年才流行?我一生都快走完了(尴尬,貌似暴露年龄了),它才出现?


如果这微服务这么好,为什么之前大家没有这样做呢?

b2YlTLuGbKDsbJzupnILVFhPtMaRjmvPKYRqTMjibE9pnd8oiawLVrQbOHQe4wBXkBQkzpKCWPKBqWgOLgwccBug

这个问题有两种答案。其一是,它强依赖我们最好的技术能力,另一个是最近的技术进步,促使我们能够把它带到一个新的高度。
当我开始写软文来回答这个问题的时候,发现这将会是一个很长的描述,所以从实际的角度出发,我将把它拆成两篇文章,稍后再发表[2]。第1篇文章,我将跳过一些内容,比如:从单个程序到多个程序的过程,忽略ESB和面向服务的体系结构,组件设计和有限的上下文等等。
感兴趣的朋友可以稍后阅读更多关于journey的信息。尽管,在很多方面我们已经这样做了一段时间,但是随着最近容器技术(特别是Docker)和编排技术(如Kubernetes、Mesos、Consul等等)的普及,从技术的角度来看,微服务模式变得更加可行。
因此,如果我们想要实施微服务的话,我们最好仔细慎重考虑是否真的需要。我们已经看到了高大上的“理论效益”,但值得一提的是,未知的挑战又是什么?


微服务有什么问题呢?

b2YlTLuGbKDsbJzupnILVFhPtMaRjmvPKYRqTMjibE9pnd8oiawLVrQbOHQe4wBXkBQkzpKCWPKBqWgOLgwccBug

微服务如此强大、完美,哪里还会有什么挑战?这是目前我见过的最大的问题。
开发的复杂性增加
对于开发者来说事情会变得更加困难。在开发人员想要在远程工作的情况下,或者可能跨越许多服务的功能的情况下,开发人员必须在他们的机器上运行它们,或者连接到它们。这通常比简单地运行单个程序更复杂。
这个挑战可以通过工具[3]得到部分缓解,但随着构成系统的服务数量的增加,开发人员在整个系统运行时面临的挑战也会越来越多。
运维的复杂性增加
对于不开发服务但维护服务的团队来说,潜在的复杂性是一个巨大的挑战。他们不是管理几个正在运行的服务,而是管理数十,数百或数千个正在运行的服务。服务越多,沟通越多,潜在的失败风险就越多。
DevOps的复杂性增加
阅读以上两点,可能会发现运维和开发是分开处理的,尤其是考虑到DevOps作为一种实践的普及(我是DevOps的真爱粉)。DevOps难道不能缓解这一痛点?
目前面临的挑战是,许多组织仍然依靠独立的开发和运营团队来运行 - 而一些组织则更倾向于采用微服务。
对于已经采用了DevOps的组织来说,这仍然很难。既是开发者又是运维者,已经非常艰难(但是要建立好的软件却很关键),但是也必须了解容器编排系统的细微差别,特别是快速发展的系统是非常困难的。这使我想到了下一点。
没专业知识?别玩微服务
当很多事情都由专家完成时,最终的结果也将是极好的。但想象一下,一个机构或组织使用单一的整体系统并不总是可以很顺利的运行。那做些什么能够来改善并让这些事情变得更好呢?通过增加系统服务的数量?但同时也会增加运行的复杂性。
不可否认,通过有效的自动化、监控和编排等,这一切都可以改善。但挑战很少是技术本身——真正的挑战其实是找到能够有效使用技术的人。恰恰目前这些技能需求非常高,可能很难找到符合你需求的人。
现实世界的系统往往界限不清
在我们用来描述微服务的好处的所有例子中,我们都谈到了独立的组件。但是在很多情况下,组件并不是完全独立的。正所谓“纸上得来终觉浅,绝知此事要躬行”,某些领域可能看起来有限,但是当你陷入冗繁的细节时,你会发现他们比你预期的更具挑战性。
这是事情变得非常复杂的地方。事实上,如果你的边界没有明确定义,那么会发生什么情况呢?即使理论上的服务可以单独部署,你会发现,由于服务之间的相互依赖关系,你必须部署一系列微服务作为一个组服务。
这意味着你需要管理协同工作的版本,这些版本的服务在联调时会经过验证和测试,你实际上没有可独立部署的系统,因为要部署新功能,你需要仔细编排许多服务的同时去部署。
状态的复杂性往往被忽略
在前面的例子中,我提到一个功能部署可能需要同时部署多个版本的许多服务。假设合理的部署技术将缓解这种情况,例如蓝/绿部署(大多数服务编排平台很少原生支持这种功能),或者并行运行多个版本的服务,以及决定使用哪个版本的消费通道。
如果服务是无状态的,这些技术可以缓解大量的挑战。但是无国界的服务非常坦率,容易处理。事实上,如果你有无状态的服务,那么我会倾向于考虑跳过微服务,并考虑使用无服务器模型。
实际上,许多服务需要管理。我们的视频共享平台的一个例子可能是订阅服务。订阅服务的新版本可以以不同形状将数据存储在订阅数据库中。如果你同时运行这两个服务,则一次运行两个模式的系统。如果您进行了蓝/绿部署,而其他服务依赖于新形状中的数据,则必须同时更新这些数据,并且如果订阅服务部署失败并回滚,则可能还需要使用级联回滚。
同样,可能你会说,在NoSQL数据库中,这些架构问题会消失,但事实并非如此。不强制执行模式的数据库无法连接无模式系统——这意味着模式往往是在应用程序级而不是数据库级进行管理的。理解数据结构以及如何流转的根本性问题并不能被消除。
沟通的复杂性往往被忽略
当你建立一个相互依赖的大型服务网络时,可能会有很多的服务间通信。这导致了一些挑战。首先,有很多事情可能会失败。我们必须假设网络call可能会失败,这意味着当一个服务call另一个服务时,它应该至少需要重试几次。现在当一个服务可能调用很多服务时,我们最终会遇到一个更加复杂的情况。
用户上传视频共享服务中的视频。我们可能需要运行upload服务,将数据传递到transcode服务,更新订阅,更新建议等等。所有这些调用都需要一定程度的协调,如果过程中任何部分失败,我们都需要重试。
这个重试逻辑可能难以管理。试图同步做事往往会导致站不住脚,失败点太多。在这种情况下,更可靠的解决方案是使用异步模式来处理通信。这里面临的挑战是异步模式本身往往会使系统具有状态性。如前所述,分布式状态系统和有状态系统很难处理。
当一个微服务系统使用消息队列进行服务内通信时,你基本上需要有一个大的数据库(消息队列或代理)将这些服务组合在一起。同样,虽然起初看起来似乎不是一个挑战,但你懂的——出来混迟早都是要还的。X版本的服务可能会写入某种格式的消息,当发送服务更改发送的消息的详细信息时,依赖于该消息的服务也将需要更新。
当然,可以有许多不同格式的消息处理服务,但这很难管理。现在,在部署新版本的服务时,你可能会有两个不同版本的服务尝试处理来自同一队列的消息,甚至可能是由不同版本的发送服务发送的消息。这可能会导致复杂的边缘情况。为了避免这些边缘情况,仅允许特定版本的消息存在可能更容易,这意味着你需要将一组服务的版本作为一个整体来部署,以确保先前版本的消息被正确地屏蔽。
这再次突出表明,独立部署的想法可能不会像预期的那样顺利。
版本控制可能很难
为了缓解前面提到的挑战,版本控制需要非常谨慎的管理。再说一下,看起来貌似有一种趋势——假设遵循像Semver[4]这样的标准或许将可以解决这个问题。然而事实并非完全如此。虽然Semver是一个合理的使用惯例,但是你仍然需要持续的跟踪那些可以一起工作的服务和API的版本。
这可能会使事情变得非常具有挑战性,并且很多时候可能会让你感到困惑——哪些版本的服务可以一起正常工作。
在软件系统中管理依赖关系是非常困难的,无论是节点模块,Java模块,C库还是其他。当一个实体消费独立组件之间的冲突的挑战是很难处理的。
当依赖关系是静态的时候,这些挑战是很难处理的。虽然可以进行修补、更新、编辑等,但是如果依赖关系本身是实时服务,那么你可能根本无法更新它们——你可能需要运行许多版本(上面已经描述过这些挑战),或者直到整个系统得到修复。
分布式事务
在需要跨操作交易完整性的情况下,微服务可能会非常痛苦。分布式状态很难处理,很多小的单位可能会很难进行编排交易。
试图通过使操作幂等性,提供重试机制等来避免这个问题可能听起来很诱人,而且在很多情况下确实可能起作用。但可能有一些场景,你只需要一个事务失败或成功,而不想它处于中间状态。解决这个问题或者在微服务模型中实现它的代价可能是非常高的。
微服务可能是变相的庞然大物
显然,单独的服务和组件可能是孤立部署的,但是在大多数情况下,你将不得不运行某种编排平台,比如Kubernetes。如果你使用的是托管服务,例如Google的GKE 5或Amazon的EKS 6,则会为你处理管理群集的大量复杂性。
但是,如果你要自己管理集群,那么你正在管理一个庞大而复杂的关键任务系统。尽管单个服务可能具有前面所述的所有优点,但你需要非常小心地管理群集。这个系统的部署可能很难,更新可能很难,故障转移可能也很困难等等。
在许多情况下,总体收益仍然存在,但重要的是不要轻视或低估管理另一个庞大而复杂系统的额外复杂性。托管服务可能会有所帮助,但在很多情况下,这些服务都是新兴的不稳定的(例如,Amazon EKS直到在2017年底才宣布)——谁用谁知道。


微服务疯狂之死!

b2YlTLuGbKDsbJzupnILVFhPtMaRjmvPKYRqTMjibE9pnd8oiawLVrQbOHQe4wBXkBQkzpKCWPKBqWgOLgwccBug

只有通过仔细考虑才能避免为微服务而微服务的疯狂。为了帮助解决这个问题,我想了一些你可能想问自己的问题,以及可能的答案:
A1HKVXsfHNk8v442xxIkR9IP5Dnxmu10knqicIJich1HK7pUttHY1ria8kD5nMXUIoAZUcMvpgycK2xCVCIricf0Ow
你可以在这里下载PDF副本:https://github.com/dwmkerr/blog/raw/master/2018/microservice-madness/images/microservice-questions.pdf


最后的想法:不要混淆微服务和架构

b2YlTLuGbKDsbJzupnILVFhPtMaRjmvPKYRqTMjibE9pnd8oiawLVrQbOHQe4wBXkBQkzpKCWPKBqWgOLgwccBug

我故意避免这篇文章中的“a”字。但是,我的朋友Zoltan在校对这篇文章的时候提到了一个很好的观点。
没有微服务体系结构。微服务只是组件的另一种模式或实现,无他。无论是否存在于系统中,都不意味着系统的体系结构得到了解决。
微服务在许多方面与打包和运维的技术过程有关,而不是系统的固有设计。组件的适当边界仍然是工程系统中最重要的挑战之一。
无论你的服务是否在Docker容器中,你总是需要仔细考虑如何将系统放在一起。没有唯一的答案,只有更多的选择。
我希望你看完这篇文章觉得有趣!一如既往,如果你有任何疑问或想法,请在下面评论即可。
相关链接:
  1. https://trends.google.com/trends/explore?date=today%205-y&q=microservice

  2. http://www.dwmkerr.com/the-death-of-microservice-madness-in-2018/#fn:2

  3. http://www.dwmkerr.com/the-death-of-microservice-madness-in-2018/#fn:3

  4. https://semver.org/


原文链接:http://www.dwmkerr.com/the-death-of-microservice-madness-in-2018/


基于Kubernetes的DevOps实践培训

?


本次培训包含:Kubernetes核心概念;Kubernetes集群的安装配置、运维管理、架构规划;Kubernetes组件、监控、网络;针对于Kubernetes API接口的二次开发;DevOps基本理念;微服务架构;微服务的容器化等,点击识别下方二维码加微信好友了解具体培训内容


?


点击阅读原文链接即可报名。

推荐阅读
  • 秒建一个后台管理系统?用这5个开源免费的Java项目就够了
    秒建一个后台管理系统?用这5个开源免费的Java项目就够了 ... [详细]
  • 为什么多数程序员难以成为架构师?
    探讨80%的程序员为何难以晋升为架构师,涉及技术深度、经验积累和综合能力等方面。本文将详细解析Tomcat的配置和服务组件,帮助读者理解其内部机制。 ... [详细]
  • Python 数据可视化实战指南
    本文详细介绍如何使用 Python 进行数据可视化,涵盖从环境搭建到具体实例的全过程。 ... [详细]
  • 提升 Kubernetes 集群管理效率的七大专业工具
    Kubernetes 在云原生环境中的应用日益广泛,然而集群管理的复杂性也随之增加。为了提高管理效率,本文推荐了七款专业工具,这些工具不仅能够简化日常操作,还能提升系统的稳定性和安全性。从自动化部署到监控和故障排查,这些工具覆盖了集群管理的各个方面,帮助管理员更好地应对挑战。 ... [详细]
  • 本文探讨了 TypeScript 中泛型的重要性和应用场景,通过多个实例详细解析了泛型如何提升代码的复用性和类型安全性。 ... [详细]
  • 面试题总结_2019年全网最热门的123个Java并发面试题总结
    面试题总结_2019年全网最热门的123个Java并发面试题总结 ... [详细]
  • 浅析python实现布隆过滤器及Redis中的缓存穿透原理_python
    本文带你了解了位图的实现,布隆过滤器的原理及Python中的使用,以及布隆过滤器如何应对Redis中的缓存穿透,相信你对布隆过滤 ... [详细]
  • Java高并发与多线程(二):线程的实现方式详解
    本文将深入探讨Java中线程的三种主要实现方式,包括继承Thread类、实现Runnable接口和实现Callable接口,并分析它们之间的异同及其应用场景。 ... [详细]
  • 如何将TS文件转换为M3U8直播流:HLS与M3U8格式详解
    在视频传输领域,MP4虽然常见,但在直播场景中直接使用MP4格式存在诸多问题。例如,MP4文件的头部信息(如ftyp、moov)较大,导致初始加载时间较长,影响用户体验。相比之下,HLS(HTTP Live Streaming)协议及其M3U8格式更具优势。HLS通过将视频切分成多个小片段,并生成一个M3U8播放列表文件,实现低延迟和高稳定性。本文详细介绍了如何将TS文件转换为M3U8直播流,包括技术原理和具体操作步骤,帮助读者更好地理解和应用这一技术。 ... [详细]
  • Java Socket 关键参数详解与优化建议
    Java Socket 的 API 虽然被广泛使用,但其关键参数的用途却鲜为人知。本文详细解析了 Java Socket 中的重要参数,如 backlog 参数,它用于控制服务器等待连接请求的队列长度。此外,还探讨了其他参数如 SO_TIMEOUT、SO_REUSEADDR 等的配置方法及其对性能的影响,并提供了优化建议,帮助开发者提升网络通信的稳定性和效率。 ... [详细]
  • 深入解析CAS机制:全面替代传统锁的底层原理与应用
    本文深入探讨了CAS(Compare-and-Swap)机制,分析了其作为传统锁的替代方案在并发控制中的优势与原理。CAS通过原子操作确保数据的一致性,避免了传统锁带来的性能瓶颈和死锁问题。文章详细解析了CAS的工作机制,并结合实际应用场景,展示了其在高并发环境下的高效性和可靠性。 ... [详细]
  • 在处理 XML 数据时,如果需要解析 `` 标签的内容,可以采用 Pull 解析方法。Pull 解析是一种高效的 XML 解析方式,适用于流式数据处理。具体实现中,可以通过 Java 的 `XmlPullParser` 或其他类似的库来逐步读取和解析 XML 文档中的 `` 元素。这样不仅能够提高解析效率,还能减少内存占用。本文将详细介绍如何使用 Pull 解析方法来提取 `` 标签的内容,并提供一个示例代码,帮助开发者快速解决问题。 ... [详细]
  • 在当今的软件开发领域,分布式技术已成为程序员不可或缺的核心技能之一,尤其在面试中更是考察的重点。无论是小微企业还是大型企业,掌握分布式技术对于提升工作效率和解决实际问题都至关重要。本周的Java架构师实战训练营中,我们深入探讨了Kafka这一高效的分布式消息系统,它不仅支持发布订阅模式,还能在高并发场景下保持高性能和高可靠性。通过实际案例和代码演练,学员们对Kafka的应用有了更加深刻的理解。 ... [详细]
  • 线程能否先以安全方式获取对象,再进行非安全发布? ... [详细]
  • 2021年Java开发实战:当前时间戳转换方法详解与实用网址推荐
    在当前的就业市场中,金九银十过后,金三银四也即将到来。本文将分享一些实用的面试技巧和题目,特别是针对正在寻找新工作机会的Java开发者。作者在准备字节跳动的面试过程中积累了丰富的经验,并成功获得了Offer。文中详细介绍了如何将当前时间戳进行转换的方法,并推荐了一些实用的在线资源,帮助读者更好地应对技术面试。 ... [详细]
author-avatar
拍友2502926823
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有