代码之家  ›  专栏  ›  技术社区  ›  user1008636

系统设计:处理数据库重写的策略

  •  7
  • user1008636  · 技术社区  · 7 年前

    从系统设计/可伸缩性的角度来看,在处理需要大量写入数据库中特定表的系统时,有哪些行业标准策略。

    为简单起见,假设该表是产品的库存表,有一列“Product Name”和一列“Count”,每次在系统中购买一个新产品时,该表只增加+1。每2秒钟就有数百万用户购买不同的产品,我们必须跟踪每种产品的最新计数,但它不必严格实时,也许5分钟的延迟是可以接受的。

    2) 基于产品名称范围或其哈希值对数据库进行分片。但是,如果有一个特定的产品(如苹果)在短时间内收到大量的更新,它仍然会击中相同的数据库。

    3) 批量更新?使用某种缓存,每X秒写入一次表,并对X秒内接收到的内容进行累计计数?这是一个有效的选项吗?我使用什么缓存机制?如果上一次读和下一次写之间发生了崩溃怎么办?我如何找回丢失的计数?

    4) 还有什么明显的选择我忘了吗?

    2 回复  |  直到 7 年前
        1
  •  10
  •   Oleg Kuralenko    7 年前

    我认为解决方案将高度依赖于你到底需要做什么。一个解决方案,写成千上万 每秒可能与增加 柜台 tables 根本无法承受这样的负担。 Consistency / availability

    不管怎样,回到你具体的简单案例和你的选择

    选项1(主从复制)

    你在这里要面对的问题是数据库 locking -每一个增量都需要一个记录锁来避免争用情况,您将很快让进程写入在队列中等待的db,从而关闭系统。即使在中等负荷下)

    选项2(分频)

    选项3(批量更新)

    非常接近。一种由轻量级存储器提供的缓存层,它提供并发的 原子的 不要丢失你的数据。我们曾经 redis 为了类似的目的 key-value database 当然也可以——实际上有很多这样的数据库。

    键值数据库或键值存储是一种数据存储范式 设计用于存储、检索和管理关联数组的 数据结构今天更常见的称为字典或哈希表

    解决方案如下:

    incoming requests → your backend server -> kv_storage (atomic increment(product_id))
    

    */5

    1. product_id 在里面 读取其当前值 value
    2. 更新数据库计数器( += value )
    3. 价值 千伏储存

    进一步扩展

    • 如果脚本失败,那么不会发生任何不好的事情-更新将在下次运行时到达
    • 如果一个单一的键值db不能处理负载—大多数都支持在多个框上扩展,或者在后端脚本中使用一个简单的分片策略就可以了
    • 如果一个“刷新”脚本跟不上增量,您可以将它们缩放到多个框,并决定每个框处理的键范围
        2
  •  2
  •   Tengiz    7 年前

    你问了一个典型的 CQRS 问题。”CQRS”代表命令查询职责分离。这就是它听起来的样子——你把写(命令)和读(查询)分开了。这种方法解决了当您在写操作和读操作之间有不同需求时的问题—这正是您的情况。

    承认 (即。, )对增量的请求,并将其排队等待处理。并让读取按请求实时工作。使用 命令处理程序知道 . i、 例如,如果失败,它应该知道如何解决冲突(例如,如果其他人更新了行,则检索更新的版本并重试)。

    我完全不同意另一个答案,有人说排队会使整个系统瘫痪。排队并没有让任何事情停止,因为它是排队而不是实时处理。这就是缩放的重点。相反,实时更改,即使这意味着只更改内存缓存中的布尔标志,也比排队要糟糕得多。试想一下,如果内存中的缓存在那一刻关闭了,会发生什么。异步脱机(后台)处理可确保此类问题不会阻止最终处理命令。 但是,您可能需要缓慢地处理排队的命令(不管它能以何种速度处理而不影响读取),或者在单独的数据副本中处理。