Linux

Serverless:复杂度没有消失,只是换了地址

2018年前后,Serverless在国内技术圈火了一阵。各大云厂商轮番布道,"按需付费"、"零运维"、"自动扩缩容"——每个口号都精准戳中了团队的痛点。我当时也投入了不少精力研究,毕竟谁不想不用管服务器?

几年过去了,当初那些All in Serverless的团队,相当一部分已经在往回走。不是Serverless不好,而是很多人慢慢意识到:当初以为消灭的复杂度,其实只是搬了个家。

 

那些承诺里没写的小字

 

Serverless的核心承诺有三条,每一条都有对应的现实版本。

"不用管服务器"——开发者只需写业务逻辑,基础设施平台托管。这对前端团队尤其有吸引力,写完函数丢上去就能跑,不用折腾部署和运维。但现实是,你很快会发现自己需要关注函数的内存配置、超时时间、并发限制、冷启动策略、VPC配置、IAM权限……这些不叫"服务器运维",但本质上还是在管基础设施,只是换了个仪表盘。

"按需付费"——代码不运行就不收钱,空转成本消失。但下一句没人告诉你的是:按需付费的反面是成本不可预测。一个函数死循环触发重试,一个爬虫突然疯爬你的API,一个配置错误导致无限调用——这些异常场景下的账单,会让你深切怀念固定成本的日子。

你选的 Git 工作流,暴露了你的发布能力

每次团队讨论 Git 工作流,场面都很热烈。有人搬出 Git Flow 的严谨分支模型,有人推荐 Trunk-Based Development 的极简主义,还有人觉得 GitHub Flow 够用就行。辩论往往持续一个下午,最后投票选一个,README 里写上规范,全员执行。

然后三个月后你会发现:分支还是乱成一锅粥,release 分支上堆了二十个 cherry-pick,hotfix 从 master 拉出来合不回去,有人偷偷开了 feature branch 三周没合,还有人在 master 上直接 commit——"就改了一行,没必要开分支"。

工作流选错了?不,工作流没选错。是大部分团队在选工作流的时候,选的是自己向往的工作方式,而不是自己实际具备的发布能力。

 

Git Flow:为发布窗口而生的妥协

 

Vincent Driessen 在 2010 年提出 Git Flow 的时候,他的假设非常明确:你的软件有固定的发布周期。develop 分支积累功能,release 分支冻结测试,master 分支只放生产代码,hotfix 从 master 拉出紧急修复。每一步都有清晰的语义。

日志的谎言:为什么你的日志比没有日志更危险

凌晨两点,线上出了一个支付失败的问题。你登录日志平台,输入订单号,回车。三千条日志滚动出来。你加上时间过滤,缩小到五百条。再加 ERROR 级别,剩三十条。你一条一条看——全是超时告警,没有一条告诉你为什么超时。

你把级别放宽到 WARN,三百条。大多是重试成功的记录,看起来没啥用。你换了个关键词搜,又出来几百条。折腾了一个小时,你发现关键信息藏在一个 INFO 级别的日志里,存的是上游服务的返回值,但打印的时候没用 JSON 格式,正则匹配不到。

最后你靠着回忆和猜,定了位。第二天写故障报告,复盘建议第一条写着:"增加更多日志。"

这个场景大概不需要太多解释,每个值过班的工程师都经历过。但真正值得思考的不是"日志不够"这个表面结论,而是更深的问题:你有成千上万条日志,为什么还需要靠猜?如果日志真的有用,为什么越紧急的时刻,日志越帮不上忙?

 

日志的安全感是假的

 

很多团队对日志有一种近乎宗教性的信任——出了问题看日志,没问题也要看日志确认一下。代码评审的时候,一句"这里加个日志吧"几乎不会被拒绝,因为加日志没有成本,看起来还体现了严谨。

但日志给你的安全感是虚假的。

技术决策的囚徒困境:为什么正确的方案总是输给能落地的方案

做了这么多年技术,我发现一个挺有意思的现象:几乎每次技术方案评审,都会有人提出一个"理论上最优"的方案,但最后落地的,往往是那个"看起来不够优雅"的方案。

这不是偶然。背后有一套残酷的逻辑。

 

那个"完美方案"为什么总是死在会议室里

 

上周技术评审会,前端团队提出要引入微前端架构,理由很充分:模块解耦、独立部署、技术栈自由、团队自治。PPT做得精美,架构图画得漂亮,甚至连落地路线图都准备好了。

然后架构师问了一句:"谁来维护基座?iframe降级方案谁负责?跨应用通信出问题谁排查?"

会议室安静了30秒。

最后的决定是:继续用现有的Monorepo + 模块化方案,虽然不够"先进",但团队都熟悉,出问题知道怎么修。

这不是个例。我见过太多"技术上正确"的方案,死在各种现实问题上:

- 服务化改造,拆到一半发现团队根本撑不起这么多服务
- TypeScript全面迁移,三个月后发现一半团队还在用any
- GraphQL替代REST,半年后发现后端团队都不会写resolver
- Kubernetes上云,结果运维团队连基本的Pod调试都不会

Monorepo的真相:为什么大部分团队都用错了

Monorepo 最近几年成了前端工程化的显学。Google、Meta、微软都在用,Turborepo、Nx 这些工具层出不穷,到处都在讲 Monorepo 的好处。但我观察下来,大部分团队引入 Monorepo 之后,要么是用成了"巨型仓库",要么是过度拆分变成了"伪 Monorepo"。

真正的问题不是 Monorepo 本身,而是大家搞错了它的适用场景。

 

先说结论:Monorepo 不是银弹

 

很多团队看到 Google 用 Monorepo 管理几十亿行代码,就觉得自己也该用。但这里有个认知偏差:Google 的 Monorepo 是为了解决他们特有的问题——跨团队代码共享和依赖管理

你的团队有这个问题吗?

大部分团队的实际情况是:
- 前端就 3-5 个人,管理的项目不超过 10 个
- 业务相对独立,跨项目共享的代码不多
- 没有复杂的内部依赖关系
- 团队协作流程还没稳定下来

这种情况下,Monorepo 带来的复杂度远大于收益。

依赖管理的迷局:为什么升级依赖总是危险的

每次看到 Dependabot 或 Renovate 提的 PR,我的第一反应不是"好,及时更新",而是"又来了,这次会炸在哪"。

这不是危言耸听。见过太多次:一个看似无害的小版本更新,导致生产环境莫名其妙地挂掉;一个"修复安全漏洞"的补丁,带来了更严重的 breaking change;一个"只是升级 devDependencies"的操作,让 CI 流水线跑不起来。

行业里有个有意思的现象:所有人都在说"依赖要及时更新",但实际操作中,大家都在拖延。不是因为懒,是因为怕。

这种恐惧是有道理的。

 

语义化版本的美丽谎言

 

Semantic Versioning(语义化版本)告诉我们:`major.minor.patch`三段式版本号清晰明了,patch 是 bug 修复,minor 是功能新增,major 才是破坏性变更。所以升级 patch 和 minor 是安全的,对吧?

对个屁。

去年金融业务的一次故障,就是因为某个依赖的 minor 版本更新。库的作者认为他只是"优化了内部实现",所以只升了 minor。但这个优化改变了某些边界情况下的行为,恰好触发了我们业务代码里一个隐式依赖的逻辑。

微服务不是银弹:大部分团队高估了自己的复杂度

博客分类: 

 

写在前面

 

前几天和一个创业公司的 CTO 聊天,他说他们团队 5 个后端开发,已经拆了 12 个微服务。我问他为什么要拆,他说"为了未来的扩展性"。然后我问他现在的 DAU 是多少,他说"几千"。

这让我想起很多年前见过的一个场景:一个刚起步的业务,还在验证商业模式,技术团队已经开始讨论服务网格和分布式追踪了。最后业务没做起来,技术架构倒是挺先进的。

微服务这几年被捧得太高了。很多团队在根本不需要的时候就开始拆服务,结果把自己搞得焦头烂额。今天想聊聊这个话题,不是说微服务不好,而是大部分团队真的不需要它,至少不是现在。

 

微服务的真实成本

 

 

开发成本的指数级增长

 

很多人以为微服务只是把代码拆开而已。实际上,从单体到微服务,你需要解决的问题是指数级增长的:

服务间通信:HTTP 调用、gRPC、消息队列,你得选一个。然后你会发现,本来一个本地函数调用,现在变成了网络请求。网络不可靠,你得处理超时、重试、熔断。原本简单的代码,现在要考虑各种边界情况。

全栈工程师的最大误区:追求全能

最近看到一个问题:"全栈工程师是不是什么都要会?"下面的回答分成了两派,一派说全栈就是要前端后端数据库运维都精通,另一派说全栈是个伪概念,啥都会等于啥都不精。

两边都有道理,但我觉得都错了重点。

做了很多年全栈,从后端写到前端,再到带团队做架构,我的观察是:大部分人误解了全栈工程师的核心价值。全栈不是让你成为技术全才,而是给你一个完整的视角去理解系统、做决策、解决问题。

追求全能是个陷阱,追求全局观才是正道。

 

全能是个伪命题

 

先说个真实场景。

在金融业务中,经常会遇到性能问题。前端说页面慢是因为接口慢,后端说接口慢是因为前端请求太多,DBA说数据库压力大是因为查询写得烂,运维说服务器资源不够要扩容。

这时候如果你是个"全能型"全栈,你会怎么做?去优化前端的渲染逻辑、重写后端的查询语句、调整数据库索引、然后去研究服务器配置?

听起来很厉害,但实际上这是在用战术上的勤奋掩盖战略上的懒惰。

真正的问题可能是:这个需求本身就不合理,或者整个架构设计有问题。

微前端的陷阱:为什么大部分团队不需要qiankun

微前端这几年很火,但我见过太多团队在盲目引入后陷入困境。最常见的情况是:团队只有3-5个前端开发,维护着2-3个业务模块,却花了两个月时间接入qiankun,结果代码复杂度翻倍,问题却没解决几个。

这不是qiankun的问题,而是大部分团队根本不需要微前端。

 

微前端解决的是组织问题,不是技术问题

 

很多人把微前端当成技术架构来看,这是第一个误区。

微前端的核心价值在于让不同团队能够独立开发、独立部署自己的模块,而不是解决技术上的模块化或性能问题。如果你的团队只有一个前端组,那么引入微前端就像一个人住别墅——空间是有了,但打扫卫生的时间也翻倍了。

我在金融业务中见过一个典型案例:公司有理财、基金、保险三条业务线,分属三个独立团队,各团队技术栈不同(React、Vue、Angular都有),发布节奏也不一致。这种情况下,微前端是合理的选择,因为组织边界清晰,技术隔离是刚需。

但大部分团队的情况是:前端是一个Team,后端可能分了几个服务,然后看到微服务很流行,就觉得前端也该"微"一下。这就是刻舟求剑了。

 

微前端带来的复杂度被严重低估

 

引入微前端后,你要面对的问题比想象中多得多:

Ubuntu 中sendmail 的安装、配置与发送邮件的具体实现

博客分类: 

一、安装      

ubuntu中sendmail函数可以很方便的发送邮件,ubuntu sendmail先要安装两个包。

必需安装的两个包:

sudo apt-get install sendmail
sudo apt-get install sendmail-cf

下面几个包是可选的:

squirrelmail //提供webmail
spamassassin //提供邮件过滤
mailman //提供邮件列表支持
dovecot // 提供IMAP和POP接收邮件服务器守护进程

注意:

Ubuntu下使用最常用的mail功能,需要安装mailutils,

安装命令:sudo apt-get install mailutils  

使用带附件的功能,则还需要安装sharutils,

安装命令:sudo apt-get install sharutils;(yum install sharutils )

 

页面