高并发场景下需要实现一个被频繁查询,读多写少的键值对(需要用键查询对应的值 & 知道前面还有多少个键值对是先于他创建且没有被删除的 ,所以数据结构需要是有序的),只需要先入先出(不需要从中间删元素),应该用什么比较好? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
SeleiXi
V2EX    程序员

高并发场景下需要实现一个被频繁查询,读多写少的键值对(需要用键查询对应的值 & 知道前面还有多少个键值对是先于他创建且没有被删除的 ,所以数据结构需要是有序的),只需要先入先出(不需要从中间删元素),应该用什么比较好?

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

    目前想到的方案

    1. Redis List ,每个 element 对应一个 Hash Map
    2. 一个用 sync.RWMutex 实现共享锁的队列,每个 element 储存一个 Hash Map

    但这两个还是得用 O(n)的时间复杂度去遍历,才能知道前面有多少个元素

    []{ {"12345": true}, {"23561": false}, {"23562": false}, } 

    补充:业务场景储存的键本来就是有序的,且与创建时间相关。而值是一个 bool 值。感觉性能优化的难点还是在需要知道前面还有多少个键值对是先于他创建且没有被删除的,Redis List 的索引不会动态更新,因此没法在前面有成员被删除后知道前面实际还有多少个成员

    12 条回复    2025-01-25 02:01:34 +08:00
    sagaxu
        1
    sagaxu  
       342 天前
    最差情况也就是内存里建 2 个索引,一个是 key 的,一个是时间的,读写都是 O(logN)
    quickfox
        2
    quickfox  
       342 天前
    用 Hash 和 Sorted Set ,Hash 存 key 和 bool 值,再用 redis 的 soted list ,存 key ,时间作为分值,
    添加:zadd zset_key "12345" {时间戳} 和 hset hash_key "12345" true
    取第一个 key:zrange zset_key 0 0
    删除指定的 key:zrem "12345" 和 hdel hash_key "12345"
    sagaxu
        3
    sagaxu  
       342 天前
    如果严格先入先出,可以设置一个自增 ID ,记录当前元素是第几个插入,再记录上一次取出的元素的 id ,相减就能算出前面有多少个元素
    lesismal
        4
    lesismal  
       342 天前   1
    zset 足够了, timestamp 做 score, 没必要用其他的, 别想多了

    > 要用键查询对应的值 & 知道前面还有多少个键值对是先于他创建且没有被删除的

    zrank 查询对应的值的时候就会返回这个值的排序下标(整个 zset 排序下标从 0 开始), 默认 timestamp 升序, zrank 返回的值减 1 就知道前面有多少个是先于它了.
    你保证每组操作原子性, 比如单次如果需要多个操作就 pipeline, 这样就能保证你每组操作在 redis 里是串行执行的, 所以你当前能查到的所有结果肯定就是对应的存在的未被删除的数据集的

    > 所以数据结构需要是有序的),只需要先入先出(不需要从中间删元素)

    zset 就是按 score 排序的, 你只要自己处理每次先删除第一个就行了
    SeleiXi
        5
    SeleiXi  
    OP
       342 天前
    @lesismal !这个就是我想要的解法,一开始就是想这个方案想了好久,但是思考的时候默认把 score 和索引强绑定了,然后因为 score 不会动态更新所以就想着用其他方案了,感谢大佬
    lesismal
        6
    lesismal  
       342 天前
    > 然后因为 score 不会动态更新所以就想着用其他方案了

    @SeleiXi 更新用 pipeline zrem+zad, 先删再重新添加, 就可以了
    SeleiXi
        7
    SeleiXi  
    OP
       341 天前
    @lesismal 不是这个问题 qwq 主要还是一开始不知道为啥想把 score 当成索引,但第一个一删那后面的索引全都得手动-1 了,忘了 zrank 能返回一个动态更新的 index
    lesismal
        8
    lesismal  
       341 天前
    @SeleiXi #7 嗯嗯, 那就完全没问题了
    ifplusor
        9
    ifplusor  
       341 天前 via iPhone
    只用 zset 查不了 value 吧
    ifplusor
        10
    ifplusor  
       341 天前 via iPhone
    @ifplusor 又看了一下,value 是 bool 值,可以直接在时间戳后面加一位塞进去。
    wei2629
        11
    wei2629  
       341 天前
    先入先出 不是个栈结构? []value 做栈 m[name]int 做索引 。 int 前面就是 有多少个。
    kytrun
        12
    kytrun  
       340 天前 via Android
    精妙!
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2049 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 16:09 PVG 00:09 LAX 08:09 JFK 11:09
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86