正在开发一个 app ,用户在使用 app 访问服务时,需要根据对应的服务从后端获取对应的配置文件( json 格式)。
一共有上千个独立的配置项。
目前是当 app 第一次启动时,会首先通过接口查询配置项清单,然后再依次对各配置项进行请求获取。
这样的问题是,一个 app 就会向后端发起上千个请求。而且可能需要十来分钟甚至更长时间才能把全部配置拉下来。
这样一方面对后端服务器造成压力,另一方面影响用户体验。
如果把配置全部打包在一起的话,大概40-50MB左右。
有些配置项还会更新,这就需要app 在后续的运行过程中对有更新的配置项进行更新。
|      1yyyyyyh      2024-09-02 10:49:29 +08:00 一个客户端就是上千请求。。。   100 个客户用 ,对后端来说岂不是 10W 的并发了。    如果还有更新的话, 建议用实时通讯的方式会好一点。 MQTT 或者 websocket 就当你在做一个 IM 。 | 
|  |      2GotKiCry      2024-09-02 11:03:23 +08:00 一个 app 向后端发起上千个请求?你确定该优化的不是后端逻辑吗 | 
|      3onichandame      2024-09-02 11:10:04 +08:00 渐进式不行吗?这上千个配置项既然是独立的,那应该是各自影响各自的页面,为啥要一次性全拉下来?进首页就只拉首页的配置,进登录页就只拉登录页的配置。我感觉现在的梭哈式设计是前端的锅。。 | 
|  |      4shadowyue      2024-09-02 11:10:20 +08:00 上千个配置马上就要用吗?按需加载吧 | 
|  |      5cweijan      2024-09-02 11:12:38 +08:00  6 先把程序员优化了吧 | 
|  |      6rockddd      2024-09-02 11:14:27 +08:00 大佬们的脑子已经宕机了😰 | 
|      7horizon      2024-09-02 11:14:49 +08:00 @onichandame #3  明显是后端配置项设计的问题 | 
|      8flytsuki      2024-09-02 11:18:58 +08:00 这。。。人都麻了 | 
|      9liuyx7894      2024-09-02 11:20:29 +08:00 比较好奇什么 APP 会需要这么多配置项 | 
|      10liuidetmks      2024-09-02 11:22:47 +08:00  4 既然已经这样了, 把配置当做静态文件,放在 oss 上吧,让 app 去刷吧 业务能稳定运行最重要 | 
|  |      11nice2cu      2024-09-02 11:22:59 +08:00  1 按需请求 合并请求 后端配置存储走缓存 | 
|      12bootvue      2024-09-02 11:23:37 +08:00 json 放到 oss 上    后端更新 | 
|      13onichandame      2024-09-02 11:24:48 +08:00 @horizon 后端可以怎么优化 | 
|      14RightHand      2024-09-02 11:28:47 +08:00 via Android 按需加合并呗,这就是后台偷懒,不是什么都要原子化的 | 
|  |      15Hilong      2024-09-02 11:32:29 +08:00 这接口设计有毒吧。搞个 bff 层聚合一下啊 | 
|  |      16Puteulanus      2024-09-02 11:34:47 +08:00 把默认的全量配置都内置在 App 里,然后你们服务器那边每次改的时候打个版本,App 拉更新的时候根据版本号只增量拉修改了的配置项( patch ) | 
|      17ala2008      2024-09-02 11:35:25 +08:00 说实话,业务是不是不合理 | 
|  |      18cinlen      2024-09-02 11:38:59 +08:00  4 能否分享一下,什么情况下 app 一启动就需要 40~50MB 的配置量? | 
|      19horizon      2024-09-02 11:40:54 +08:00 @onichandame #13  首先把配置项分分类,不是所有的配置项都要实时从数据库里查吧 一些通用的可以提取出来,像上面说的放到 OSS 里 每次启动的时候从 oss 里获取咯 另外一些实时获取的,接口优化聚合一下,也分分类,首页只获取必要的 | 
|  |      20lasuar      2024-09-02 11:43:11 +08:00 按 描述,判断 OP 几乎是个后端新手水平。 | 
|  |      21tool2dx      2024-09-02 11:44:40 +08:00 采用类似游戏客户端的差异化更新,第一次向打包一部分预配置到 app 内,每次启动,有新变动再申请下载。 | 
|      22onichandame      2024-09-02 11:46:07 +08:00 @horizon #19 静态的移到 oss 没问题,动态的配置项分类获取不就是我说的渐进式获取吗。。。要优化的是前端的调用逻辑,后端接口根据题主说的明显已经分成了不同的接口 | 
|  |      23LieEar      2024-09-02 11:48:11 +08:00 我觉得也可以采用 OSS 方案,打包后上传,让 APP 直接去 oss 拿 | 
|  |      24rb6221      2024-09-02 11:48:48 +08:00 啥系统啊这么多配置,感觉大厂的 APP 都没你们多 | 
|  |      25spicy777      2024-09-02 11:50:17 +08:00 高并发就是这么玩出来的是吧 | 
|      26zgsi      2024-09-02 11:50:52 +08:00 不改变现状的话,就 oss+cdn 吧 | 
|      27horizon      2024-09-02 11:52:09 +08:00 | 
|      29horizon      2024-09-02 11:54:44 +08:00 | 
|  |      30adoal      2024-09-02 12:12:11 +08:00 如果是 to B 的项目,别优化了,to B 哪有不纵容屎山的。如果是 to C 的项目,首先重构业务逻辑。 | 
|  |      31mb4555      2024-09-02 12:26:18 +08:00 不变的直接打包到 app 里面 | 
|  |      32potatowish      2024-09-02 12:30:09 +08:00 via iPhone 把配置按使用场景分类,加个聚合层 | 
|      33mooyo      2024-09-02 12:30:56 +08:00 app 层抽一个 proxy configuration manager ,服务端定期聚合部分 config ,如果是用户无关的,聚合成 CDN 文件,如果用户相关的,走接口一次性拉下来 | 
|  |      34learnshare      2024-09-02 12:33:46 +08:00 是一次把数据库全吐出来吗 还是所谓的原子化、微服务 进入 App 的时候,第一个页面要用到所有数据? | 
|      35mymail6811      2024-09-02 12:38:14 +08:00 在服务器加一层, app 给服务器发一个请求, 服务器再去获取那上千个配置项并返回. 之后再慢慢改后端 | 
|  |      36MoozLee      2024-09-02 12:53:26 +08:00 好想见识一下这个 app | 
|  |      37aboutboy OP @onichandame 也想过这个方式,感觉可能最合适的方案。 | 
|  |      38aboutboy OP @Puteulanus 现在是一次全部拉取,如果有更新的话,可以通过接口获取更新列表,再按照列表去拉取。 | 
|  |      39aboutboy OP @learnshare 其实只有在访问某个页面的时候才会用到那个对应的配置。可能是为了让用户不等待,所以在 app 首次启动的时候去把几千个配置都拉下来。感觉产品上用户访问某个页面时是可以接受等待加载配置的。 | 
|  |      40aduangduang      2024-09-02 13:36:48 +08:00 配置项清单带上每个配置的 md5 结果 前端第一次请求全部内容后本地存储 后续只请求配置项清单,和本地配置项清单做对比后 增量同步有变动的内容 | 
|  |      41qbmiller      2024-09-02 13:38:08 +08:00 是游戏吗? 40-50m.   长连接 ( mqtt 那种也行)|| oss | 
|      42superedlimited      2024-09-02 13:41:52 +08:00 via iPhone hoge ? | 
|      43onichandame      2024-09-02 13:43:34 +08:00 @horizon #29 没访问到的页面的配置项就不需要拉了呀。不过我倒是先入为主地觉得独立的配置项来自不同的独立接口,如果真是一个通用接口调一千次那确实后端有问题 | 
|  |      44aduangduang      2024-09-02 13:44:57 +08:00 @aduangduang 每次 APP 新版本打包的时候可以把当前的配置项一起打包,这样首次启动也不需要大量请求了 可以统一使用增量同步的逻辑 | 
|      45ShuWei      2024-09-02 13:47:28 +08:00 你确定这些东西能叫配置项? | 
|      46fov6363      2024-09-02 13:56:53 +08:00  1 一个类似的解决办法,加一个 BFF 层,将所有接口汇总为两个接口: 1 、/api/config/update 2 、/api/config/list app 在打包时,自动从 /api/config/list 拉到最新的全量的配置,并返回一个 hashId 来标识这次结果,这样用户打开 app 所有功能都是可用的。 然后 app 定期轮询 /api/config/update?id=$hashId ,如果有变更,就返回 true ,然后 app 端异步更新 diff 数据(复杂点就设计一套 add 、update 、delete 的语法,简单点就全量再拉一遍),如果无变更,就返回 false 。 这样针对相同的 hashId 还可以做 cache ,对后端的压力比较小 | 
|      47wxf666      2024-09-02 13:59:15 +08:00 | 
|      48henix      2024-09-02 14:00:47 +08:00 展示加载进度条 | 
|      49wOuv7i4e7XxsSOR1      2024-09-02 14:01:24 +08:00 什么样的配置会有 40-50M? 你知道 40M 存文本可以存多少吗? | 
|  |      50106npo      2024-09-02 14:06:15 +08:00 via Android 就算 5000 个吧,50m 每个配置 10k ? 如果有压缩的话,每个配置原始有上百 k 了?那不能说后端没努力了,你们这一个配置就比别人整个配置大了 | 
|  |      51Tink PRO 重构 | 
|      52hwb      2024-09-02 14:08:54 +08:00 好想见识一下这个 app | 
|  |      53ruobingm      2024-09-02 14:11:13 +08:00 我比较想看 到底这上千个配置 都配置了啥?需要在首页获取? 很想知道。。 | 
|      54fffq      2024-09-02 14:12:56 +08:00 能跑吗 | 
|  |      553IOhG7M0knRu5UlC      2024-09-02 14:13:01 +08:00 这配置不得有几千万字了 | 
|      56MozzieW      2024-09-02 14:16:11 +08:00 最简单的,加上一个缓存,时间戳没变就不要更新了,1000 个配置频繁变的也没有几个。 还是正在开发的,这个 App 没有人用,放弃吧 | 
|  |      57joyoyao      2024-09-02 14:19:50 +08:00 这玩意交给后端处理不就行了,app 只需要请求后端接口,那些需要展示,接口就返回,不需要展示接口就不返回。垃圾后端,自己不想搞,就恶心前端,交给前端搞。 | 
|  |      58burymme11      2024-09-02 14:20:44 +08:00 oss+cnd  指标不治本、 好好整理下这些配置吧,几千个配置竟然要 40.50M ?? 你们不会把用户个人数据全部塞在配置里了吧? | 
|  |      59Mephisto233      2024-09-02 14:22:41 +08:00 看这需求怎么感觉有点像是马甲包?先用正常 app 过审核,上线后通过配置项直接改界面? | 
|  |      60vipfts      2024-09-02 14:26:25 +08:00 @Mephisto233 哈哈, 变身🥵 | 
|  |      61ktqFDx9m2Bvfq3y4      2024-09-02 14:27:41 +08:00 via iPhone 低代码? | 
|  |      62k9982874      2024-09-02 14:29:50 +08:00 建议废除后端,app 直读数据库 | 
|  |      64unco020511      2024-09-02 14:37:56 +08:00 可以参考 firebase 的 remoteConfig 产品 https://firebase.google.com/docs/remote-config 几个关键点: 1. 有本地默认配置文件,用于各种情况下的兜底配置 2. 配置有分组,支持分组更新/获取 3. 有版本号机制,支持增量更新,绝大部分情况都应该是增量差异更新 4. 可选长链接,实现 real-time 更新机制 5. 扩展可与各种其他产品结合,比如与你的业务 api 网关结合,在 header 中携带客户端配置的版本号,网关中去拦截,如果线上有版本号更新,则触发配置更新,配置更新在客户端可以独立进程,做到业务无感 | 
|  |      65unco020511      2024-09-02 14:41:35 +08:00 最关键的,就是动态配置是需要定期去固化清理的,比如一段时间去做一些 abtest,或者一些功能的临时开关,过了几个版本业务验证完之后一般是需要有明确数据结论去支撑,然后固化配置的.你现在配置数据有上千个,讲道理不太合理 | 
|  |      66icyalala      2024-09-02 14:46:41 +08:00 哈哈,FGO 游戏逻辑就是这样,一启动就要下载几十 MB 的 JSON 配置数据,后来嫌大就改成 pb/msgpack 了。 | 
|  |      67lingalonely      2024-09-02 14:47:40 +08:00 游戏更新的时候不是有个加载过程吗,把这些配置传过来就行,没有必要请求上千次 | 
|  |      68broken123      2024-09-02 14:49:25 +08:00 app 有个东西叫做启动器 https://blog.csdn.net/jdsjlzx/article/details/129019317 道理都是通用的 每个端都可用 哦 | 
|  |      69FreshOldMan      2024-09-02 14:58:17 +08:00 app 一进来是首页什么情况下需要上千个配置,这些配置不能在后端配置好再下发吗? | 
|  |      70yufeng0681      2024-09-02 15:01:31 +08:00 @Mephisto233 #59 如果是这种需求,是不是资源包在本地,网上只要弄个配置,就能启用第 N 套资源当界面更好? 资源压缩后扩展名改成不可预知的,规避审核人员打开即可。 | 
|  |      71Solix      2024-09-02 15:03:07 +08:00 via iPhone 不是应该进啥模块加载啥配置吗…… | 
|  |      72winglight2016      2024-09-02 15:05:10 +08:00 这既是产品设计的缺陷,也是后端架构设计的缺陷,哪个 APP 需要一次性下载 1000 个配置项?再说了,有什么配置项非要在客户端才能起作用的? 退一万步说吧,即使真的就要启动前加载好 1000 个配置项,也只需要 app 内建一套默认配置,等到用户修改了某项配置再做 diff-merge 操作就够了,我不信哪个用户上来就把 1000 个配置项全部自定义一遍。 | 
|  |      73lambdaq      2024-09-02 15:06:38 +08:00 不要盲目优化啊。先说加多少钱。 越屎的代码越值钱。 | 
|      74wu00      2024-09-02 15:10:44 +08:00 某几个配置占了 50M ,剩下 99x 个配置占了几百 K ? | 
|  |      75yufeng0681      2024-09-02 15:12:24 +08:00 所有配置项梳理分类 1 、按加载重要性排序, 启动必需的,首页必需的,二级页面必需的 2 、按更新频率分类:不更新的(放 app 里),不经常更新的(初始数据放 app 里),频繁更新的(只存网络, 这类配置要精简到极少个) 3 、按功能分类:模块级数据同步,模块级配置接口,系统级配置接口,系统级数据同步 。 不要把所有数据用配置接口获得,可以换成数据同步,这样接口不涉及业务,只是数据同步。 服务端数据文件由各个模块自己负责生成,客户端也是由模块代码负责去获取数据文件。 | 
|  |      76juzisang      2024-09-02 15:12:49 +08:00 40-50M ,是把图片转 base64 放配置里了吗...要不然纯配置怎么可能这么大,还请求上千次... | 
|      77lefer      2024-09-02 15:13:55 +08:00 @onichandame #3 我觉得你的方案是可取的。 | 
|  |      78cBlank      2024-09-02 15:14:17 +08:00 参考游戏的启动流程 | 
|  |      79xuanbg      2024-09-02 15:14:48 +08:00 这上千个达到 4-50M 之巨的所谓配置数据,不知道有几个是配置项,几个是模版数据,估计 99%其实都是模版数据吧,要不然怎么可能有几十 M 。。。。。 办法很简单,配置项启动一次加载,模版数据完全可以按需加载。 | 
|      80realJamespond      2024-09-02 15:30:55 +08:00 拼成一个 json 一次发过来 | 
|  |      81icyalala      2024-09-02 15:47:21 +08:00 给你们看看现实中几十 MB 配置项的例子: 这是 FGO 手游每次启动下载的 JSON 配置数据,80M+,现在更大了所以不用 JSON 了 https://github.com/UnderFGO/MasterDataDumper/releases | 
|      8228Sv0ngQfIE7Yloe      2024-09-02 15:58:17 +08:00 @icyalala #81 这种一般是放在 OSS 获取吧 | 
|      83FireKey      2024-09-02 16:02:50 +08:00 应用的话配置 copy 一份存本地,配置版本变化时再更新对应项.如果运行中需要及时更新,考虑将配置版本加入 headers 中,版本更新了接口走更新流程 | 
|  |      84panlatent      2024-09-02 16:06:13 +08:00  1 纯色背景配上点大字: ”嗨,别来无恙“ ”一切即将准备就绪“ ”这可能需要几分钟“ ”马上就好“ | 
|      85ysw      2024-09-02 16:07:17 +08:00 json 放 cdn ,然后按需加载,应该就差不多了 | 
|  |      86icyalala      2024-09-02 16:09:33 +08:00 @Morii 这个配置数据变动还没那么频繁可以放静态,但用户数据游戏进度就不行了,那个同样也不小。 如果不换架构的话,最简单的办法就是换格式,用 protobuf/msgpack 再压缩一下,客户端选个高性能的解析库,这个量级基本还是够用的。 | 
|  |      872owe      2024-09-02 18:02:42 +08:00 按需缓存吧,首先获取一下当前需要更新的配置,只获取有更新的部分 | 
|      88veightz      2024-09-02 18:49:48 +08:00 问题还挺多, 不是单方面的。整体方案就挺奇怪的,感觉没有沟通好设计。。 客户端的问题: 1. 用户体验问题肯定要客户端解决。不可能同步等这份配置吧,这个数据量的下载,反序列化,都是不小的开销。一般来说是同步读客户端缓存,异步刷新数据。 2. 配置同步做下版本管理, 记录下版本的上一次同步时间。 做好缓存时间控制。 服务端问题: 1. 上千个配置下是同构的吧? 一个读结构不同的配置项 key 吧? 要支持批量的接口。 2. 服务端都做热缓存吧, 有内存缓存的话, 我觉得性能本身倒是还好。 但是目前方案我觉得你们的第一个瓶颈是带宽。 3. 我觉得可以的方式是读 cdn , 配置大概率也不是高频更新的,可以结合 etag 等手段, 确定有数据变更了再回拉。 | 
|  |      89xiangyuecn      2024-09-02 19:03:41 +08:00 能用上你们的 app 的客户也是倒了八辈子霉🐶 | 
|  |      90Ritr      2024-09-02 20:38:59 +08:00 什么 APP ,说出来我避雷 | 
|      91shunia      2024-09-02 21:54:52 +08:00 游戏不就是这样的吗? 一万个配置文件也可以做一个更新列表,有更新的才拉,没更新的用缓存。 基本只有冷启动会全量下载,热启动基本很难遇到大量更新的情况。 | 
|  |      92simo      2024-09-02 22:03:56 +08:00 如果你说的 50M 的配置必须所有人都加载,那就分析下,拆分请求,按需,数据压缩,缓存,cdn 。 | 
|      93murmurkerman      2024-09-02 22:10:05 +08:00 via iPhone 这个明显要用增量更新,可以看看有没有类似于 remote config 的国内替代。没有的话只能自己撸一个。也可以借助 s3 ,oss 实现,s3 文件下载都会返回一个文件内容的 hash 值,可以用 head 请求判断是否更新了。然后就是拉配置的时候需要有一个请求队列,安卓 okhttp 自带,不用担心网络并发。 配置下载也可以加一个分页接口,一次下载 n 项。 最好还是用 protobuff 缩小配置文件传输大小。 | 
|      95prosgtsr      2024-09-03 08:15:53 +08:00 via iPhone 放在一个接口全部请求回来。 还可以带上版本号,每次通过版本号获取更新的数据。 我们公司的 app 就是这么干的,没什么问题。 | 
|      96jzphx      2024-09-03 08:33:27 +08:00 启动一次 app 40-50M ,用户流量不要钱的吗 | 
|  |      97duanxianze      2024-09-03 09:13:03 +08:00 不明白,什么样的应用会有这种需求? | 
|  |      98ArianX      2024-09-03 09:25:43 +08:00 上千个配置为什么会有 40M | 
|      99Huelse      2024-09-03 09:29:28 +08:00 区分启动配置和分页配置,另外很多配置都是应该存本地的,更改时发送一份到服务端记录就行了,不需要再次下载。 | 
|  |      100p1gd0g      2024-09-03 09:46:29 +08:00 配置不放 cdn 上?不做缓存?没有增量更新? |