每当节点服务器上的数据发生变化时编写整个 SQL 表(很奇怪,请耐心等待)

Posted

技术标签:

【中文标题】每当节点服务器上的数据发生变化时编写整个 SQL 表(很奇怪,请耐心等待)【英文标题】:Writing entire SQL table whenever data changes on a Node server (weird one, so bear with me) 【发布时间】:2016-07-07 18:24:16 【问题描述】:

好的,首先让我说我知道这很奇怪。我愿意。

但是这里有:

假设我有一个存储数据的 SQL 数据库。假设我在这方面别无选择,它必须是 SQL。我正在构建的应用程序的数据库中有大约 100,000 条记录,一旦应用程序的用户处理了每条记录,它们就会全部关闭并完全发送到不同的应用程序。所以在短时间内,这个应用程序将被使用,然后停止使用,直到明年同一时间。在使用应用程序时,根本不会有任何外部资源访问数据库。

当(Node)服务器启动时,它会将数据库中的所有内容加载到服务器上的对象字面量中。

这个应用程序的客户端,在一个非常基本的层面上,发出请求(向服务器上的 API)获取数据,并在处理完记录后将更新版本的记录发送回服务器。

这就是奇怪的地方:假设我不希望客户端应用程序必须直接从数据库中检索记录,也不希望它能够写入它们。所以整个数据库的数据已经存在于服务器的内存中。服务器上有一个模块已经可以处理更改该数据的表示形式(同样,因为客户端应用程序只与服务器上的 API 交互,所以存在数据库模块来促进这一点)。

多个用户同时访问系统,但由于系统的工作方式,不可能向两个用户发送相同的记录,因此两个用户永远不会为相同的记录发送更新(记录单独处理,并按顺序处理)。

所以,假设我决定,因为我已经在服务器的内存中管理所有这些数据,所以我每次都将当前数据的更新版本完整地发送回数据库它改变了。

问题是,这在疯狂的规模上排名第几?

写入整个数据库而不是单个记录的性能显然会受到影响。但是,在一个从一次读取的数据库中(在应用程序启动时),这甚至是一个问题吗?如果除了“当任何东西发生变化时写入所有东西”之外的所有操作都发生在服务器的内存中,那么这些更新实际需要多长时间是否重要?如果在更新数据库的同时对数据库进行了新的更新,那么 SQL 肯定会处理这个问题吗?

感觉这样做的正确方法当然是让每个用户直接从数据库中获取他们的信息,并直接对数据库进行更新(或至少与 API 交互实现这一点的端点),但是,只是......不这样做,完全疯了?

就像我说的,我知道这很奇怪,但除了“感觉有点不对劲”这一事实之外,我不确定我是否确信这实际上是完全错误的。所以我想这个地方会有意见。

我认为目前的工作方式是:

只要在 in-memory DB 上发生更改,就会更新[SQL DB] in-memory DB 根据对服务器的 API 调用以各种方式更新 发出数据请求,并发送数据更新,这两者都在内存数据库中处理

来自应用程序的多个请求可以同时发生,但多个用户看不到相同的记录,因为记录在发送之前已分配给给定用户

多个更新可以来自多个用户,每个更新最终都以将整个 SQL 数据库与内存数据库的内容一起保存到其中而结束。

(注意:我不是说“这是最好的方法吗?”除非需要重新启动服务器,否则会再次读取)

【问题讨论】:

我看到的问题是并发:假设重写数据库需要5分钟。您必须使 api 处理程序异步以防止客户端 Web 浏览器超时 - 真的没问题。但是当 Bob 提交他的更改,然后在 1 分钟后 Sally 提交更改时会发生什么? Bob 的请求仍在忙于写入(如您所说的整个数据集),而 Sally 的请求也想做同样的事情?您必须阻止(长超时 + 事务锁定或使用布尔值和 setTimeout 的廉价 n-nasty)以防止数据不一致。 如果您确实正确锁定了所有内容,假设仍然有 5 分钟的保存时间,那么您显然希望平均每 5 分钟窗口不会收到超过 1 个请求,但是关闭您的服务或数据库需要很长时间。此外,在锁定并等待推送整个数据库时,您可能会丢失用户更改 - 因为更改仅在内存中:如果 api 服务终止 - 更改将丢失。 我对你的建议有点迷茫,但听起来你说你有一个中间件服务器正在将整个 SQL 数据库加载到内存中。客户端用户正在更新/通信中间件。现在您想知道是要通过中间件增量更新 SQL,还是总是将整个数据集发送回 sql。我想以后会有什么好处?您不必进行更改跟踪吗?您肯定会对您的网络骨干网/硬件、SQL 服务器产生更大的性能影响...... 批量数据库写入可能会生成大量日志,具体取决于它们的实现方式。归档日志文件基本上是写入数据库的每条记录的寄存器。因此,您可以从备份中恢复数据库,然后将其前滚(使用日志)到现在。我真的看不出这个设计有什么好处。理论上,您可以将保存到 USB 驱动器的文件缓存在内存中,然后每 10 分钟将它们写入驱动器。不过,这不是一个很好的设计决策。 哈,谢谢您的意见 - 不要误会我的意思,我并不是说这是一个的想法,而是要全面了解它的原因一个坏主意。这并不是一个真正的“设计决策”,它只是事情的最终结果,因为“模拟”数据库只是一个 JSON 文件,所以在服务的初始构建。然后我只是想“如果我让它像这样工作怎么办?”,并认为我会就这个主题进行投票。 【参考方案1】:

在这种情况下,我认为我会做的是为每个缓存记录添加一个属性,以指示该记录是“脏的”。换句话说,自从它最初是从数据库中读取的以来,有人对它做了什么。

(您还可以添加一个属性来指示某人“已将这条特定记录‘签出’”,这样您就可以确定两个用户在同一时间。)

在某个方便的时候,您可以遍历集合,将“脏”记录发布回数据库。使用 SQL 事务,不仅是为了提高效率,也是为了确保对数据库的最终更新是原子的。

您需要非常注意竞争条件的可能性。一种可能的策略是使用 Unix 时间戳作为“脏”指标。只有当一条记录的“脏时间”大于或等于上次运行提交过程时的时间戳时,才会选择一条记录发布到数据库。

(并且,P.S.:“不,在我从事这个疯狂行业的所有疯狂岁月中,我见过比这更“奇怪”的事情......)

【讨论】:

谢谢你 - 我已经有一个属性记录谁签出了每条记录,所以它的那一面已经到位。但是,是的,我可以看到您关于定期更新最新的“肮脏”记录的建议比我公认的骑士“一直都在做所有该死的事情”的方法更明智。 :D 再说一次,我不认为这是一个 的想法,我只是想澄清一下它有多少是一个 的想法。得知我在数据库方面没有几十年的经验,您可能会有些惊讶。 :D 非常感谢。 :) Meh... “谁做的?我们都只是真的很擅长假装它!” ;-) 是的,完全替换“一个非常糟糕的主意。” 现在,另一个的想法,你可能希望渗透到颅骨的灰细胞中,是这样的:而不是将“整个该死的数据库”加载到程序启动时的内存,而是按需检索记录。从 empty 哈希开始。每次用户请求一个尚未在内存中的记录时,就去获取它,并将其添加到哈希中。 您可能想思考“将整个事情记入记忆”策略是否是,今天,“不再需要另一个时间的必要性。” “今天的硬件”在“当时”是一个不可能实现的梦想。 (是的,我在那儿...)(koff,koff ...) ... 但话又说回来,如果 (正如您在上一篇文章的评论中所说) “它曾经是一个 JSON 文件...” (它实际上有效 ...) 哎呀,你也许仍然能够摆脱那个策略!

以上是关于每当节点服务器上的数据发生变化时编写整个 SQL 表(很奇怪,请耐心等待)的主要内容,如果未能解决你的问题,请参考以下文章

SQL 索引视图:如果数据发生变化会发生啥

京东云数据库RDS SQL Server高可用概述

当 sql server 数据库中的数据发生变化时,从一个 android 应用程序向另一个应用程序发送推送通知

每当firebase发生任何变化时,自动向所有用户发送通知[关闭]

当您的数据库架构发生变化时处理旧版本移动应用程序的正确方法

Watcher