V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
aboutboy
V2EX  ›  程序员

app 初始化时需要通过接口获取上千个独立的配置项,如何优化?

  •  
  •   aboutboy · 14 天前 · 7257 次点击

    正在开发一个 app ,用户在使用 app 访问服务时,需要根据对应的服务从后端获取对应的配置文件( json 格式)。

    一共有上千个独立的配置项。

    目前是当 app 第一次启动时,会首先通过接口查询配置项清单,然后再依次对各配置项进行请求获取。

    这样的问题是,一个 app 就会向后端发起上千个请求。而且可能需要十来分钟甚至更长时间才能把全部配置拉下来。

    这样一方面对后端服务器造成压力,另一方面影响用户体验。

    如果把配置全部打包在一起的话,大概40-50MB左右。

    有些配置项还会更新,这就需要app 在后续的运行过程中对有更新的配置项进行更新

    请问大佬们有什么好的思路?

    106 条回复    2024-09-04 08:00:06 +08:00
    1  2  
    yyyyyyh
        1
    yyyyyyh  
       14 天前
    一个客户端就是上千请求。。。 100 个客户用 ,对后端来说岂不是 10W 的并发了。

    如果还有更新的话, 建议用实时通讯的方式会好一点。

    MQTT 或者 websocket 就当你在做一个 IM 。
    GotKiCry
        2
    GotKiCry  
       14 天前
    一个 app 向后端发起上千个请求?你确定该优化的不是后端逻辑吗
    onichandame
        3
    onichandame  
       14 天前
    渐进式不行吗?这上千个配置项既然是独立的,那应该是各自影响各自的页面,为啥要一次性全拉下来?进首页就只拉首页的配置,进登录页就只拉登录页的配置。我感觉现在的梭哈式设计是前端的锅。。
    shadowyue
        4
    shadowyue  
       14 天前
    上千个配置马上就要用吗?按需加载吧
    cweijan
        5
    cweijan  
       14 天前   ❤️ 6
    先把程序员优化了吧
    wxw752
        6
    wxw752  
       14 天前
    大佬们的脑子已经宕机了😰
    horizon
        7
    horizon  
       14 天前
    @onichandame #3
    明显是后端配置项设计的问题
    flytsuki
        8
    flytsuki  
       14 天前
    这。。。人都麻了
    liuyx7894
        9
    liuyx7894  
       14 天前
    比较好奇什么 APP 会需要这么多配置项
    liuidetmks
        10
    liuidetmks  
       14 天前   ❤️ 4
    既然已经这样了,
    把配置当做静态文件,放在 oss 上吧,让 app 去刷吧
    业务能稳定运行最重要
    nice2cu
        11
    nice2cu  
       14 天前   ❤️ 1
    按需请求
    合并请求
    后端配置存储走缓存
    bootvue
        12
    bootvue  
       14 天前
    json 放到 oss 上 后端更新
    onichandame
        13
    onichandame  
       14 天前
    @horizon 后端可以怎么优化
    RightHand
        14
    RightHand  
       14 天前 via Android
    按需加合并呗,这就是后台偷懒,不是什么都要原子化的
    Hilong
        15
    Hilong  
       14 天前
    这接口设计有毒吧。搞个 bff 层聚合一下啊
    Puteulanus
        16
    Puteulanus  
       14 天前
    把默认的全量配置都内置在 App 里,然后你们服务器那边每次改的时候打个版本,App 拉更新的时候根据版本号只增量拉修改了的配置项( patch )
    ala2008
        17
    ala2008  
       14 天前
    说实话,业务是不是不合理
    cinlen
        18
    cinlen  
       14 天前   ❤️ 4
    能否分享一下,什么情况下 app 一启动就需要 40~50MB 的配置量?
    horizon
        19
    horizon  
       14 天前
    @onichandame #13
    首先把配置项分分类,不是所有的配置项都要实时从数据库里查吧
    一些通用的可以提取出来,像上面说的放到 OSS 里
    每次启动的时候从 oss 里获取咯
    另外一些实时获取的,接口优化聚合一下,也分分类,首页只获取必要的
    lasuar
        20
    lasuar  
       14 天前
    按 描述,判断 OP 几乎是个后端新手水平。
    tool2dx
        21
    tool2dx  
       14 天前
    采用类似游戏客户端的差异化更新,第一次向打包一部分预配置到 app 内,每次启动,有新变动再申请下载。
    onichandame
        22
    onichandame  
       14 天前
    @horizon #19 静态的移到 oss 没问题,动态的配置项分类获取不就是我说的渐进式获取吗。。。要优化的是前端的调用逻辑,后端接口根据题主说的明显已经分成了不同的接口
    LieEar
        23
    LieEar  
       14 天前
    我觉得也可以采用 OSS 方案,打包后上传,让 APP 直接去 oss 拿
    janus77
        24
    janus77  
       14 天前
    啥系统啊这么多配置,感觉大厂的 APP 都没你们多
    spicy777
        25
    spicy777  
       14 天前
    高并发就是这么玩出来的是吧
    zgsi
        26
    zgsi  
       14 天前
    不改变现状的话,就 oss+cdn 吧
    horizon
        27
    horizon  
       14 天前
    @onichandame #22
    「一个 app 就会向后端发起上千个请求」
    看上去是后端把配置项细分了啊
    不然哪需要这么多请求
    gorvey
        28
    gorvey  
       14 天前
    @cinlen 盲猜是以前的中后台系统,迭代了很久产生了大量的字典数据,后端没做优化,然后 APP 用以前的接口问题就暴露了
    horizon
        29
    horizon  
       14 天前
    @onichandame #22
    再渐进不还是要发上千个请求么
    关键要是聚合吧
    大概率是后端新手,创建了一个通用获取配置的接口而且不支持传多个 key 值
    adoal
        30
    adoal  
       14 天前
    如果是 to B 的项目,别优化了,to B 哪有不纵容屎山的。如果是 to C 的项目,首先重构业务逻辑。
    mb4555
        31
    mb4555  
       14 天前
    不变的直接打包到 app 里面
    potatowish
        32
    potatowish  
       14 天前 via iPhone
    把配置按使用场景分类,加个聚合层
    mooyo
        33
    mooyo  
       14 天前
    app 层抽一个 proxy configuration manager ,服务端定期聚合部分 config ,如果是用户无关的,聚合成 CDN 文件,如果用户相关的,走接口一次性拉下来
    learnshare
        34
    learnshare  
       14 天前
    是一次把数据库全吐出来吗
    还是所谓的原子化、微服务

    进入 App 的时候,第一个页面要用到所有数据?
    mymail6811
        35
    mymail6811  
       14 天前
    在服务器加一层, app 给服务器发一个请求, 服务器再去获取那上千个配置项并返回. 之后再慢慢改后端
    li746224
        36
    li746224  
       14 天前
    好想见识一下这个 app
    aboutboy
        37
    aboutboy  
    OP
       14 天前
    @onichandame 也想过这个方式,感觉可能最合适的方案。
    aboutboy
        38
    aboutboy  
    OP
       14 天前
    @Puteulanus 现在是一次全部拉取,如果有更新的话,可以通过接口获取更新列表,再按照列表去拉取。
    aboutboy
        39
    aboutboy  
    OP
       14 天前
    @learnshare 其实只有在访问某个页面的时候才会用到那个对应的配置。可能是为了让用户不等待,所以在 app 首次启动的时候去把几千个配置都拉下来。感觉产品上用户访问某个页面时是可以接受等待加载配置的。
    aduangduang
        40
    aduangduang  
       14 天前
    配置项清单带上每个配置的 md5 结果
    前端第一次请求全部内容后本地存储
    后续只请求配置项清单,和本地配置项清单做对比后 增量同步有变动的内容
    qbmiller
        41
    qbmiller  
       14 天前
    是游戏吗? 40-50m.
    长连接 ( mqtt 那种也行)|| oss
    superedlimited
        42
    superedlimited  
       14 天前 via iPhone
    hoge ?
    onichandame
        43
    onichandame  
       14 天前
    @horizon #29 没访问到的页面的配置项就不需要拉了呀。不过我倒是先入为主地觉得独立的配置项来自不同的独立接口,如果真是一个通用接口调一千次那确实后端有问题
    aduangduang
        44
    aduangduang  
       14 天前
    @aduangduang 每次 APP 新版本打包的时候可以把当前的配置项一起打包,这样首次启动也不需要大量请求了
    可以统一使用增量同步的逻辑
    ShuWei
        45
    ShuWei  
       14 天前
    你确定这些东西能叫配置项?
    fov6363
        46
    fov6363  
       14 天前   ❤️ 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 ,对后端的压力比较小
    wxf666
        47
    wxf666  
       14 天前
    能不能像聊天记录一样,只拉取有更新却没下载过的?

    简单做法:配置项放数据库里,标记创建/更新时间。

    客户端开启时,拉取 [上次开机时间,现在] 范围内的新配置项?

    henix
        48
    henix  
       14 天前
    展示加载进度条
    jdkxnktkdkxod
        49
    jdkxnktkdkxod  
       14 天前
    什么样的配置会有 40-50M? 你知道 40M 存文本可以存多少吗?
    xmumiffy
        50
    xmumiffy  
       14 天前 via Android
    就算 5000 个吧,50m 每个配置 10k ?
    如果有压缩的话,每个配置原始有上百 k 了?那不能说后端没努力了,你们这一个配置就比别人整个配置大了
    Tink
        51
    Tink  
       14 天前
    重构
    hwb
        52
    hwb  
       14 天前
    好想见识一下这个 app
    ruobingm
        53
    ruobingm  
       14 天前
    我比较想看 到底这上千个配置 都配置了啥?需要在首页获取?
    很想知道。。
    fffq
        54
    fffq  
       14 天前
    能跑吗
    GooMS
        55
    GooMS  
       14 天前
    这配置不得有几千万字了
    MozzieW
        56
    MozzieW  
       14 天前
    最简单的,加上一个缓存,时间戳没变就不要更新了,1000 个配置频繁变的也没有几个。

    还是正在开发的,这个 App 没有人用,放弃吧
    joyoyao
        57
    joyoyao  
       14 天前
    这玩意交给后端处理不就行了,app 只需要请求后端接口,那些需要展示,接口就返回,不需要展示接口就不返回。垃圾后端,自己不想搞,就恶心前端,交给前端搞。
    burymme11
        58
    burymme11  
       14 天前
    oss+cnd 指标不治本、
    好好整理下这些配置吧,几千个配置竟然要 40.50M ??
    你们不会把用户个人数据全部塞在配置里了吧?
    Mephisto233
        59
    Mephisto233  
       14 天前
    看这需求怎么感觉有点像是马甲包?先用正常 app 过审核,上线后通过配置项直接改界面?
    vipfts
        60
    vipfts  
       14 天前
    @Mephisto233 哈哈, 变身🥵
    Chad0000
        61
    Chad0000  
       14 天前 via iPhone
    低代码?
    k9982874
        62
    k9982874  
       14 天前
    建议废除后端,app 直读数据库
    zxc880301
        63
    zxc880301  
       14 天前
    @fov6363 靠谱 我们就是这么做的
    unco020511
        64
    unco020511  
       14 天前
    可以参考 firebase 的 remoteConfig 产品
    https://firebase.google.com/docs/remote-config

    几个关键点:
    1. 有本地默认配置文件,用于各种情况下的兜底配置
    2. 配置有分组,支持分组更新/获取
    3. 有版本号机制,支持增量更新,绝大部分情况都应该是增量差异更新
    4. 可选长链接,实现 real-time 更新机制
    5. 扩展可与各种其他产品结合,比如与你的业务 api 网关结合,在 header 中携带客户端配置的版本号,网关中去拦截,如果线上有版本号更新,则触发配置更新,配置更新在客户端可以独立进程,做到业务无感
    unco020511
        65
    unco020511  
       14 天前
    最关键的,就是动态配置是需要定期去固化清理的,比如一段时间去做一些 abtest,或者一些功能的临时开关,过了几个版本业务验证完之后一般是需要有明确数据结论去支撑,然后固化配置的.你现在配置数据有上千个,讲道理不太合理
    icyalala
        66
    icyalala  
       14 天前
    哈哈,FGO 游戏逻辑就是这样,一启动就要下载几十 MB 的 JSON 配置数据,后来嫌大就改成 pb/msgpack 了。
    lingalonely
        67
    lingalonely  
       14 天前
    游戏更新的时候不是有个加载过程吗,把这些配置传过来就行,没有必要请求上千次
    broken123
        68
    broken123  
       14 天前
    app 有个东西叫做启动器
    https://blog.csdn.net/jdsjlzx/article/details/129019317 道理都是通用的 每个端都可用 哦
    FreshOldMan
        69
    FreshOldMan  
       14 天前
    app 一进来是首页什么情况下需要上千个配置,这些配置不能在后端配置好再下发吗?
    yufeng0681
        70
    yufeng0681  
       14 天前
    @Mephisto233 #59 如果是这种需求,是不是资源包在本地,网上只要弄个配置,就能启用第 N 套资源当界面更好? 资源压缩后扩展名改成不可预知的,规避审核人员打开即可。
    gaobh
        71
    gaobh  
       14 天前 via iPhone
    不是应该进啥模块加载啥配置吗……
    winglight2016
        72
    winglight2016  
       14 天前
    这既是产品设计的缺陷,也是后端架构设计的缺陷,哪个 APP 需要一次性下载 1000 个配置项?再说了,有什么配置项非要在客户端才能起作用的?

    退一万步说吧,即使真的就要启动前加载好 1000 个配置项,也只需要 app 内建一套默认配置,等到用户修改了某项配置再做 diff-merge 操作就够了,我不信哪个用户上来就把 1000 个配置项全部自定义一遍。
    lambdaq
        73
    lambdaq  
       14 天前
    不要盲目优化啊。先说加多少钱。

    越屎的代码越值钱。
    wu00
        74
    wu00  
       14 天前
    某几个配置占了 50M ,剩下 99x 个配置占了几百 K ?
    yufeng0681
        75
    yufeng0681  
       14 天前
    所有配置项梳理分类
    1 、按加载重要性排序, 启动必需的,首页必需的,二级页面必需的
    2 、按更新频率分类:不更新的(放 app 里),不经常更新的(初始数据放 app 里),频繁更新的(只存网络, 这类配置要精简到极少个)
    3 、按功能分类:模块级数据同步,模块级配置接口,系统级配置接口,系统级数据同步 。 不要把所有数据用配置接口获得,可以换成数据同步,这样接口不涉及业务,只是数据同步。 服务端数据文件由各个模块自己负责生成,客户端也是由模块代码负责去获取数据文件。
    juzisang
        76
    juzisang  
       14 天前
    40-50M ,是把图片转 base64 放配置里了吗...要不然纯配置怎么可能这么大,还请求上千次...
    lefer
        77
    lefer  
       14 天前
    @onichandame #3 我觉得你的方案是可取的。
    cBlank
        78
    cBlank  
       14 天前
    参考游戏的启动流程
    xuanbg
        79
    xuanbg  
       14 天前
    这上千个达到 4-50M 之巨的所谓配置数据,不知道有几个是配置项,几个是模版数据,估计 99%其实都是模版数据吧,要不然怎么可能有几十 M 。。。。。

    办法很简单,配置项启动一次加载,模版数据完全可以按需加载。
    realJamespond
        80
    realJamespond  
       14 天前
    拼成一个 json 一次发过来
    icyalala
        81
    icyalala  
       14 天前
    给你们看看现实中几十 MB 配置项的例子:
    这是 FGO 手游每次启动下载的 JSON 配置数据,80M+,现在更大了所以不用 JSON 了
    https://github.com/UnderFGO/MasterDataDumper/releases
    28Sv0ngQfIE7Yloe
        82
    28Sv0ngQfIE7Yloe  
       14 天前
    @icyalala #81 这种一般是放在 OSS 获取吧
    FireKey
        83
    FireKey  
       14 天前
    应用的话配置 copy 一份存本地,配置版本变化时再更新对应项.如果运行中需要及时更新,考虑将配置版本加入 headers 中,版本更新了接口走更新流程
    panlatent
        84
    panlatent  
       14 天前   ❤️ 1
    纯色背景配上点大字:


    ”嗨,别来无恙“
    ”一切即将准备就绪“
    ”这可能需要几分钟“
    ”马上就好“
    ysw
        85
    ysw  
       14 天前
    json 放 cdn ,然后按需加载,应该就差不多了
    icyalala
        86
    icyalala  
       14 天前
    @Morii 这个配置数据变动还没那么频繁可以放静态,但用户数据游戏进度就不行了,那个同样也不小。
    如果不换架构的话,最简单的办法就是换格式,用 protobuf/msgpack 再压缩一下,客户端选个高性能的解析库,这个量级基本还是够用的。
    2owe
        87
    2owe  
       14 天前
    按需缓存吧,首先获取一下当前需要更新的配置,只获取有更新的部分
    veightz
        88
    veightz  
       14 天前
    问题还挺多, 不是单方面的。整体方案就挺奇怪的,感觉没有沟通好设计。。

    客户端的问题:
    1. 用户体验问题肯定要客户端解决。不可能同步等这份配置吧,这个数据量的下载,反序列化,都是不小的开销。一般来说是同步读客户端缓存,异步刷新数据。
    2. 配置同步做下版本管理, 记录下版本的上一次同步时间。 做好缓存时间控制。

    服务端问题:
    1. 上千个配置下是同构的吧? 一个读结构不同的配置项 key 吧? 要支持批量的接口。
    2. 服务端都做热缓存吧, 有内存缓存的话, 我觉得性能本身倒是还好。 但是目前方案我觉得你们的第一个瓶颈是带宽。
    3. 我觉得可以的方式是读 cdn , 配置大概率也不是高频更新的,可以结合 etag 等手段, 确定有数据变更了再回拉。
    xiangyuecn
        89
    xiangyuecn  
       14 天前
    能用上你们的 app 的客户也是倒了八辈子霉🐶
    Ritr
        90
    Ritr  
       14 天前
    什么 APP ,说出来我避雷
    shunia
        91
    shunia  
       14 天前
    游戏不就是这样的吗?
    一万个配置文件也可以做一个更新列表,有更新的才拉,没更新的用缓存。
    基本只有冷启动会全量下载,热启动基本很难遇到大量更新的情况。
    simo
        92
    simo  
       14 天前
    如果你说的 50M 的配置必须所有人都加载,那就分析下,拆分请求,按需,数据压缩,缓存,cdn 。
    murmurkerman
        93
    murmurkerman  
       14 天前 via iPhone
    这个明显要用增量更新,可以看看有没有类似于 remote config 的国内替代。没有的话只能自己撸一个。也可以借助 s3 ,oss 实现,s3 文件下载都会返回一个文件内容的 hash 值,可以用 head 请求判断是否更新了。然后就是拉配置的时候需要有一个请求队列,安卓 okhttp 自带,不用担心网络并发。

    配置下载也可以加一个分页接口,一次下载 n 项。
    最好还是用 protobuff 缩小配置文件传输大小。
    caqiko
        94
    caqiko  
       13 天前
    @panlatent #84 请坐和放宽,海内存知己,天涯若比邻
    prosgtsr
        95
    prosgtsr  
       13 天前 via iPhone
    放在一个接口全部请求回来。
    还可以带上版本号,每次通过版本号获取更新的数据。
    我们公司的 app 就是这么干的,没什么问题。
    jzphx
        96
    jzphx  
       13 天前
    启动一次 app 40-50M ,用户流量不要钱的吗
    duanxianze
        97
    duanxianze  
       13 天前
    不明白,什么样的应用会有这种需求?
    ArianX
        98
    ArianX  
       13 天前
    上千个配置为什么会有 40M
    Huelse
        99
    Huelse  
       13 天前
    区分启动配置和分页配置,另外很多配置都是应该存本地的,更改时发送一份到服务端记录就行了,不需要再次下载。
    p1gd0g
        100
    p1gd0g  
       13 天前
    配置不放 cdn 上?不做缓存?没有增量更新?
    1  2  
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   920 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 19:57 · PVG 03:57 · LAX 12:57 · JFK 15:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.