烟囱架构重构,最近重构了微信生态对接业务

写在前面,本文只讲理论,不写代码,若有疑惑请留言。

写作背景

最近,又马不停蹄重构了历史更悠久的屎山代码,代码追溯可以到2019年10月了。说起来也有意思的,这个模块我还没到公司的时候开发上线了,后来加入公司我也贡献了一批代码,公司越来越大,拆分了多个团队,这个模块后来交接给我们团队了,由于团队的业务太多了后续又交接到兄弟团队。反反复复交接了4、5、6次吧,经历的开发没有10个也有15个。

哈,没想到今年又回到我手里了,这就是缘分吧。

早在接手项目前,产品同研发拉了一个共创群,主要目的是重新梳理底层模型,更好的适配我们产品未来的发展,刚好产品讨论的跟我们板块更贴切,顺便扩大一些团队的业务边界,接手过来折腾下。

不过接手后发现文档缺失非常严重(这也是公司早期发展过快的历史债),还好当初我也贡献了不少代码,所以整个流程还是熟悉的。

核心模型和能力层变动不大,但接口明显更多了,新老接口并存都有流量,很难分清楚使用这些接口的背景是啥,该如何下手整合接口;

测试环境和线上环境问题严重,经常处理测试环境数据,客户提需求手动处理数据,主要是代码在多个服务,链路比较长,心累+1;

好了,言归正传吧,我想重构这个板块其实有下面几个原因:

  1. 这块一直年老失失修比较混乱,一部分代码还是19年的也没有设计文档,中途经历迭代并都采用烟囱的架构垒上去,散落到6-8个应用里面,这块架构需要好好治理下;

  2. 经常要人为介入协助客户处理一些数据,人力成本挺高的;

  3. 梳理底层模块,更好适配产品未来发展;

  4. 主要还是产品最近有需求。

名词解释

获客工具兴起,大家对公众号,小程序,视频号,抖音小程序等,应该都不陌生吧?

挺多公司也基于抖音/微信生态做了一系列获客工具,来帮助客户更容易获取线索,针对这些线索做转换和运营,最终达到成单目的。

常见生态比如抖音生态(抖音流量是很大的,现在短视频也很火爆,如果能把这些流量转换为私领域流量,价值还是很大的);另外就是微信生态,小程序套电、授权留资等。

对接这些生态无非就是干几件事儿

  1. 获取用户信息留资,常见信息有 unionid、头像、昵称等。

  2. 套电,拿用户手机号。

为了帮助大家快速了解平台相关名词,下面对常见术语进行归纳,有助于对后续架构重构的理解。感兴趣可以看看微信生态/抖音生态官网。基本概念介绍 | 微信开放文档developer.open-douyin.com/docs/resour...

抖音生态和微信生态,差异不大,主要以微信生态为主来介绍。

服务商

服务商如字面意思,就是为商家/卖家服务的,那如何服务呢?商家需要将其公众号或者小程序授权给第三方平台,服务商才可以代商家进行相关操作。比如:代授权、代发布小程序等。

如何完成商家授权 | 微信开放文档

应用 AppId

在微信生态,不同的应用(微信小程序、公众号、视频号)都有唯一的标志,可以理解为不同产品的身份ID。

OpenId

openid 是微信用户在不同类型的产品留下身份ID,微信用户访问不同产品(小程序、公众号、视频号)都会产生不同的身份Id,对于不同的公众号,同一个微信用户访问产生的openid也不一样。

多一嘴,在大部分场景openid都是没有用处的,目前我知道的在支付场景会用。

Unionid

UnionID 是微信用户在同一个开放平台下不同产品留下身份ID,这个身份ID就比较牛逼了,只要在同一个开放平台下,不同的产品比如:不同公众号、小程序、网站应用,可通过 UnionID 来区分用户的唯一性。即,同一用户,对同一个微信开放平台下的不同应用,UnionID 是相同的。

商家开放平台

要将商家的公众号、小程序绑定到商家的开放平台账号下,才能实现为商家将公众号和小程序的用户身份打通,也就是实现同一个用户在不同应用留下的 unionid 是相同。

微信生态画了一个图还挺直观的

商家"绑定" VS "授权"

"绑定"指的是将商家的公众号或者小程序账号绑定到商家的开放平台下,主要是为了实现用户身份打通。

"授权"是指商家将其公众号或者小程序扫码授权给服务商的第三方平台账号,主要是为了代开发,比如:小程序开发、发布等。

用户身份

什么是用户身份?每个人的理解和定义都不一样,微信小程序授权拿openid、unionid算是一个身份、访客访问浏览器产生的cookie也是一个身份、客户的手机号、设备码、ip 分别也算是一个身份。

按照我的理解,用户只要在互联网上留下的痕迹就算是用户身份,最终将用户的不同是身份 mapping 起来,能识别成同一个用户,能把他/她在系统内留下的全部链路串起来得到全链路溯源能力。

架构现状

好了,啰啰嗦嗦讲了一堆生态的名词,开始正文。架构现状比较复杂,初期对架构设计要求没有这么高,基本都是有需求就垒上去,再加上对接这类生态产品形态并不是一开始就想的非常清楚的,所以,多多少少都会有点问题。

一图胜千言,直接看我梳理的架构图吧。

上图,我分了4个模块方便理解,从途中可以看出不同的烟囱都有属于自己的模型、核心能力、以及对外提供的API。意味着,存在下面几个问题:

  1. 重复建设和维护,对于同一个生态来讲,不同应用的授权、管理、配置都是大同小异的,(备注:我们梳理发现抖音生态和微信生态的差异都不大),所以,模型、能力层提供的能力、接口是可以复用一大部分的,不用重复开发和建设,减少研发成本。

  2. 数据打通成本高,比如:某一天产品需求要打通用户数据、实现全链路溯源,这时候就会发现各种阻碍,这里不行那里不行,改造成本是很高的。

  3. 不利于业务/技术沉淀,模型、能力不能复用,如果某一天有相似的场景,无法复用,只能重新造轮子,没有更好的赋能相似业务。相当于你做了一个组件,使用方根本接不进来。

新架构

这次梳理下来直接相关的后端应用有7个,数据模型15个,接口大概是在60-70个左右,接口都在不同的应用里。

在页面上点点点,都要调好几个应用,调用关系是非常复杂的,涉及的模型没有按域来划分,相互查。

分享我梳理类似比较难啃业务的方案或者说是技巧。

  1. 利用血缘关系看板(某大佬留下的),方便找到流量的调用关系网,比如:A服务调用方是B,并且调用了a接口100次、b接口300次、c接口400次...等,能方便我找到影响范围,并且知道哪些接口有流量,有业务方在用。

  2. 熟悉业务,我一般是在对应的功能页面测试功能,顺便整理前端不同页面调用了哪些接口,通过这些接口可以顺藤摸瓜,找到对应的应用(熟悉业务是非常有必要的,如果需求不合理,可以跟产品沟通调整需求,会有意想不到的收获)。

  3. 业务模型读写日志,如果某个应用有对业务表的读写,我建议你埋点把这些表读写日志记录下来,方便定位问题,有利于未来技术方案梳理。

  4. 问,每个业务都有熟悉的测试、产品、研发,一般来说测试是最熟悉的,利用这些资源能帮你快速梳理业务。

  5. 历史文档,按照我的经验,历史文档的意义不是特别大,尤其是设计文档。见过太多系分设计和最终上线的架构差异较大的,所以别抱太大希望。

  6. 看代码,一般都很痛苦,但是必须要经历的,通过代码能直观看出"开发同学"的编码能力、以及代码对应的业务。

理想中的架构
  1. 业务模型抽象,相似的业务场景,能用同一套模型收敛。

  2. 能力层复用,尽量造一些通用的轮子,比如:商家授权小程序、公众号,都是通过服务商预授权码授权,所以预授权出码的能力是共用的。

  3. 接口复用,提供通用原子接口,对于公众号、小程序的管理端列表、商家授权、解绑...等,逻辑都是一样的,所以这些接口应该都是同一个,没必要单独写。

好了,架构如上图,不同业务模型复用了不部分,所以模型相对也较少。那有人会问了,抖音、微信生态都有特定的字段怎么兼容呢?首先类似的生态对接,基础字段基本都一样,差异的字段冗余就可以了,如下:

go 复制代码
type A struct {
	ID    string `bson:"Id"`
	Extra Extra  `json:"extra"`
}

type Extra struct {
	X string `bson:"x"`
}

能力层也是可复用,不同的能力相互独立的,基本没有耦合,假设未来接新平台,只需要编排这些能力就可以了,并不需要多大开发量。

标准接口,按照我目前的规划,微信生态、抖音生态接口都是一套,也不需要开发过多接口,能复用的绝不开发,本来接口就是编排能力的,根据不同的业务做好设计模式就可以了,代码不难懂。

系统边界

什么是系统边界?系统边界是系统与系统的分界线,用以区分不同的系统。比如:a团队开发了n模块,需要b团队的x模块支持。所以,a团队和b团队都是有工作量的,在一些大版本跨越多个团队,厘清系统边界非常重要了。我一般喜欢画边界图,把每个团队要做的工作梳理清楚。

列一个简单边界图,下图是关于对象存储的编辑图,比较简单用于写文章比较合适。

架构拆解

模型设计

模型比较简单,有2个模型比较重要,商家授权记录、C端用户身份记录。只要把用户身份定义清楚也不难。

Token 管理器

token管理器主要负责token生命周期管理,对接过三方open-api的应该都清楚,如果你要调用open-api接口肯定需要调用凭证。并且为了安全,token是有时间限制的,一般都是2小时,所以,token过期后,需要自动续期,保活。

token续期一般有2种方案。

  1. 定时调度,针对每个授权应用(公众号、小程序)都创建调度任务,假设:微信平台2小时过期,定时任务可以设置为1小时50分回调,提前刷新token。

  2. 利用redis过期策略,生成token存入redis并设置过期时间,假设:微信平台2小时过期,过期时间可以设置为1小时50,缓存miss,重新生成就好了。另外,做一个兜底方案,生态接口调用都会返回错误码,若错误码是token失效强制刷新token重试接口。

我更倾向方案2,方案1有2个缺点:

  1. 引入额外的中间件,调度任务随着授权应用越来越多调度任务膨胀;

  2. 若商家取消授权需要删除调度任务,如果任务删除失败调度任务就死循环了;

相比方案2就简洁了一些,不用关心商家取消授权,redis自动过期就好了。

生态接口收敛

微信/抖音生态接口加起来也有几百个吧,不可能所有接口都封装一遍,这多费时费力呀。所以,最好做一个代理网关,思路如下图:

  1. 定义抽象接口 Adaptor,包含若干方法,比较重要的就是将 mgr 的 http body 反序列化为外部真实对象,向上返回一些关键错误码。

  2. AdaptorMgr 主要负责链接完整性拼接,比如拼接 token、appid...,发起 http get/post 请求,返回最终数据。

  3. TokenMgr 主要就是token管理器,管理 token 的生命周期。

  4. 业务方,只需关注外部生态的业务参数、和返回值即可。

优化技巧

前面写过一篇文章祖传屎山代码平时不优化,一重构就翻天覆地 - 掘金有一些常见的优化技巧,已经讲的很清楚了,这里不在赘述,感兴趣看看。

总结

  1. 作为大型迭代的负责人,你必须清楚每个团队的职责,以及工期。系分设计阶段梳理业务边界,厘清兄弟团队的边界和职责尤其重要,避免项目后期越做越拉垮。

  2. 重构前,先厘清业务逻辑、技术链路。按照模型层、能力层抽象底层模型、通用能力,业务接口编排能力层支撑丰富业务场景,避免烟囱式架构。多一嘴,业务接口并不越多越好,尽量保证接口的通用性,避免重复开发。

  3. 聊聊业务,微信/抖音生态对接其实很简单,就干下面几个事儿,不用想的太复杂。所以,就瞄着复用的思路做好系分设计,开发结果都不会太差。(多一嘴,你可以多找几个生态的对接文档分别看看它们的差异,有助于你的模型设计)。 a) token凭证续期;

    b) 接口封装;

    c) 关键数据存储;

相关推荐
58沈剑22 分钟前
80后聊架构:架构设计中两个重要指标,延时与吞吐量(Latency vs Throughput) | 架构师之路...
架构
齐 飞1 小时前
MongoDB笔记01-概念与安装
前端·数据库·笔记·后端·mongodb
LunarCod1 小时前
WorkFlow源码剖析——Communicator之TCPServer(中)
后端·workflow·c/c++·网络框架·源码剖析·高性能高并发
码农派大星。2 小时前
Spring Boot 配置文件
java·spring boot·后端
杜杜的man2 小时前
【go从零单排】go中的结构体struct和method
开发语言·后端·golang
幼儿园老大*2 小时前
走进 Go 语言基础语法
开发语言·后端·学习·golang·go
llllinuuu2 小时前
Go语言结构体、方法与接口
开发语言·后端·golang
cookies_s_s3 小时前
Golang--协程和管道
开发语言·后端·golang
为什么这亚子3 小时前
九、Go语言快速入门之map
运维·开发语言·后端·算法·云原生·golang·云计算
想进大厂的小王3 小时前
项目架构介绍以及Spring cloud、redis、mq 等组件的基本认识
redis·分布式·后端·spring cloud·微服务·架构