负载均衡原理:流量分发为什么不是“平均”这么简单
当一个服务有多个实例时,系统就要面临一个非常直接的问题:这一批请求应该发给谁。如果所有流量都打到同一个实例上,那扩容就失去了意义;如果实例之间分发策略不合理,即便节点数量不少,也可能出现有的机器很忙、有的机器很闲。 所以负载均衡虽然听起来像...
当一个服务有多个实例时,系统就要面临一个非常直接的问题:这一批请求应该发给谁。如果所有流量都打到同一个实例上,那扩容就失去了意义;如果实例之间分发策略不合理,即便节点数量不少,也可能出现有的机器很忙、有的机器很闲。 所以负载均衡虽然听起来像...
在单体服务里,模块之间调用通常只是函数调用。你知道它在哪个包、哪个文件、哪个接口,引用过来就能用。但当系统开始拆分成多个服务以后,问题一下子就变了:一个服务如果想调用另一个服务,它首先要知道对方在哪里。 表面上看,这只是“拿到一个地址”的问...
很多团队在系统刚起步时,都会从一个单体服务开始。这是非常正常、也非常合理的选择。因为单体部署简单、调试直接、调用链清晰,开发和排查都相对低成本。问题往往不是单体本身,而是当业务不断增长以后,原本只需要管理一份代码、一个进程、一个发布包的世界...
在前一组 Go 后端工程化 里,我们解决的是一个服务怎么搭、怎么跑、怎么排查、怎么上线。那一组内容更像是在回答一个问题:当你手里只有一个服务时,怎样把它做得像一个真正可以交付的项目。 但服务一旦变多,问题就会明显变化。你会发现,很多麻烦已经...
当你把一个 Go HTTP 服务的基础工程化能力逐步补齐以后,通常会自然遇到下一个问题:如果业务继续增长,一个服务开始承担越来越多职责,或者系统之间需要更稳定地互相调用,后面应该怎么走?这时你会逐渐从“单个服务怎么写”转向“多个服务怎么协作...
很多 Go 项目在最开始都能很快跑起来:一个 main.go,一个 go.mod,再加几个包,功能就能开始迭代了。但只要项目继续长大,你很快会碰到另一类问题:构建命令每个人写得不一样,启动方式靠口头约定,目录层次越来越乱,依赖版本漂移,脚本...
很多人刚开始写后端服务时,对测试的态度往往是“先把功能写完再说”。结果到了后面,接口越来越多、逻辑越来越绕,每次改一点代码都担心牵出别的问题,但又没有足够信心去改。这个阶段最明显的感觉就是:项目能继续写,但不太敢继续动。 测试在后端工程化里...
很多接口在开发阶段都能跑通,但一旦交给前端、测试或者别的服务方使用,问题就会很快暴露出来:参数规则不清楚、错误信息不稳定、同类接口返回结构不一致、不同异常时状态码和业务码含义混乱。表面上看,这些都不算“核心业务”,但它们会直接影响接口可用性...
很多服务在开发阶段都能正常运行,但一谈到上线,就会暴露出另一类问题:服务启动后能不能被探活、退出时会不会把正在处理的请求直接掐掉、依赖异常时外界能不能及时看出来、出了问题有没有基础观测信号。这些问题和业务功能没有直接关系,却决定了一个服务是...
很多后端项目刚开始都很简单,一个接口就是一个函数,参数解析、业务判断、数据库查询、响应拼装全写在一起,功能也确实能跑。但项目只要开始增长,代码很快就会变得越来越难维护。一个很典型的信号就是:改一个接口要同时看 handler、SQL、业务分...