有些时候我不得不问自己,我是不是真的已经在这个行业待了三年。很长一段时间里,我一直都在科技的周边打转,但大多数是从消费者的角度,也就是游戏。从来没接触过它们背后的系统。
这也是我一开始从工商管理转到信息技术的部分原因。我喜欢科技,讨厌商科那种理论化、靠死记硬背的苦差事。结果发现编程也没差多少,这里一样有很多东西要背。区别在于,编程里的背诵是为了服务于我真正感兴趣的东西。
那些让我措手不及的问题
最近,我被问到关于多租户(multi-tenancy)的问题。我的答案大致是:"就是你有多个租户,而你是房东。租户向房东汇报。"技术上没错,但薄弱得让人难堪。当追问跟进,优点和缺点是什么,我拿不出任何扎实的东西。
让人沮丧的是,多租户对我来说并不是一个陌生的概念,我以前接触过。只是没接触到能在压力之下脱口而出、清楚展示出我是真正理解而不是半吊子记忆的程度。
接着更难的问题来了。什么是broker(代理/经纪)?什么是provider(提供者)?"provider"我至少大致知道——我想我说的是跟依赖和采购有关,但没法再具体了。"broker"直接就是一片空白。然后:API和REST API的区别是什么?老实说,我从来没有坐下来认真区分过这两个概念。我们工作里一直是混着用的。API是你消费的东西,这就是我心智模型的极限了。直到事后我才去查了REST到底是什么的缩写、是什么意思。
事后的重新梳理
多租户是真正让我震惊的地方,因为我知道自己以前处理过它的一部分,只是没有全貌,更像是面包屑而不是整块面包。当下没法立刻回忆起来。但等我冷静下来、坐下来认真想的时候,它比我预期的更快就想通了。
房东的比喻其实比我当时给的评价要站得住脚得多。想象一栋公寓楼,对比一片独立房屋的社区。在多租户里,你的租户(使用你应用的不同客户或组织)共享同一套底层资源,也就是"这栋楼":一份代码库、一个运行中的应用程序,通常还有一个数据库,每个租户的数据在逻辑上被分隔开(比如通过一个tenant_id字段,或者每个租户一个单独的schema)。房东的优势正是我当时感觉到但说不清楚的地方:维护、打补丁、扩容一栋楼,远比开车绕着一片独立房屋一家一家修要容易得多。而代价就是同一枚硬币的另一面:租户共享资源,所以一个吵闹的邻居(比如某个租户把数据库打爆,或者一个bug导致数据在租户之间泄漏)带来的风险,会比在完全隔离的单租户配置里大得多。
provider和broker最后发现都没有当时感觉的那么陌生。
Provider(提供者)(在Laravel里是*service provider*)其实很接近我当时摸索着想说的东西:它是启动引导层。当应用启动时,provider会把各种构建模块——数据库连接、配置、第三方集成——注册进应用的容器里,这样等你的代码开始运行时,它所依赖的一切都已经接好线、准备就绪了。与其说是"采购",不如说更像"应用正式开门营业前的装配线"。
Broker(经纪/代理)是个中间人,我的直觉在这一点上并没有错,只是在压力下没能把这个定义抓住。broker坐在两个本来不需要直接互相认识的当事方之间。它从发送方接收消息,并路由给应该接收的那一方,这样发送方就永远不需要知道另一端是谁在听。
真正戳中我的地方是这个:我一直大量使用Redis。队列、缓存、pub/sub,好一阵子以来都是我技术栈的一部分。但我从来没有坐下来把"这个我一直在用的东西"和"broker"这个词联系起来。我在用这个工具,却从来没给它所属的那个类别命过名。RabbitMQ我只是听说过,从没碰过。Kafka在这三者里是最陌生的,我连它是做什么的都说不出来。所以当我被问到broker的时候,我脑子一片空白,不是因为缺乏经验,而是因为我从来没有给自己已经拥有的经验贴上标签。
Observer(观察者)和dispatcher(调度器)也是类似的情况,不过等我坐下来认真想过之后,这个空白就更说得通了。当时我能给出的只有"有点像是状态变化时会运行的一个worker"。方向没错,但很模糊,因为我确实不知道observer通常是绑定在一个数据库模型上的:它监听一个模型被创建、更新或删除,并作出反应,而原始代码完全不需要知道它的存在。dispatcher我本能上理解得更准一些,我把它理解为"事件发生了",这已经比较接近了:dispatcher会把一个job、事件或消息发送给应该处理它的那个东西。
事后想想,我觉得这与其说是知识上的空白,不如说是经历上的空白。observer和dispatcher的价值,是在多个用户或多个服务互相交互、真的有值得反应的事情发生时才体现出来的。我的作品集项目从来没有那么复杂过。大多数项目里我都是唯一的用户,所以很少有需要触发另一处反应的"第二个行动者"。我真正碰过这个模式的地方只有发送邮件的调度,而这甚至只是这些模式用途中很窄的一角。有时候我会希望自己作品集里能有一个更进阶的项目,一个真正有多用户交互的项目,这样我就能自然地碰到这些东西,而不是等到被人问起时才第一次听到它们的名字。
还有API和REST API的问题,事后回想几乎有点尴尬。API是一个宽泛的总称:任何两块软件互相通信的既定方式都算。REST是构建API的一种特定架构风格,基于HTTP,把一切都当作用URL标识的"资源",用标准动词(GET、POST、PUT、DELETE)去操作它,无状态,一次一个请求,不记得之前发生过什么。所以REST API是API的一种特定类型,而不是它的同义词。每一个REST API都是API,但不是每一个API都是REST。
我从这件事上带走了什么
这些概念没有一个对我来说是真正陌生的。这一点有点刺痛,但也正是这一点让我想把它写下来。我在工作中已经接触过这些想法中的每一个。我缺的不是接触经历,而是把"我用过这个"变成"我能清楚地向别人解释这个"的能力。做和解释之间的这个落差,显然是三年经验也依然可能让你暴露短板的地方。
我现在不把这当成一次失败,而是当成一份清单来对待:多租户、provider、broker、observer、dispatcher、REST。这些都是我用过、但从来没被要求当面辩护清楚过的概念。值得在下次有人再问之前,把它们钉牢。