先说结论:能不能一套GEO源码卖给多个客户,不取决于后台有没有「租户管理」这个菜单,取决于租户边界有没有贯穿到查询、队列、缓存、文件和升级这五处。少一处,早期看不出来,客户上到五六个就会串。
有个做代运营的朋友算过一笔账:手上八个客户,各装一套系统要八台机器、八次部署、八轮升级,太重,于是装了一套,开了八个账号。头两个月相安无事。第三个月连着出三件事——某个客户在报表里看到了别家的关键词;有人把检测频率调高,其他几个跟着一起涨了调用量;还有一家把当月额度跑空,全站检测停了一下午。
他起初以为是权限没配好。但权限只管「能不能点这个按钮」,管不到「这条 SQL 查出来的是谁的数据」。2026年买GEO源码的人里,打算贴牌转售或给多个客户交付的占了不少,这一层早晚要面对。下面按出事的顺序拆,每节先给结论。
答:账号是权限概念,租户是数据边界,这是两件事。

常见做法是在每张业务表加一个 tenant_id,查询时带上。想法没错,问题在于它靠人记:新加一张表忘了加字段,或者某个统计 SQL 少写一个 where,数据就串了。更稳的做法是把租户条件放进框架的全局作用域,业务层默认不写也带着,需要跨租户时显式声明。一套自研GEO源码如果起初按单客户设计,这一层后补要动每张表。
除了查询层,写入层、队列任务、缓存 key、上传文件路径、日志目录也都要带租户标识。这几处漏一处,表现形式都很隐蔽:缓存 key 只按关键词拼,A 客户刚跑完的结果,B 客户点开直接命中了。
跟进的那半句是:「报表里那条统计 SQL,tenant_id 是手写的还是全局作用域带上的?」手写的地方总会有漏网的一条,而且往往在没人复核的导出接口里。
答:三种,按客户类型和交付方式选,没有哪套能通吃。
共享库共享表加 tenant_id:改动量小,一套升级全生效,成本低,隔离也弱。适合自己内部多个小组用,或者客户对数据归属不敏感。
共享库分 schema 或按租户分表:备份能按租户拆,误查的范围小一截,代价是迁移要逐租户跑。
每客户独立库或独立部署:物理隔离,讲数据私有化时底气足,客户看着也更像专属系统,代价是部署和升级要逐套做。
判断标准很实际:客户签合同里有没有写「数据不得与其他主体混存」。写了,就别选共享表。
跟进的那半句是:「某个客户要导出自己的完整数据,多久能拿到?」答不上来的,说明备份是整库做的,按租户拆不出来,换供应商时这条会变成纠纷。
答:这两处比查询层更容易串,因为任务一旦离开请求上下文,租户信息就丢了。
检测任务入队时要把 tenant_id 写进 payload,worker 消费时先还原租户上下文,再落库。只带 keyword_id 不带租户的任务,写结果时会落到默认库,后台看着像「这次没检测到」,其实是写到别人那儿去了。
额度要按租户独立计量并各自限流。共用一个计数器的系统,一家跑爆,其他客户一起停;更麻烦的是失败重试没有单租户熔断,一家平台 key 失效,重试会把公共队列堵满。GEO源码的检测模块若只按单客户跑过,任务上下文往往没做还原。
跟进的那半句是:「某个客户连续失败,会不会把别家的任务一起拖住?」要有独立队列或者公平调度,不然一户出问题全站卡,客户来问的时候你连是谁拖的都说不清。
答:每个租户一套平台 key、代理、超时、开关,不能都塞在全局 .env 里。
这一层在单客户版本里通常是一个配置文件,改成多租户时要挪进数据库,并且加密存储、日志脱敏。八个平台各自的 key、额度、启用状态都按租户存,某个客户自己的 key 到期,不该影响其他客户。
还要注意配置加载时机。启动时读进常量的写法,改一个租户的参数就得重启服务,其他租户跟着抖一下;运行时按租户读取,才能做到互不影响。
跟进的那半句是:「换一家的 key,其他客户要不要重启服务?」要重启,说明配置还是启动期常量,后面客户一多会变成运维负担。
答:按租户取主题配置,别为某个客户改代码。
logo、favicon、系统名称、后台标题、主题色、邮件与短信模板、客户协议,这些存成 tenant_id 对应的配置行。域名解析到租户之后,登录页、找回密码链接、邮件里的跳转地址都要带上租户上下文,否则客户用自己的域名点开邮件,会跳到别家的登录页。
2026年做贴牌交付,把上面这些放进配置表,比逐个改主题文件省事。容易漏的是那些不走主流程的页面:404 页、邮件页脚、导出文件的文件名、错误提示里的系统名。这些地方不进验收清单,上线之后被客户自己发现,比功能 bug 更伤信任。
跟进的那半句是:「客户用自己域名访问,404 页和邮件页脚会不会露出别家的名字?」这两处是贴牌事故的高发位置。
答:迁移文件带版本号,并且记下每个租户跑到哪一版。
共享表结构的部署,一次迁移影响各个租户,所以要先在一个影子租户上跑通,再上生产;结构变更涉及历史数据时,还要能按租户分段重算,别一把梭全表 update。
独立库的部署,逐库执行,中断之后能从断点续跑,失败的那个租户可以单独回滚,而不是整站回退。升级记录里留一句「哪次改版动了哪个适配器」,平台改版时才好定位。GEO源码的迁移脚本若不记录每个租户跑到哪一版,中断之后就没法从断点续跑。
跟进的那半句是:「某个租户升级失败,能单独回滚它吗?」答不上来的,说明升级是整站一次性的,出问题只能全停。
答:验收一套GEO源码的租户隔离,开两个租户交叉跑三项,别只看菜单和截图。
其一,A 传一条只有自己知道的关键词,在 B 的报表、搜索、导出文件、引用明细里查一遍,不能出现。
其二,A 把额度跑空或者连续失败,B 的检测任务照常完成,队列不堆积。
其三,A 换掉域名和 logo,B 的登录页、邮件模板、导出文件名保持原样。
三项都过,隔离才算成立。人工点一遍能发现眼前的问题,挡不住后面每次改代码,所以这三项建议写成自动化回归用例,跟着每次发版跑。
跟进的那半句是:「跨租户的回归用例有没有进发版流程?」没有的话,隔离做得再细,也会在某个新加的接口上被重新打破。
三个追问
问:客户少的时候要不要上多租户?
答:三五个客户、又都要各自的后台,按客户各部署一套反而省事,隔离天然成立,代价只是升级逐套做。租户数是被运维成本逼出来的选择,不是越早上越好。
问:多租户会不会削弱数据私有化这个说法?
答:会,得讲清楚。逻辑隔离不等于物理隔离,客户在意这一点时,把存储方式写进合同比在方案里含糊过去稳。别把「数据在你手里」讲成「数据只在你手里」。
问:SAAS 和源码在这件事上差在哪?
答:SAAS 是替你把这一层管好;源码是把这一层交给你自己管。前者省心,后者自由,改得动改不动取决于代码结构,这也是看一套自研GEO源码值不值的地方。
文末说个不太好听的判断。
一套GEO源码能不能卖给多个客户,看有没有租户管理菜单说明不了什么。菜单一天就能加,查询作用域、队列上下文、租户级额度、逐租户迁移这四样凑不齐,加得再漂亮也只是把风险往后推。四样都在,客户从三个涨到三十个,你要补的是机器,不是重写系统。
我们在做GEO系统时,把 tenant_id 放进全局作用域和队列上下文两处,就是为了不让后来新增的每张表、每个任务都靠人记得补一个条件。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。