微服务全做错了!谷歌提出新方法,成本直接降9倍!
- 谷歌坐不住了:我们做的微服务都错了!
- 亚马逊Prime Video团队:放弃微服务,改用单体
- 放弃微服务的,不止谷歌、亚马逊
- 微服务的虚假繁荣:从单体变成“分布式单体”
- 谷歌提出了一种新的微服务
- 基础架构重新思考的一年
2023,微服务“水逆”之年。
长期以来,不管大厂还是小厂,微服务都被认为是云原生服务应用程序架构的事实标准,然而2023,不止那位37signals的DHH决心下云,放弃微服务,就连亚马逊和谷歌等这些云巨头,正在带头开始革了微服务的命。
谷歌坐不住了:我们做的微服务都错了!
“在编写分布式应用程序时,传统观点认为将应用程序拆分为可以独立推出的独立服务。这种方法的初衷是好的,但像这样基于微服务的体系结构往往会适得其反,带来的挑战抵消了体系结构试图实现的好处。
今年6月,一群谷歌员工(由谷歌软件工程师Michael Whittaker领导)发表了一篇名为“Towards Modern Development of Cloud Applications”的论文,开篇就对当下的微服务架构开怼。
文章认为,从架构上讲,微服务本身设置就有问题,它是一个没有边界的结构:“从根本上说,这是因为微服务将逻辑边界(如何编写代码)与物理边界(如何部署代码)混为一谈。”
因此,谷歌的工程师们提出了一种堪称“微服务2.0”的方法。将应用程序构建为逻辑整体,但将其交给自动化运行时,后者可以根据应用程序所需的内容和可用的内容来决定在哪里运行工作负载。
基于新提出的结构,他们能够将系统的延迟降低15倍,成本降低9倍。
“从有组织的模块化代码开始,我们就可以将部署架构作为实现细节,”Google开发人员倡导者Kelsey Hightower在10月份对这项工作表示了下一步计划。
这群谷歌开发者们发现了将应用程序拆分为独立部署的服务方法缺点太明显,并给出了非常有创新性的3条原则:
(1)鼓励开发人员编写分为逻辑组件的单片应用程序(2)将物理分布和执行模块化单片的挑战推迟到运行时(3)原子部署应用程序。
这三个指导原则带来了许多好处,并会为未来的开发创新打开大门。
亚马逊Prime Video团队:放弃微服务,改用单体
无独有偶,同样是在6月,亚马逊流媒体平台 Prime Video发布的一则案例研究似乎改变了风向:“我们放弃了无服务器、微服务架构,改用单体架构取而代之,此举为客户节省90%的运营成本,还简化了系统复杂度”。
单体应用对微服务的“反戈一击”,还是亚马逊团队提出来的,再次让这个话题迅速引爆技术圈。
整个案例看下来,微服务跟降本增效似乎也扯不到一起去。问题出在哪里?
Prime Video 团队需要一个监控视频流质量问题的工具,由于视频数量太大,就要求该工具有很强的可扩展性。
最初这项工作是由一组分布式组件完成的,这些组件由AWS Step Functions(一种无服务器编排服务,AWS Lambda无服务器服务)编排,分分钟就能搭出一个有模有样的监控系统。但谁能想到,Step Function 伸缩问题竟然成为最大的绊脚石。
具体来看,一是对于视频流的每一秒,需要很多并发的 AWS Step Function,所以很快就达到了账户限制;二是 AWS Step Function 是按照状态转换向用户收费的,太贵了实在用不起。
无奈之下,Prime Video开始考虑用单体的解决方案以降低成本和增加应用的扩展能力,在经历了反复试验后,团队最终决定重建Prime Video的整个基础设施。
亚马逊在博客文章总结道:“微服务和无服务器组件是可以大规模工作的工具,但是否在整体上使用它们必须根据具体情况而定……将服务迁移成单体让我们的基础设施成本降低了 90%以上,还提升了我们的伸缩能力。”
这就说明,至少在视频监控领域,单体架构比微服务、无服务器主导的方法产生了更高的性能、更能降本增效。
始终鼓吹下云和反对微服务化的DHH( Ruby on Rails创始人,David Heinemeier Hansson)一针见血地指出:连亚马逊自个都觉得微服务或无服务器“扯淡”了。
放弃微服务的,不止谷歌、亚马逊
最近几年,无数的中小团队在权衡利弊后选择放弃微服务。
Uber 就是其中一家,此前 Uber 通过构建微服务来完成很小的需求或功能,甚至出现很多由一个人构建维护的微服务。这些微服务的存在给Uber带来了更多的挑战,比如监控、测试、持续集成 / 持续交付(CI/CD)、服务级别协议(SLA)等。
踩了微服务的“坑”之后,Uber 团队对新服务进行了更加深思熟虑的规划:不再只是完成一件事,而是使其服务于一项业务功能,由 5-10 个工程师负责维护,还总结出了血泪教训:要在正确的时间选择正确的解决方案来构建产品。
办公管理软件公司 Managed by Q 的应用程序是一个部署在 ECS 上的 Django 单体。为了赶上现代化开发实践的步伐,他们转向微服务架构。但他们很快发现,每多一个新服务,就会增加一些基础设施,而且开发一个跨多个服务的功能需要做更多的工作。
结果,在转向微服务两年之后,他们开始合并微服务。一些微服务被合到了单体中,其他的则合并成较大的服务。他们也在实践中得出经验:不能理所当然地认为微服务就是正确的选择。
本来想把微服务当银弹,结果工程开销太大,得不偿失。以上提到的企业最大的问题是在只有20位工程师的环境中实现了几十个微服务,有种杀鸡焉用牛刀的错位感。
微服务的虚假繁荣:从单体变成“分布式单体”
随着越来越多“逃离微服务”的案例发生,人们对于2005年就提出的“微服务”再度审视,甚至批评。
比如开头提到的谷歌工程师们,就在他们的论文中列出了目前微服务方法的缺陷,包括:
性能: 通过网络将数据序列化并发送到远程服务会损害性能,如果应用程序变得足够复杂,甚至可能导致瓶颈。
理解追踪 :众所周知,在分布式系统中,考虑到微服务之间的许多交互,很难追踪Bug。
管理问题 :应用程序的不同部分可以按照自己的时间表进行更新,这被认为是一个优势。但这导致开发人员不得不管理大量的二进制文件,每个二进制文件都有自己的发布时间表。祝您好运,使用本地运行的服务运行端到端测试。
API变得脆弱 :微服务互操作性的关键是,一旦建立了微服务,API就不能改变,让它们破坏任何其他依赖API的微服务。因此,API只能用更多的API进行扩展,从而产生膨胀。
看起来跟之前提到的“过度设计”的概念不谋而合。
事实上有些团队在将集中式单体应用拆分为微服务时,首先进行的往往不是建立领域模型,而只是按照业务功能将原来单体应用的一个软件包拆分成多个所谓的“微服务”软件包,而这些“微服务”内的代码高度耦合,逻辑边界不清晰,本质上还是单体架构模式 ,所以只是实现了“表面繁荣”,并没有实现想要的结果。
正如Sam Newman在《构建微服务》一书中提到的那样,架构需要满足一定的前提条件,否则就可能过度设计。
谷歌提出了一种新的微服务
业内有这样一种依旧支持微服务架构的观点:微服务需要与之匹配的规模。“如果你知道最终会以一定的规模来做这件事,在开始时可能会以不同的方式来构建它。但问题就在于,你知道如何做这件事情吗?你知道你将以多大的规模来运营它吗?”
事实上在许多应用程序中,尤其是内部应用程序,开发成本往往会超过了运行时成本。
谷歌的论文恰恰解决了这个问题,编程模式和部署模式的分开,可以让开发人员更加轻松,同时让运行时基础设施的“赌注”找到运行这些应用程序的最具成本效益的方法。
正如谷歌研究人员所写道的:“通过将所有执行责任委托给运行时,我们的解决方案能够提供与微服务相同的好处,但性能更高,成本更低。”
基础架构重新思考的一年
今年进行了许多基础架构的重新思考,微服务并不是唯一被质疑的泡沫。例如,云计算也受到了审查。
6月,同时运行Basecamp和Hey电子邮件应用程序的37signals公司采购了一批戴尔服务器,并离开了云计算,打破了几十年来大家抛弃老旧拥抱新故事的传统。
David Heinemeier Hansson在一篇博客文章中解释道:“这是云营销的常用话术:它会变得容易得多,几乎不需要任何人来操作。”“(但事实是)我从来没有见过。37signals没有,来自大型互联网公司的人也没有见过。云有一些优势,但它通常不会减少运维人员。”
当然,DHH是一名赛车手,有可能更喜欢裸机。但也有不少拥趸愿意支持这一赌注。今年晚些时候,Oxide Computers推出了他们的新系统,希望能为其他人提供类似的服务:运行云计算工作负载,但在自己的数据中心更具成本效益。
此外,在云账单即将到期的情况下,这种情绪似乎更加强烈。2023年,随着越来越多的组织转向KubeCost等公司来控制其云支出,FinOps成为一件引人注目的事。一位DataDog的客户收到6500万美元的云监控账单的消息,也再次让业界无数人惊到了。
也许对于一个创造数十亿收入的机构来说,6500万美元的可观测性账单可能是值得的。但是对于架构师而言,面对过去十年中做出的工程决策带来的技术债,也许是时候做出一些调整的决定。
当然,微服务也不例外。
参考链接:
https://thenewstack.io/year-in-review-was-2023-a-turning-point-for-microservices/
https://dl.acm.org/doi/10.1145/3593856.3595909?utm_source=thenewstack&utm_medium=website&utm_content=inline-mention&utm_campaign=platform
相关文章:

k8s 标签和选择器
标签(Label)是附加在Kubernetes对象上的一组名值对,其意图是按照对用户有意义的方式来标识Kubernetes对象,同时,又不对Kubernetes的核心逻辑产生影响。管理这些对象时,很多时候要针对某一个维度的条件做整体操作,例如,将某个版本的程序整体删除,这种情况下,如果用户能够事先规划好标签的使用,再通过标签进行选择,就会非常地便捷。Kubernetes api server支持两种形式的标签选择器,equality-based 基于等式的 和 set-based 基于集合的。

常见的七种加密算法及实现
**数字签名**、**信息加密** 是前后端开发都经常需要使用到的技术,应用场景包括了用户登入、交易、信息通讯、`oauth` 等等,不同的应用场景也会需要使用到不同的签名加密算法,或者需要搭配不一样的 **签名加密算法** 来达到业务目标。这里简单的给大家介绍几种常见的签名加密算法和一些典型场景下的应用。## 正文### 1. 数字签名**数字签名**,简单来说就是通过提供 **可鉴别** 的 **数字信息** 验证 **自身身份** 的一种方式。一套 **数字签名** 通常定义两种 **互补

7min到40s:SpringBoot 启动优化实践
然后重点排查这些阶段的代码。先看下。

SpringBoot系列教程之Bean之指定初始化顺序的若干姿势
之前介绍了@Order注解的常见错误理解,它并不能指定 bean 的加载顺序,那么问题来了,如果我需要指定 bean 的加载顺序,那应该怎么办呢?本文将介绍几种可行的方式来控制 bean 之间的加载顺序。

在Java中使用WebSocket
WebSocket是一种协议,用于在Web应用程序和服务器之间建立实时、双向的通信连接。它通过一个单一的TCP连接提供了持久化连接,这使得Web应用程序可以更加实时地传递数据。WebSocket协议最初由W3C开发,并于2011年成为标准。

3种方案,模拟两个线程抢票
在多线程编程中,资源竞争是一个常见的问题。资源竞争发生在多个线程试图同时访问或修改共享资源时,可能导致数据不一致或其他并发问题。在模拟两个线程抢票的场景中,我们需要考虑如何公平地分配票,并确保每个线程都有机会成功获取票。本篇文章将通过三种方式来模拟两个线程抢票的过程,以展示不同的并发控制策略。使用 Synchronized 来确保一次只有一个线程可以访问票资源。使用 ReentrantLock 来实现线程间的协调。使用 Semaphore 来限制同时访问票的线程数量。

替代Druid,HakariCP 为什么这么快?
这次源码探究,真的感觉看到了无数个小细节,无数个小优化,积少成多。平时开发过程中,一些小的细节也一定要“扣”。

Java中volatile 的使用场景有哪些?
volatile是一种轻量级的同步机制,它能保证共享变量的可见性,同时禁止重排序保证了操作的有序性,但是它无法保证原子性。所以使用volatilevolatile。

JDK22 正式发布了 !
Java 22 除了推出了新的增强功能和特性,也获得 Java Management Service (JMS) 的支持,这是一项新的 Oracle 云基础设施远程软件服务(Oracle Cloud Infrastructure, OCI) 原生服务,提供统一的控制台和仪表盘,帮助企业管理本地或云端的 Java 运行时和应用。使包含运行时计算值的字符串更容易表达,简化 Java 程序的开发工作,同时提高将用户提供的值编写成字符串,并将字符串传递给其他系统的程序的安全性。支持开发人员自由地表达构造器的行为。

Jackson 用起来!
你可以创建自定义序列化器和反序列化器以自定义特定字段或类的序列化和反序列化行为。为此,请创建一个实现或接口的类,并在需要自定义的字段或类上使用和注解。@Override// ...其他代码...优势性能优异:Jackson在序列化和反序列化过程中表现出优秀的性能,通常比其他Java JSON库更快。灵活性:通过注解、自定义序列化器/反序列化器等功能,Jackson提供了丰富的配置选项,允许你根据需求灵活地处理JSON数据。易于使用:Jackson的API设计简洁明了,易于学习和使用。

拜托!别再滥用 ! = null 判空了!!
另外,也许受此习惯影响,他们总潜意识地认为,所有的返回都是不可信任的,为了保护自己程序,就加了大量的判空。如果你养成习惯,都是这样写代码(返回空collections而不返回null),你调用自己写的方法时,就能大胆地忽略判空)这种情况下,null是个”看上去“合理的值,例如,我查询数据库,某个查询条件下,就是没有对应值,此时null算是表达了“空”的概念。最终,项目中会存在大量判空代码,多么丑陋繁冗!,而不要返回null,这样调用侧就能大胆地处理这个返回,例如调用侧拿到返回后,可以直接。

详解Java Math类的toDegrees()方法:将参数从弧度转换为角度
Java Math 类的 toDegrees() 方法是将一个角度的弧度表示转换为其度表示,返回值为double类型,表示从弧度数转换而来的角度数。这就是Java Math 类的 toDegrees() 方法的攻略。我们已经了解了该方法的基本概念、语法、注意事项以及两个示例。希望这篇攻略对你有所帮助。

SpringBoot接口防抖(防重复提交)的一些实现方案
作为一名老码农,在开发后端Java业务系统,包括各种管理后台和小程序等。在这些项目中,我设计过单/多租户体系系统,对接过许多开放平台,也搞过消息中心这类较为复杂的应用,但幸运的是,我至今还没有遇到过线上系统由于代码崩溃导致资损的情况。这其中的原因有三点:一是业务系统本身并不复杂;二是我一直遵循某大厂代码规约,在开发过程中尽可能按规约编写代码;三是经过多年的开发经验积累,我成为了一名熟练工,掌握了一些实用的技巧。啥是防抖所谓防抖,一是防用户手抖,二是防网络抖动。

公司新来一个同事:为什么 HashMap 不能一边遍历一边删除?一下子把我问懵了!
前段时间,同事在代码中KW扫描的时候出现这样一条:上面出现这样的原因是在使用foreach对HashMap进行遍历时,同时进行put赋值操作会有问题,异常ConcurrentModificationException。于是帮同简单的看了一下,印象中集合类在进行遍历时同时进行删除或者添加操作时需要谨慎,一般使用迭代器进行操作。于是告诉同事,应该使用迭代器Iterator来对集合元素进行操作。同事问我为什么?这一下子把我问蒙了?对啊,只是记得这样用不可以,但是好像自己从来没有细究过为什么?

SpringBoot请求转发与重定向
但是可能由于B网址相对于A网址过于复杂,这样搜索引擎就会觉得网址A对用户更加友好,因而在重定向之后任然显示旧的网址A,但是显示网址B的内容。在平常使用手机的过程当中,有时候会发现网页上会有浮动的窗口,或者访问的页面不是正常的页面,这就可能是运营商通过某种方式篡改了用户正常访问的页面。重定向,是指在Nginx中,重定向是指通过修改URL地址,将客户端的请求重定向到另一个URL地址的过程,Nginx中实现重定向的方式有多种,比如使用rewrite模块、return指令等。使用场景:在返回视图的前面加上。

SSO 单点登录和 OAuth2.0 有何区别?
此方法的缺点是它依赖于浏览器和会话状态,对于分布式或者微服务系统而言,可能需要在服务端做会话共享,但是服务端会话共享效率比较低,这不是一个好的方案。在单点登录的上下文中,OAuth 可以用作一个中介,用户在一个“授权服务器”上登录,并获得一个访问令牌,该令牌可以用于访问其他“资源服务器”上的资源。首先,SSO 主要关注用户在多个应用程序和服务之间的无缝切换和保持登录状态的问题。这种方法通过将登录认证和业务系统分离,使用独立的登录中心,实现了在登录中心登录后,所有相关的业务系统都能免登录访问资源。

TCP协议-TCP连接管理
TCP协议是 TCP/IP 协议族中一个非常重要的协议。它是一种面向连接、提供可靠服务、面向字节流的传输层通信协议。TCP(Transmission Control Protocol,传输控制协议)。

接口响应慢?那是你没用 CompletableFuture 来优化!
大多数程序员在平时工作中,都是增删改查。这里我跟大家讲解如何利用CompletableFuture优化项目代码,使项目性能更佳!

30张图带你彻底理解红黑树
当在10亿数据进行不到30次比较就能查找到目标时,不禁感叹编程之魅力!人类之伟大呀!—— 学红黑树有感。终于,在学习了几天的红黑树相关的知识后,我想把我所学所想和所感分享给大家。红黑树是一种比较难的数据结构,要完全搞懂非常耗时耗力,红黑树怎么自平衡?什么时候需要左旋或右旋?插入和删除破坏了树的平衡后怎么处理?等等一连串的问题在学习前困扰着我。如果你在学习过程中也会存在我的疑问,那么本文对你会有帮助,本文帮助你全面、彻底地理解红黑树!

为什么阿里巴巴修正了HashMap关于1024个元素扩容的次数?(典藏版)
此番修正主要是每个人对「扩容」定义存在了分歧,在JDK1.8中如果没有给HashMap设置初始容量,那么在第一次put()操作的时候会进行resize()。而有的人认为这算一次扩容,有的人认为这不是一次扩容,这只是HashMap容量的初始化。所以存储1024的元素时:前者的人认为扩容次数为8次。后者的人认为扩容次数为7次。孤尽老师说对此分歧,希望用没有「二义性」的语言来表示,所以「扩容次数」修正为「resize次数」。

强烈建议你不要再使用Date类了!!!
这里就不细说修改流程了,主要说一下我们在改造的时候遇到的一些问题。(Date从现在开始)是一个糟糕的类型,这解释了为什么它的大部分内容在 Java 1.1 中被弃用(但不幸的是仍在使用)。只能说这种基础的类改起来牵一发动全身,需要从DO实体类看起,然后就是各种Converter,最后是DTO。这个改造难度不高,但是复杂度非常高,一个地方没改好,轻则接口报错,重则启动失败,非常耗费精力,真不想改。我们要改的原因很简单,我们的代码缺陷扫描规则认为这是一个必须修改的缺陷,否则不给发布,不改不行,服了。

SpringBoot 中实现订单30分钟自动取消的策略
在电商和其他涉及到在线支付的应用中,通常需要实现一个功能:如果用户在生成订单后的一定时间内未完成支付,系统将自动取消该订单。本文将详细介绍基于Spring Boot框架实现订单30分钟内未支付自动取消的几种方案,并提供实例代码。

一键部署 SpringCloud 微服务,这套流程值得学习一波儿!
一键部署 springcloud 微服务,需要用到 Jenkins K8S Docker等工具。本文使用jenkins部署,流程如下图开发者将代码push到git运维人员通过jenkins部署,自动到git上pull代码通过maven构建代码将maven构建后的jar打包成docker镜像 并 push docker镜像到docker registry通过k8s发起 发布/更新 服务 操作其中 2~5步骤都会在jenkins中进行操作。

计算机网络TCP/IP协议-从双绞线到TCP
消息响应也是同理,这种带端口的消息发送方式,其实就是UDP协议,UDP简单粗暴,但是UDP存在很多问题,所以我们需要设计一个稳定可靠的协议,TCP协议,首先,网络是不稳定的,我们发送的消息很有可能会在中途丢失,所以需要设置重试机制,当消息发送失败时重新发送,为了判断是否成功,还需要要求接收方收到消息后,必须发送确认消息,这样就可以保证消息必达,另外大段的内容发送,很容易造成部分丢失,导致全部内容都要重新发送,于是我们可以将数据分包,分成多个包发送。到这,也行你会发现了,演示中的IP地址是怎么设置的呢?

自定义参数解析器,减少10%的代码
*** 赋值调用方法* 如果为空,默认调用name()方法* 该方法必须是一个不含参数的方法,否则将会调用失败* @return*/value() : value用于绑定请求参数和方法参数名一致时的对应关系。比如user?statusNo=1。方法的参数写法如下:getUser(@EnumParam(value=“statusNo”) int status) 或者 getUser(@EnumParam() int statusNo)valueMethod() : 赋值时调用枚举中的方法。

Graphics2D API:Canvas操作
在中已经介绍了Canvas基本的绘图方法,本篇介绍一些基本的画布操作.注意:1、画布操作针对的是画布,而不是画布上的图形2、画布变换、裁剪影响后续图形的绘制,对之前已经绘制过的内容没有影响。

Java8 以后的 LocalDateTime,你真的会用吗?
本文从 LocalDateTime 类的创建、转换、格式化与解析、计算与比较以及其他操作几个方面详细介绍了 LocalDateTime 类在 Java 8 中的使用。掌握 LocalDateTime 类的使用可以大大提高日期时间处理效率和质量,希望本文对读者有所帮助。

我有一个朋友写出了17种触发NPE的代码!避免这些坑
在JUnit4中,使用Mockito框架时,any() 是一个参数匹配器,当与基本数据类型一起使用时,需要使用相应的类型特定的匹配器,例如使用anyInt() 而不是any()。要防范它,不在高超的编码技巧,在细。的可能性,却并不是万能的,比如开发者在使用Optional,不检查是否存在,直接调用Optional.get(),那么会得到一个NoSuchElementException。我有一个朋友,写代码的时候常常遭到NPE背刺,痛定思痛,总结了NPE出没的17个场景,哪一个你还没有遇到过?

一起学JDK源码 -- System类
System类是被final修饰的,不能被继承。

JVM优雅退出
在某个Java应用增加新功能,缩容机器,或者应用以及机器发生异常,通常会停止正在运行的应用,该应用通常正在运行着任务,如果停止应用的操作处理不当的话,很有可能会导致数据丢失,损坏,从而影响业务。所以在停止应用的时候,需要考虑如何安全优雅的退出。维护了所有已经注册的钩子,由于jvm本身没有提供好用的方法去移除已经注册的钩子,可以通过反射的方式调用。对于强制关闭的几种情况,会直接停止JVM进程,JVM不会调用已注册的。对于正常关闭、异常关闭的几种情况,JVM关闭前,都会调用已注册的。