我有一个应用程序,每秒在一个主机上生成5-10个新的数据库记录。
记录不需要任何检查。它们只需要记录在远程数据库中。
我正在使用Java作为客户端应用程序。
数据库位于服务器后面。
发送数据无法让应用等待。因此,可能将每条记录发送到远程服务器,至少是同步的,这样做并不好。
发送数据不得失败。我的应用程序不需要服务器的答案,但必须100%安全,它必须正确到达服务器(应该保证使用例如http url连接(TCP)......?)。
我想到了几个方法:
在单独的线程中运行发送数据代码。
仅将数据存储在内存中,并在计数后发送到数据库。
将数据存储在本地数据库中,并通过请求由服务器发送/提取。
所有这些都是有道理的,但我对此是一个菜鸟,也许有一些我缺少的标准方法,让事情变得更容易。不确定要走的路。
答案 0 :(得分:2)
您的要求不是很清楚。我的最佳答案是回答你的问题,并尝试逐点指出正确的方向。
您是否计划在客户端知道在没有发送回复的情况下收到数据?您应该始终计划在应用程序中编写异常处理,并处理由于某种原因客户端连接或其发送的数据被丢弃的情况。你所做的这两个陈述似乎彼此冲突;你不需要回复,但你需要知道数据到了吗?你的应用程序是否会使用水晶球来确认收到的数据(如果是这样,请发给我一个水晶球 - 我想用它来缩短股市)。
好的,所以听起来你想要非阻塞的I / O.但实际情况是,即使使用非阻塞I / O,实际发送数据仍需要一些时间。我的问题是,你为什么要求非阻塞和/或快速I / O?如果数据传输速度非常快,那么它是否也不会非阻塞真的很重要吗?这是您自己的设计决定,但是您的问题为什么需要这样做是不明确的,所以我只是把它扔到那里。
至于将数据放入内存并稍后发送,这不是非阻塞或多任务;那是在将来的某个时间推迟工作。我认为软件拖延。此方法不会减少您的应用程序为处理该数据而需要执行的时间或工作量,而只是将其放在将来某个日期。这对你没有任何好处,除非对#34;批处理有好处。数据发送到大块。
内存中的想法听起来像是一个临时缓冲区。许多I / O流实现都将内置缓冲区,网卡上的缓冲区以及路由器上的缓冲区等等。在代码中添加另一个缓冲区并不会从表面上看似乎没有任何意义,除非你能证明为什么你认为这会有所帮助。也就是说,你试图通过引入一个缓冲区来解决实际的,经验丰富的问题?此外,根据您发送此数据的方式(即您选择的网络I / O类),您可能会将非阻塞I / O作为类实现的一部分包含在内。
接下来,至于在单独的线程上发送数据,如果你需要非阻塞I / O,这很好,但是(1)你需要证明为什么这是一个好主意。在你走这条路之前你的软件设计,因为它会增加你的应用程序的复杂性,所以除非它解决了一个特定的,真正的问题(即你的应用程序中有一个不应该被冻结/无响应的用户界面等待I / O操作),然后它只是增加了复杂性,你不会从中获得任何额外的性能。 (2)使用线程的常见诱惑是,基本上拖延工作。将工作放到另一个线程上并不会减少需要完成的工作总量,或者应用程序为完成其功能而消耗的I / O总量 - 它只是将其放在另一个线程上。有时候这是非常有益的,也许这对你的应用来说是正确的决定,但从你的描述中我看到了许多要求的功能,但没有理由(或者你的问题的解释)试图解决备份这些功能/设计选择,这应该最终推动你选择的方向。
最后,只要拥有服务器" pull"它不是被推送到服务器,而是你在这里做的就是翻转角色,让服务器充当客户端,客户端充当服务器。意识到"客户"和"服务器"是相对术语,服务器是提供服务的东西。简单地转换角色并不能真正改变任何东西 - 它只是将客户端/服务器角色从软件的一部分转移到另一部分。标签本身就是 - 标签 - 一种方便的方式来了解哪一块提供服务,哪一块消耗服务(客户端)。
这不应该是一个问题。任何体面的数据库服务器都会将此类工作视为极低负载。服务器速度/响应速度方面的更大问题将是网络延迟(假设您通过网络传输此数据)以及与您的I / O选择有关的其他因素,这些因素将影响您是否可以写入每秒5-10条记录 - 即您的整体吞吐量。
答案 1 :(得分:2)
规范,如果不幸的是企业,对此的回答是使用持久的消息队列。您的应用程序会将消息发送到队列,后端应用程序将接收并将它们存储在数据库中。一旦队列接受了一条消息,即使发送方,接收方或队列代理本身崩溃,它也能保证接收方可以使用它。
在我的机器上,使用HornetQ,构造并向持久队列发送短文本消息需要约1 ms。这非常快,您可以在处理Web请求时执行此操作,而不会添加任何明显的额外延迟。任何好的消息队列都将支持每秒10条消息的吞吐量。 HornetQ已被标记为处理8.2 million messages per second。
我应该补充说,消息队列并不难设置和使用。我下载了HornetQ,并在几分钟内启动并运行。创建队列(使用本机HornetQ API)以及发送和接收消息(使用JMS API)所需的代码是less than a hundred lines。
答案 2 :(得分:1)
如果您将数据排队并将其发送到一个帖子中,那么如果您的费率是每秒5-10并且只有一个客户端则应该没问题。如果您有多个客户端,那么数据库插入开始变慢,您可能会遇到问题;鉴于您的要求“发送数据一定不能失败”。这是一个更加困难的要求,特别是在机器或网络故障面前。
请考虑以下情形。您拥有的客户端数量超出了数据库的有效处理能力,您的一个用户就是快速打字员。插入内容开始在应用程序中备份到内存中。他们完成工作并在最后一个实际上传到数据库之前将其关闭。或者,机器在发送数据之前崩溃 - 或者在发送数据时崩溃;或者更糟糕的是,数据库在发送时崩溃,并且由于网络问题,客户端无法确定其事务尚未完成。
避免这些问题(无论如何大多数问题)的简单方法是让用户等到数据提交到某个地方,然后才允许它们继续。如果您可以使数据库插入足够快,那么您可以坚持使用更简单的方案。如果没有,那么你必须更有创意。
例如,您可以在用户点击提交时将数据本地写入磁盘,然后从另一个线程上传。这个场景需要足够聪明,以标记发送时保留的内容(删除它会起作用);并且能够在启动时重新扫描并查找要发送的未发送工作。它还需要能够在网络或集中式服务器故障的情况下继续尝试。
还需要一种方法让服务器端检测重复项。因为客户端机器可以在将数据标记为已发送之前发送数据并崩溃;然后重新启动它会再次发送它。如果网络连接不良,可能会出现相同的情况。客户端可以发送它,永远不会收到服务器的确认;超时,然后最终重试。
答案 3 :(得分:0)
如果您不希望客户端应用程序阻止,则是,您需要从其他线程发送数据。
一旦你完成了,那么唯一重要的是你是否能够将记录发送到数据库至少与生成它们一样快。我开始让它一个接一个地发送它们,然后如果这还不够,将它们放入内存中的队列并批量更新。很难说更多,因为你没有告诉我们什么决定了生成记录的速度。
你没有说你是怎么写数据库的...... JDBC? ORM喜欢Hibernate?但原则是一样的。