服务器分为应用服务器和什么_为什么要对无服务器应用单一责任原则

服务器分为应用服务器和什么

by Yan Cui

崔燕

为什么要对无服务器应用单一责任原则 (Why you should apply the single responsibility principle to serverless)

A fun­ny moment (at 38:50) hap­pened dur­ing Tim Bray’s ses­sion (SRV306) at re:invent 2017. Tim asked the audi­ence if we should have many single-purposed func­tions, or few­er mono­lith­ic func­tions, and there was an equal split in opinions.

在re:invent 2017上Tim Bray的会议( SRV306 )期间发生了一个有趣的时刻(38:50)。Tim问听众我们是否应该拥有许多单一用途的功能,或更少的整体功能,并且意见分歧是相等的。

This was a moment that chal­lenged my belief, as I’ve been brought up on the SOLID principles.

这是挑战我的信念的那一刻,因为我已经养成SOLID原则。

  • Single Responsibility Principle

    单一责任原则
  • Open/Closed Principle

    开/关原则
  • Liskov Substitution Principle

    里斯科夫替代原则
  • Interface Segregation Principle

    接口隔离原理
  • Dependency Inversion Principle

    依赖倒置原则

I have, for a long time, believed that following the Single Responsibility Principle (SRP) is a no-brainer.

很长一段时间以来,我一直相信遵循单一职责原则 (SRP)毫无疑问。

That prompt­ed this clos­er exam­i­na­tion of the argu­ments from both sides.

这促使双方仔细研究了双方的论点。

Full dis­clo­sure: I am biased in this debate. If you find flaws in my think­ing, or disagree with my views, please point them out in the com­ments.

全面披露: 在这场辩论中,我有偏见。 如果您发现我的想法有缺陷或不同意我的观点,请在评论中指出。

By “mono­lith­ic func­tions,” I mean func­tions that have inter­nal branch­ing log­ic. These functions can do one of sev­er­al things based on the invocation event.

“单片函数”是指具有内部分支逻辑的函数。 这些函数可以根据调用事件执行以下操作之一。

For exam­ple, you can have one func­tion han­dle all the endpoints for an API. The function would per­form a dif­fer­ent action based on the path and method parameters.

例如,您可以让一个函数处理API的所有端点。 该函数将根据pathmethod参数执行不同的操作。

module.exports.handler = (event, context, cb) => {   const path = event.path;   const method = event.httpMethod;
if (path === '/user' && method === 'GET') {     .. // get user   } else if (path === '/user' && method === 'DELETE') {     .. // delete user   } else if (path === '/user' && method === 'POST') {     .. // create user   } else if {    .. // other endpoints & methods   }}

You can’t ratio­nal­ly rea­son about and com­pare solu­tions with­out first under­stand­ing the prob­lem and what qual­i­ties are most desirable in a solu­tion.

在没有先了解问题以及解决方案中最需要什么素质的情况下,您无法合理地推理和比较解决方案。

And when I hear com­plaints such as that “hav­ing so many func­tions is hard to man­age,” I won­der what does man­age entail?

当我听到的抱怨,诸如“有这么多的功能是很难管理,”我不知道是什么管理意味着什么?

  • Is it to find spe­cif­ic func­tions you’re look­ing for?

    是否可以找到您要查找的特定功能?
  • Is it to dis­cov­er what func­tions you have?

    是为了发现您具有什么功能?
  • Does this become a prob­lem when you have 10 func­tions or 100 func­tions?

    当您有10个功能或100个功能时,这会成为问题吗?
  • Does it become a prob­lem only when you have more devel­op­ers work­ing on them than you’re able to keep track of?

    仅当您有更多的开发人员在工作,而不是能够跟踪时,这才成为问题吗?

Draw­ing from my own expe­ri­ences, the prob­lem has less to do with what func­tions we have. Rather, it’s about discovering what fea­tures and capabilities we pos­sess through these func­tions.

根据我自己的经验,该问题与我们所具有的功能无关。 而是要通过这些功能发现我们拥有哪些功能。

After all, a Lamb­da func­tion, like a Dock­er con­tain­er, is a con­duit to deliv­er some busi­ness fea­ture or capa­bil­i­ty.

毕竟,Lambda函数(例如Docker容器)是传递某些业务功能或特性的渠道。

You wouldn’t ask “Do we have a get-user-by-facebook-id func­tion?” since you would need to know what the func­tion was called with­out even know­ing if the capa­bil­i­ty exists and if it’s cap­tured by a Lamb­da func­tion. Instead, you would prob­a­bly ask, “Do we have a Lamb­da func­tion that can find a user based on his/her face­book ID?”

您不会问“我们有一个get-user-by-facebook-id功能吗?” 因为您甚至不知道该功能是否存在以及是否由Lambda函数捕获,就需要知道该函数被调用了什么。 取而代之的是,您可能会问: “我们是否有一个Lambda函数可以根据其Facebook ID查找用户?”

So the real prob­lem is that, giv­en that we have a com­plex sys­tem that con­sists of many fea­tures and capa­bil­i­ties, that is main­tained by many teams of devel­op­ers, how do we orga­nize these fea­tures and capa­bil­i­ties into Lamb­da func­tions so that it’s opti­mized towards:

因此,真正的问题在于,鉴于我们有一个由许多开发人员维护的,由许多功能组成的复杂系统, 我们如何将这些功能组织到Lambda函数中,以便针对以下方面进行优化:

  • dis­cov­er­abil­i­ty: how do I find out what fea­tures and capa­bil­i­ties exist in our sys­tem?

    问题:我如何找出系统中存在哪些功能?

  • debug­ging: how do I quick­ly iden­ti­fy and locate the code I need to look at to debug a prob­lem? For example, there are errors in sys­tem X’s logs, where do I find the rel­e­vant code to start debug­ging the sys­tem?

    debug­ging :如何快速识别和定位调试问题所需的代码 例如,系统X的日志中有错误,在哪里可以找到相关代码以开始调试系统?

  • scal­ing the team: how do I min­imize fric­tion and grow the engi­neer­ing team while maintaining the code?

    扩大团队规模 :如何在维护代码的同时最大程度地减少摩擦并发展工程团队?

Below are the qual­i­ties that are most impor­tant to me. With this knowl­edge, I can com­pare different approach­es and see which is best suit­ed for me.

以下是对我来说最重要的素质。 有了这些知识,我可以比较不同的方法,看看哪种适合 我的

You might care about dif­fer­ent qual­i­ties. For exam­ple, you might not care about scal­ing the team, but cost is an important consideration for you. Whatever they might be, it’s help­ful to make those design goals explic­it. You should also make sure they’re shared with and under­stood by your team.

您可能会关心不同的品质。 例如,您可能并不关心团队规模,但是成本是您的重要考虑因素。 无论它们是什么,明确那些设计目标都是有帮助的。 您还应该确保团队共享和理解它们。

可发现性 (Discoverability)

The lack of dis­cov­er­abil­i­ty is not a new prob­lem. Accord­ing to Simon Ward­ley, it’s rather ram­pant in both gov­ern­ment as well as the pri­vate sec­tor. Most organ­i­za­tions lack­ a sys­tem­at­ic way for teams to share and dis­cov­er each other’s work.

缺乏可发现性不是一个新问题。 根据西蒙·沃德利(Simon Wardley)的说法,无论是政府部门还是私营部门,这种情况都相当普遍。 大多数组织缺乏团队共享和发现彼此工作的系统方法。

As stated ear­li­er, discovery is about finding out what capa­bil­i­ties are avail­able through your func­tions. Knowing what functions you have is not enough.

如前所述,发现是要找出通过您的功能可以使用的功能。 仅仅知道您拥有什么功能还不够。

An argu­ment I often hear for mono­lith­ic func­tions is that it reduces the number of func­tions, which makes them eas­i­er to man­age.

我经常听到的关于整体函数的论点是,它减少了函数的数量,这使它们更易于管理。

On the sur­face, this seems to make sense. But the more I think about it, the more the argument appears flawed. The number of func­tions would only be an imped­i­ment IF we try to man­age them by hand rather than using the tools avail­able to us already.

从表面上看,这似乎是有道理的。 但是我想得越多,争论就越有缺陷。 如果我们尝试手动管理功能,而不是使用已经可用的工具,那么功能的数量将成为一个障碍。

After all, we are able to locate books by their con­tent in a huge phys­i­cal space with tens of thou­sands of books. Using the library analogy, with the tools available to us, we can catalogue our functions and make them easy to search.

毕竟,我们能够根据书本的内容在具有成千上万本书的巨大物理空间中查找书本。 使用类库,使用我们可用的工具,我们可以对函数进行分类并使其易于搜索。

For example, the Serverless frame­work enforces a simple naming convention of {service}-{stage}-{function}. This simple convention makes it easy to find relat­ed func­tions by pre­fix. If I want to find all the func­tions that are part of a user API, I can do that by search­ing for user-api.

例如, 无服务器框架强制执行{service}-{stage}-{function}的简单命名约定。 这个简单的约定使按前缀查找相关功能变得容易。 如果我想找到user API的所有功能,可以通过搜索user-api

With tags, we can cat­a­logue func­tions across mul­ti­ple dimen­sions. For example, we can catalogue using envi­ron­ment, fea­ture name, event source, author, and so on.

使用标签,我们可以在多个维度上对函数进行分类。 例如,我们可以使用环境,功能名称,事件源,作者等进行分类。

If you have a rough idea of what you’re look­ing for, then the number of func­tions is not an imped­i­ment to your abil­i­ty to dis­cov­er what’s there.

如果您对要查找的内容有一个粗略的了解,那么功能的数目并不妨碍您发现其中的内容。

With single-purposed functions, the capa­bil­i­ties of the user-api is immediately obvi­ous. I can see from the rel­e­vant func­tions that I have the basic CRUD capa­bil­i­ties, because there are cor­re­spond­ing func­tions for each.

使用单一用途的功能, user-api功能立即显而易见。 从相关功能中可以看到我具有基本的CRUD功能,因为每个功能都有相应的功能。

With a mono­lith­ic func­tion, how­ev­er, it’s not so straightforward. There is only one function, but what can this function do? I’ll have to either look at the code myself, or con­sult with the author of the func­tion. For me, this makes for poor dis­cov­er­abil­i­ty.

但是,具有单片函数并不是那么简单。 只有一个功能,但是该功能可以做什么? 我将不得不自己看代码,或者咨询函数的作者。 对我来说,这使可发现性差。

Because of this, I mark the mono­lith­ic approach down on dis­cov­er­abil­i­ty.

因此,我将整体方法标记为可发现性。

But, having more func­tions means there are more pages for you to scroll through. This can be laborious if you just want to browse and see what functions are there.

但是,拥有更多功能意味着您可以滚动浏览更多页面。 如果您只想浏览并查看其中有什么功能,这可能会很麻烦。

Although, in my expe­ri­ence, this has never been a problem per se. Thanks to the Serverless framework’s naming convention, all related functions are close together. It’s actually quite nice to see what each group of functions can do, rather than having to guess what goes on inside a monolithic function.

尽管以我的经验来看,这本身从来不是问题。 由于无服务器框架的命名约定,所有相关功能都紧密结合在一起。 看到每组函数可以做什么实际上很不错,而不必猜测单个函数内部发生了什么。

But, it can be a pain to scroll through every­thing when you have thousands of func­tions. So, I’m going to penalize sin­gle-purposed func­tions for that.

但是,当您具有数千个功能时,滚动浏览所有内容可能会很痛苦。 因此,我将为此惩罚单用途函数。

At that lev­el of com­plex­i­ty, though, packing more capabilities into each function would only make the system more difficult to understand. Say you have a thousand functions, and you know what each does at a glance. Wouldn’t it be simpler if you replace them with a hundred functions, but you can’t tell what each does?

但是,在这种复杂性级别上,将更多功能打包到每个功能中只会使系统更加难以理解。 假设您有上千种功能,那么您一眼就能知道它们的功能。 如果用一百个函数代替它们会更简单,但是您不知道每个函数是什么?

调试 (Debugging)

For debug­ging, the rel­e­vant ques­tion is whether having few­er func­tions makes it easier to iden­ti­fy and locate the bug.

对于调试,相关的问题是功能是否较少,是否可以更轻松地识别和定位错误。

In my experience, the path from an error to the relevant function and repo is the same, regard­less of whether the func­tion does one thing or many things.

以我的经验,从错误到相关功能以及回购的路径是相同的,而不管该功能是做一件事情还是做很多事情。

The difference is how to find the rel­e­vant code inside the repo for the prob­lems you’re inves­ti­gat­ing.

区别在于如何在仓库中找到要调查的相关代码。

A mono­lith­ic func­tion has more branch­ing logic. So it would take more cog­ni­tive effort to fol­low through to the code that is rel­e­vant to the prob­lem at hand.

单片函数具有更多分支逻辑。 因此,要花更多的精力才能完成与手头问题相关的代码。

For that, I’ll mark mono­lith­ic func­tions down slight­ly. Of course, we’re talking about a minimal difference here, which is why the penalty is also minimal.

为此,我将单片函数标记为略微降低。 当然,我们在这里谈论的是最小的差异,这就是为什么罚款也最小的原因。

缩放比例 (Scaling)

In the early days of microservices, one of the argu­ments for microservices was that it makes scal­ing eas­i­er.

在微服务的早期,微服务的观点之一是它使扩展变得更容易。

But that’s not the case!

但是事实并非如此!

If you know how to scale a sys­tem, then you can scale a mono­lith as eas­i­ly as you can scale a microser­vice.

如果您知道如何扩展系统,则可以像扩展微服务一样轻松地扩展整体。

I say that as some­one who has built mono­lith­ic back­end sys­tems for games that had a mil­lion Dai­ly Active Users (DAU). Super­cell, the cre­ator of top gross­ing games like Clash of Clans and Clash Royale, have well over 100 million DAU. The backend systems for these games are all monoliths, and Supercell has no problems scaling these systems.

我说的是,他为拥有百万每日活跃用户(DAU)的游戏构建了整体后端系统。 超级单体 ,顶部卖座的游戏,如部落冲突冲突皇家的创造者,拥有超过1亿的DAU。 这些游戏的后端系统都是独石, Supercell扩展这些系统没有问题。

Instead, tech giants such as Ama­zon and Google taught us that microservices make it eas­i­er to scale in a dif­fer­ent dimen­sion — our engi­neer­ing team.

取而代之的是,诸如亚马逊和谷歌之类的技术巨头告诉我们,微服务使我们更容易在不同维度上进行扩展-我们的工程团队。

This style of archi­tec­ture allows us to cre­ate bound­aries with­in our sys­tem, around fea­tures and capa­bil­i­ties. It allows our engi­neer­ing teams to scale the com­plex­i­ty of what they build, because they can more easily build on top of the work that oth­ers have cre­at­ed before them.

这种体系结构样式使我们能够在系统中围绕功能部件创建边界。 它使我们的工程团队能够扩展其构建的复杂性,因为他们可以更轻松地在其他人之前创建的工作之上进行构建。

Take Google’s Cloud Data­s­tore as an exam­ple. The engi­neers in that team were able to pro­duce a sophis­ti­cat­ed ser­vice by build­ing on top of many lay­ers of ser­vices. Each layer pro­vides a pow­erful abstrac­tions the next layer can leverage.

以Google的Cloud Datastore为例。 该团队中的工程师能够通过在多层服务之上构建服务来提供复杂的服务 。 每层都提供了下一层可以利用的强大抽象。

These bound­aries give us a greater divi­sion of labour. Which allows more engi­neers to work on the sys­tem by giv­ing them areas where they can work in rel­a­tive iso­la­tion. This way, they don’t trip over each oth­er with merge con­flicts, inte­gra­tion prob­lems, and so on.

这些界限使我们更加分工。 通过给他们可以相对隔离的工作区域,使更多的工程师可以在系统上工作。 这样,它们不会因合并冲突,集成问题等而相互绊倒。

Michael Nygard also wrote a nice arti­cle that explains this ben­e­fit from another angle: that these bound­aries and iso­la­tion helps us reduce the over­head of shar­ing men­tal mod­els.

迈克尔·尼加德(Michael Nygard)也写了一篇不错的文章 ,从另一个角度解释了这一好处:这些边界和隔离有助于我们减少共享心理模型的开销。

“If you have a high coher­ence penal­ty and too many peo­ple, then the team as a whole moves slow­er… It’s about reduc­ing the over­head of shar­ing men­tal mod­els.”

“如果你有一个高相干性和惩罚的人太多了,那么球队的整体移动速度较慢......这是关于减少共享心智模型的开销 。”

- Michael Nygard
-迈克尔·尼加德(Michael Nygard)

Hav­ing lots of sin­gle-pur­posed func­tions is per­haps the pin­na­cle of that divi­sion of tasks. You lose that division a little when you move to mono­lith­ic func­tions. Although in prac­tice, you prob­a­bly won’t have so many devel­op­ers work­ing on the same project that you feel the pain.

具有许多单一用途的功能可能是该任务划分的顶峰。 当您转向单片函数时,您会稍微失去该划分。 尽管在实践中,您可能不会有那么多开发人员在同一个项目上工作,但您会感到痛苦。

Restrict­ing a func­tion to doing one thing also helps lim­it how complex a func­tion can become. To make some­thing more complex, you would com­pose these sim­ple func­tions togeth­er via oth­er means, such as with AWS Step Functions.

将功能限制为只能执行一项操作也有助于限制功能的复杂程度。 为了使事情变得更复杂,您可以通过其他方法(例如,AWS Step Functions)将这些简单的函数组合在一起

I’ll mark mono­lith­ic func­tions down for los­ing some divi­sion of labour, and for rais­ing the com­plex­i­ty ceil­ing of a func­tion.

我将单片函数标记为降低失去某些分工并提高函数的复杂性上限。

结论 (Conclusion)

Based on the cri­te­ria that are impor­tant to me, hav­ing many sin­gle-pur­posed func­tions is the bet­ter way to go. But I do not see this as a hard and fast rule.

根据对 我来说 重要 标准 ,拥有许多单一用途的功能是更好的选择。 但是我不认为这是一成不变的规则。

Like every­one else, I come pre­loaded with a set of pre­dis­po­si­tions and bias­es formed from my expe­ri­ences, which like­ly do not exactly reflect yours. I’m not ask­ing you to agree with me. Though I do hope you appre­ci­ate the process of working out what’s important to you so you can go about find­ing the right approach for you.

像其他所有人一样,我充满了根据我的经验形成的一系列倾向和偏见,这些倾向和偏见可能无法完全反映您的经验。 我不是要你同意我的观点。 尽管我确实希望您对确定对您来说重要的过程感到赞赏,以便您可以为自己找到正确的方法。

But what about cold starts? Wouldn’t monolithic functions help you reduce the number of cold starts?

但是冷启动呢? 单片函数是否可以帮助您减少冷启动次数?

The short answer is no, they don’t help you with cold starts in any meaningful way. It’s also the wrong place to optimize for cold starts. If you’re interested in the longer version of this answer, then please read my other post here.

简短的答案是没有,它们不会以任何有意义的方式帮助您进行冷启动。 这也是为冷启动进行优化的错误位置。 如果您对此答案的较长版本感兴趣,请在此处阅读我的其他文章。

And lastly, having smaller surface areas with single-purposed functions reduces the attack surface. You can give each function the exact permission it needs and nothing more. This is an important, but often underappreciated advantage of single-purposed functions.

最后,具有单一用途功能的较小表面积可减少攻击面。 您可以给每个功能所需的确切权限,仅此而已。 这是单一用途功能的重要但通常不为人知的优势。

翻译自: https://www.freecodecamp.org/news/why-you-should-apply-the-single-responsibility-principle-to-serverless-77810a24bd49/

服务器分为应用服务器和什么

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值