原文链接: nickjanetakis.com/blog/micros…
以下为译文:
让我们来讨论一下使用微服务框架是不是一个好主意。
剧透警告:项目不同,答案也不尽相同。
作为软件开发人员,我们拥有一个非常有趣的职业。我们可以开开心心的敲一整天代码,下班不经意瞥到一篇奈飞写的乱七八糟的文章就会让你忽然质疑你所有代码存在的价值。这是非常真实的,我们经常会因为某个人或者某个公司的观点就开始质疑我们已经做了很多年的项目,即便这个项目一直运行的非常出色。
你不是谷歌(除非你是谷歌)
当我们浏览技术新闻或者其他行业新闻门户时,我们经常会看到谷歌、奈飞、亚马逊、脸书这些公司发表的一些文章,对于他们如何同时部署成百上千个服务侃侃而谈,并且大肆吹捧通过这种思路而获得的效益。互联网巨头引导技术发展在过去几年已经变成了一种趋势。
但是我们必须面对这样一个现实。你很可能并没有服务超大项目的超过千人的庞大团队,也没有超过十几年的行业实操背景。
谷歌在使用某项技术并不意味着你也应该使用。
与谷歌相比,我们基本就是生活在另一个银河系的。谷歌遇到的问题我们基本上是不可能遇到的,同时我们也可以做很多谷歌无法实施的事情。
绝大多数软件项目是如何起步的?
很多项目都是从一个人完成所有编码工作开始的。有无数这样的案例,让我们先看看Shopify,Shopify最开始是由 Tobias Lütke编写的(最开始使用Ruby on Rails框架,并保持到现在)
你觉得Tobias是不动手写任何代码就犹豫不决的呆坐在那里,煞费苦心的尝试创造一个完美的微服务框架吗?
当然不是,当Tobias开发第一个迭代版本的Shopify时,Shopify只是一个出售滑雪装备的电商平台。如果Tobias同我有一点点相像(一个典型的程序员),那他很可能是这样完成Shopify框架的:
1.一边学习一门新技术,一边搭建初始产品
2.写出一些质量糟糕但是可以运行的代码
3.为代码跑通而感到兴奋不已
4.每当遇到问题时就着手重构那堆狗屎一般的代码
5.不断重复上面这个循环并且不断增加新的功能并在项目中验证效果
看起来这个循环是非常简单的,但是我花了将近20年的编码经历才真正领悟到这个循环里面的奥秘。
不动手写代码而只关注理论最优是无法变成更好的程序员的。 只有通过大量编码工作并专注于不断用更好的代码替代原有代码来解决产品真实问题才可以变得更强。 那些不断被重写的代码所花费的精力和时间并不是浪费,这些代码才是不断提升自我的积淀。这就是程序员成长的秘诀。
让我们来聊一下代码抽象
作为开发人员,我们都曾听说过“不要重复编码(DRY:don't repeat yourself)”,通常来说这是有参考价值的,然而,有些时候“重复编码”是非常有意义的。
因为在没有真正理解所要抽象的问题时尝试进行抽象会发生抽象漏洞(leaky abstraction:所有非不证自明的抽象概念,都有某种程度的疏漏)。
在考虑重构代码进行抽象之前,我会先完成3次重复编码,而真正动手去进行抽象重构时往往已经进行了4-5次重复编码。
因为只有真正搞清楚如何在多个不同场景下完成重复编码,才可能明确哪些原有的内联内容可以被抽象。
抽象的阶段性,从内联编码到扩展类库:
1.编写内联代码
2.在多个不同场景下实现重复编码
3.将重复编码抽取为功能方法
4.在一段时间内验证抽象的效果
5.检查抽象代码如何与其他代码交互
6.抽取通用功能方法形成内部类库
7.在更长时间内使用、验证内部类库
8.认真理解这个类库的内容,想清楚这些内容组成类库的前因后果
9.如果可以将前因后果整理清楚,将内部类库发展为扩展类库(形成开源成果)
这种阶段性意味着我们注定无法“发明”一个优秀的类库或是框架。今天我们所使用的几乎所有工具都是从实际项目中提炼出来的,是在项目内部得到真实验证后才形成工具的。
Rails就是一个很好的例子。DHH(Rails作者)并不是某天早上醒来忽然意识到应该将项目结构调整为models/、controllers/和views/这些路径,他在开发Basecamp(一个真实的产品)时,这个模式已经出现,又从Basecamp抽取出来使用在Rails中,这个过程也在Rails中继续,在我看来,这种阶段性演变模式也是Rails可以持续如此成功的唯一原因。
使用合适的编程语言配合写出非常漂亮的代码,Rails是经过充分验证抽象的完美风暴。这也是几乎所有其他语言版本Rails框架失败的原因。这些版本的框架都没有经历Rails所经历的关键步骤,而只是想复制Rails框架的功能。
面向微服务的代码抽象 在我看来,微服务只是更进一步的抽象。我不认为微服务是上述步骤列表中的后续步骤10,因为不是所有的类库都注定要抽象为微服务,但是在概念层面是微服务是上述抽象步骤的一种类似递进。
微服务不是在项目第一天就开始着手实施的,就像在你没有开始写代码之前无法尝试创建一个完美的开源类库一样。在项目第一天,你根本不知道自己会实现什么东西。 一个基于微服务的框架是在已有项目版本基础上不断碰到并解决实际问题而慢慢演变的一种可能方案。
一个项目,可能完全没有碰到这样的问题,也有很多类似问题是完全可以通过其他方式来解决的。让我们再看一下Basecamp和Shopify这两个产品。他们都是单体框架应用,而且运行表现非常好。
我觉得任何人都不可以把这两个产品成为小型应用,当然这两个产品没有运营到谷歌的体量。但是我们可以通过几个维度对这两个产品进行说明。
作为单体服务架构应用,Shopify每个月收入1700万美元 2018年中期,Shopify公开宣布已有60多万商户在其平台上运营网店。
Shopify是一个SAAS应用,最便宜的套餐每月收费29美元,但是我认为大量的商户在使用他们79美元/月的套餐。就算60万商户全部使用他们最便宜的套餐,那只靠SAAS服务这一项每月就可以为公司带来1740万美元的利润。
Basecamp是另外一个体量较大的单体服务架构应用,这家公司非常有趣的一点是他们只有大概50名员工,而且只有其中很少一部分是服务主要产品的软件工程师。
我想说的是,在没有真正了解微服务的前提下,大家对微服务的认识偏差很可能是非常大的。微服务应该以需要为基础。
什么时候应该使用微服务?
问题的答案在于你和你的团队。当你已经完全了解微服务和单体服务,不需要再去网上搜索“微服务和单体服务的区别”时,你才可能拥有这个问题的答案。
有一种场景是适合推广微服务的,如果你已经有一大堆开发人员,他们已经习惯于分别开发一个应用的不同模块。多个团队相互隔离,分别负责产品的不同模块,这是推行微服务架构的一个有力前提。
如果你只有一个非常小的团队,并且短期内不会快速扩张,那很可能在做了一两个微服务之后就会放弃,不大可能在很短时间内将原有的单体服务直接彻底转换成100个微服务。
这杯果汁值得榨吗?
另外一个值得提醒的事情,向微服务转换会面临其特有的问题和挑战。换成微服务只是将一系列问题转换成另外的一系列问题,所以你自己一定要针对自己的实际项目,权衡利弊。
微服务带来的最大的问题之一就是监控。使用微服务后,你会忽然间发现很多个使用不同技术栈开发的微服务运行在很多个不同的机器上,但是微服务架构要求你必须时刻了解每个服务的每个细节。
从监控的视角考虑,你肯定希望可以使用一套统一的服务完成所有数据的采集和展示,所以监控将成为一个非常痛苦的工作。
你不大可能去开发自己的监控工具,因为只是监控工具开发这件事会消耗团队太多资源。这也是为什么像LightStep这种公司会如此成功的原因,他们的产品是我这些年见过最有意思的监控服务。
他们的产品更针对于大体量的应用(有非常充分的理由)但是也可以使用在小体量的项目上。我通过上次活动他们的幻灯片才了解到他们。
不管怎么说,监控只是诸多挑战中的一个,因为这是非常痛苦的一个,所以我单独展开讨论了一下。
最后的思考
有两个主要原因让我写下这篇文章:
1.两周前我参加活动,碰巧参加了一些关于这个话题的小组分享。活动的材料会在几个月后发出来,不过我在这篇文章里想详细讨论一下自己的一些观点。
2.因为有人发起了线上课程,我经常收到大家关于如何架构应用的一些问题。
我发现一个普遍的趋势,很多人在代码开发之前就很执着的想把他们的应用分解为多个独立的服务。
甚至有人在项目开始时就为应用的不同组件配置多种数据库。这会拖累产品的进度,而且作为一个资深的开发人员我知道陷入犹豫不决的恶性循环中有多么的痛苦。
顺便说一句,我最近正在开发一个关于开放定制课程平台的大型SAAS应用。目前只有我一个人开发这个项目,而且我是直接打开代码编辑器从第一行代码开始编写的。
我非常坚定,会把这个项目作出一个庞大的单体服务,直到有一天这个服务无法继续运营,不过根据我的经验判断,这一天永远不会到来。
