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

妹纸求方案点评:分布式下的导入进度条获取,限制同一数据表同一时间只能导入一次

  •  
  •   Breadykid · 114 天前 · 1381 次点击
    这是一个创建于 114 天前的主题,其中的信息可能已经有所发展或是发生改变。

    将将将~ 最近领了个需求,如题

    我的想法是: 每次导入用数据表生成唯一 tag,key=tag,value=导入进度,存入 redis,并开启导入线程进行 value=导入进度的更新,获取该导入操作的进度直接拿 key=tag 查找 redis 就行,导入完成后把 redis 里这条 key=tag 删掉。 其中,由于导入时间不可控,ttl 时间需要在更新 value=导入进度时同步更新。。。

    蓝吼,领导否定了这个想法,建议用 mysql 建一张表替代 redis 的操作,说是可以解决并发和服务突然挂掉问题。。。 同事建议用 zookeeper 来解决。。。

    我不晓得我的这个方案在微服务分布式下会产生神马问题哇?

    btw:spring cloud,mysql,redis

    25 回复  |  直到 2019-07-01 14:49:16 +08:00
        1
    AlloVince   114 天前
    为一个进度条建一张表…… #论系统里上千张表是从哪里来的#

    异步任务重要的应该是任务结果是否成功,进度条就算显示有偏差或者数据丢失对系统也不会有什么影响的吧
        2
    qq316107934   114 天前
    redis 不是比 mysql 更能解决并发么? mysql 读写效率没 redis 高。 如果 redis 并不是经常暴毙我个人觉得还是 redis 吧。就算挂掉了也不会有什么问题吧,大不了重新开始。
        3
    polebug   114 天前 via Android   ♥ 1
    歪个楼(楼主不是男生吗...
        4
    Cooky   114 天前 via Android
    MySQL 什么时候能比 Redis 更扛并发了?
    怕挂掉弄个主备不就得了
        5
    litujin1123   114 天前
    楼主不是男生吗...
        6
    ztmqg   114 天前
    v 站规矩: 女留微信男自强
        7
    des   114 天前 via Android
    能好好说话么?
        8
    dazkarieh   114 天前   ♥ 1
    >求手游坑!属性:男,本硕 211,软件工程,Android && iOS && C++

    女装👚大佬?
        9
    saulshao   114 天前
    首先,我要举报,楼主是个男生。
    其次,我觉得你的办法比较好,虽然我不懂 redis......为了这种事在数据库里建表,实际上就是我过去 10 年的干法。这不是什么好事,关键是很难把文档维持到跟代码甚至跟表保持一致......
        10
    tyrantZhao   114 天前
    是紧要数据吗,如果是不可丢失的那就存 mysql,否则还是放 redis 吧,mysql 的并发量支撑不住那么高的请求。
        11
    p2p   114 天前 via iPhone
    楼主其实是妹子的领导
        12
    luw2007   114 天前   ♥ 1
    问题:布式下的导入进度条获取,限制同一数据表同一时间只能导入一次,需要记录导入进度,解决并发和服务不稳定引发的问题

    解决:
    同一数据表同一时间只能导入一次。使用分布式锁就可以解决。
    服务不稳定,这块只要保证存储稳定就行( redis/mysql )

    领导的 mysql 方案,使用建表的方式来解决分布式锁的方式目前不太建议使用在高并发的后端服务。主要是性能太差。
    同事的 zookeeper 方案,使用 zk 来做分布式锁。这个方案本身没有问题。不过考虑 zk 的部署,业务代码编写并非很容易,建议可以用来扩展思路,尝试实现一个来提高个人技术水平。
    目前常规的做法都是使用 redis 加个锁,然后实时更新锁就行了。


    容错性低的方案一:
    1. 使用 SET NX 设置分布式锁。
    set table_name 0 EX 3600 NX

    table_name 表示表名
    0 表示进度为 0
    3600 表示到期时间。这里的到期时间需要根据业务自行调整,建议大于业务每批次的处理时间。最好等于业务表导入最小间隔。

    2. 如果抢不到锁表示其他业务正在处理导入,当前线程退出或者休眠后重试。
    3. 抢到锁的线程批量处理业务并实时更新进度
    set table_name N EX 3600 XX

    N 数字,表示当前进度

    4. 处理完之后,可以删除当前 key,或者设置到期时间为下次需要运行的时间。

    缺点:
    1. redis 分布式锁的方案虽然简单,但是并不安全。如果存储不稳定,暂时没有特别完善的方案。 关键词:” redis 分布式锁的安全性“

    2. 更新进度,直接按照 table_name 设置,可能出现当前线程卡住很长时间。这段时间中当前的锁过去后,别的线程重新设置锁。然后两个线程同时写一个 key,导致进度出现问题。

    可行性:
    由于没有足够的信息,无法确认方案是否满足业务需求。不过根据你领导的方案可以推断,上面这个方案在设置比较合理的到期时间之后应该问题不大。

    思考题:
    可以从 key 入手,设计一个容错性高的方案。
        13
    Breadykid   111 天前
    @AlloVince 个人是觉得用数据库有点重。。。所以想避免建表的操作
        14
    Breadykid   111 天前
    @qq316107934 我也觉得哇!但是他们提出了微服务挂掉,用 redis 如何解决这个问题的疑问
        15
    Breadykid   111 天前
    @polebug 妹纸!不够软的妹纸!
        16
    Breadykid   111 天前
    @Cooky 就是没钱搞主备,嘤嘤嘤。。。
        17
    Breadykid   111 天前
    @dazkarieh 那个是我蓝朋友哇
        18
    Breadykid   111 天前
    @saulshao 我真的是妹纸,嘤嘤嘤
        19
    Breadykid   111 天前
    @saulshao redis 就是非关系型数据库哇,可以看作一个超大 size 的 HashMap
        20
    Breadykid   111 天前
    @tyrantZhao 只是一个进度值的临时数据,其实用完就扔的,同感握爪
        21
    Breadykid   111 天前
    @p2p lz 明明是妹纸本冷!
        22
    Breadykid   111 天前
    @luw2007 少年的建议很细致哇~
    同事们目前对 redis 方案的疑问集中在,如果微服务挂掉,那这个进度的信息会在该 ttl 时间内一直存在,用户再次对这个数据表进行导入的话就没法导入(需求:同一数据表只能有一个导入任务)导致死锁,虽然 ttl 不设置-1 就总等得到 redis 内该信息删除的一天,但是这个死锁时间太长,用户体验很差。。。
    个人是觉得是不是在 redis 的 value 里存储一些进度更新的时间值之类的数据,来解决这个问题。。。
        23
    chimagun   111 天前
    怕不是女装大佬 tx
        24
    brust   111 天前
    @Breadykid #17
    有蓝朋友啊
    这问题我不会
        25
    luw2007   111 天前
    @Breadykid 大叔一个。
    看业务,按照你需要的业务时间设置超时时间, 比如抢锁多长时间,可以设置成具体需要的时间, 比如 1 分钟或者 5 分钟。
    这只是记录进度,如果需要保存进度信息。还需要存储到 mysql 中。
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   863 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 31ms · UTC 19:14 · PVG 03:14 · LAX 12:14 · JFK 15:14
    ♥ Do have faith in what you're doing.