从系统设计/可扩展性的角度来看,在处理需要大量写入数据库中特定表的系统时,有哪些行业标准策略。
为简单起见,假设该表是产品的库存表,并且具有“产品名称”列和“计数”列,并且每次将新产品购买到产品中时,该表就简单地增加+1系统。而且每2秒钟有数百万用户购买不同的产品,我们必须跟踪每种产品的最新数量,但是不必严格实时,也许5分钟的延迟是可以接受的。
我的选择是:
1)主从复制,其中主数据库处理所有写操作,而从数据库处理读操作。但这并不能解决大量写入的问题
2)根据产品名称范围或其哈希值对数据库进行分片。但是,如果有特定产品(例如Apple)在短时间内收到大量更新该怎么办,它仍然会到达同一数据库。
3)批量更新?使用某种缓存并每X秒钟写入表一次,累积计数是否等于这X秒钟我们收到的所有计数?那是一个有效的选项,我使用什么缓存机制?如果最后一次读取和下一次写入之间发生崩溃怎么办?如何恢复丢失的计数?
4)我忘记了其他明显的选择吗?
任何见识都受到赞赏!
答案 0 :(得分:4)
我要说的是,解决方案将高度取决于您真正需要做的事情。每秒写入数千条记录的解决方案可能与您提供的示例中增加 counter 的方式大不相同。更重要的是,根本没有tables
可以处理这种负载。您的问题中也缺少Consistency
/ availability
的要求,并且根据它们的要求,整个体系结构可能会非常不同。
无论如何,回到您的简单案例和选项
您将在这里遇到的问题是数据库locking
-每个增量都将需要一个记录锁,以避免出现竞争情况,并且您将迅速使写入队列的进程在队列中等待并且系统崩溃。即使在中等负载下)
您的假设是正确的,与第1页相差无几
非常接近。轻量级存储提供的缓存层提供并发的 atomic 增量/减量和持久性,不会丢失数据。我们已经将redis
用于类似的目的,尽管其他key-value database也可以使用-实际上有数十个这样的数据库。
键值数据库或键值存储是一种数据存储范例 设计用于存储,检索和管理关联数组 如今通常称为字典或哈希表的数据结构
解决方案如下:
incoming requests → your backend server -> kv_storage (atomic increment(product_id))
然后您将运行一个“冲洗”脚本,即*/5
,它执行以下操作(简化):
product_id
中读取其当前的value
+= value
)value
答案 1 :(得分:0)
您问了一个典型的CQRS问题。 “ CQRS”代表命令查询责任隔离。听起来就是这样-您正在将写入(命令)与读取(查询)分开。当您在读写之间有不同的需求时,这种方法可以解决问题-正是您的情况。
要以可扩展的方式实现此目的,您需要确认(即接受)一个增加请求,并将其排队等待处理。并让每个请求的读取实时进行。使用背景命令处理程序处理排队的请求,该命令处理程序知道如何协调。也就是说,如果失败,它应该知道如何解决冲突(例如,如果其他人更新了该行,则检索了较新的版本,然后重试)。
我完全不同意另一个答案,有人建议排队会降低整个系统的性能。排队不会降低任何性能,因为它是排队而不是实时处理。这就是扩展的重点。相反,实时更改(即使这意味着仅更改内存缓存中的布尔标志)比排队要糟糕得多。试想一下,如果在那一刻内存不足的缓存关闭,将会发生什么。异步脱机(后台)处理可确保此类问题不会阻止命令最终被处理。 但是,您可能需要缓慢处理排队的命令(无论它能处理多少步速而不会影响读取),或者在单独的数据副本中处理。
您可以使用像其他人建议的那样的特定技术,例如内存缓存,但这又是CQRS范例的另一种实现。它可以是缓存,也可以是记录或数据库的另一个副本。同样的东西,同样的效果。