[英]Haskell database connections
请查看这个scotty应用程序(它直接取自2014年的这个旧答案 ):
import Web.Scotty
import Database.MongoDB
import qualified Data.Text.Lazy as T
import Control.Monad.IO.Class
runQuery :: Pipe -> Query -> IO [Document]
runQuery pipe query = access pipe master "nutrition" (find query >>= rest)
main = do
pipe <- connect $ host "127.0.0.1"
scotty 3000 $ do
get "/" $ do
res <- liftIO $ runQuery pipe (select [] "stock_foods")
text $ T.pack $ show res
您将看到如何在启动Web应用程序时仅一次创建数据库连接( pipe
)。 随后,成千上万(如果不是数百万)的访问者将同时点击“ /”路由,并使用相同的连接( pipe
)从数据库中读取数据。
我对如何正确使用Database.MongoDB
有疑问:
以下是连接池为您带来的好处:
如果达到池连接限制,则将等待下一个可用连接,并且不会出现运行时错误。 因此,您的应用将稍等片刻,而不是拒绝您的客户端。
池将为您重新建立连接。 您可以配置池以关闭过多的连接,并根据需要创建更多的连接,直到达到特定限制。 如果您在读取或写入连接时断开连接,则只需从池中建立另一个连接。 如果您不将断开的连接返回到池中,池将为您创建另一个连接。
如果数据库连接已关闭,则:此连接上的mongodb监听器将退出,并在终端上显示一条错误消息,您的应用将收到IO错误。 为了处理此错误,您将需要创建另一个连接,然后重试。 在处理这种情况时,您了解使用数据库池更容易。 因为最终您对此的解决方案将非常类似于连接池。
作为连接的一部分,我只进行一次身份验证。 如果以后需要认证其他用户,可以随时进行。
是的,mongodb可以同时使用,但是就像我说的那样,它只写一个管道,很快就成为瓶颈。 如果您创建的连接数至少等于mongodb服务器所能负担的用于处理它们的线程数(CPU数),则它们将全速运行。
如果我错过了任何事情,请随时澄清。 谢谢你的问题。
您真正想要的是一个数据库连接池。 看一下另一个答案中的代码。
如果您的MongoDB服务器处于安全模式,则可以使用withMongoDBPool
代替auth
。
这是设置事情的正确方法吗? 相对于每次访问“ /”都创建数据库连接。 在后一种情况下,我们可以一次拥有数百万个连接。 灰心吗? 这种方法的优缺点是什么?
您不想打开一个连接然后再使用它。 支持Scotty的HTTP服务器称为Warp。 Warp具有多核,多绿线设计 。 允许您在所有线程之间共享相同的连接,因为Database.MongoDB
直截了当地说连接是线程安全的,但是将发生的事情是,当一个线程被阻塞以等待响应时( MongoDB协议遵循简单的请求-响应设计 ),您的Web服务中的所有线程都会阻塞。 这是不幸的。
相反,我们可以在每个请求上创建一个连接。 这琐碎地解决了一个线程阻塞另一个线程的问题,但导致了自己的问题。 建立TCP连接的开销虽然不大,但也不为零。 回想一下,每次我们想要打开或关闭套接字时,我们都必须从用户跳到内核,等待内核更新其内部数据结构,然后跳回(上下文切换)。 我们还必须处理TCP握手和告别。 在高负载下,我们还将耗尽文件描述符或内存。
如果我们之间有解决方案,那就太好了。 解决方案应该是
资源池解决的正是这个问题。
有人说我应该使用一个池(Data.Pool)。 看起来这只会帮助限制同时使用同一数据库连接的访问者数量。 但是我为什么要这样做呢? MongoDB连接是否没有对同时使用的内置支持?
目前尚不清楚同时使用是什么意思。 我可以猜测一种解释:您的意思是类似HTTP / 2的东西,该协议已内置流水线。
流水线的标准图片http://research.worksap.com/wp-content/uploads/2015/08/pipeline.png
在上方,我们看到客户端向服务器发出多个请求,而无需等待响应,然后客户端可以按一定顺序接收响应。 (时间从上到下流动。)此MongoDB没有。 这是一个相当复杂的协议设计,没有比仅要求您的客户端使用连接池好多少了。 而且MongoDB并不孤单:Postgres,MySQL,SQL Server和大多数其他数据库都采用了简单的请求和响应设计。
并且:的确,连接池限制了在阻止所有线程并且用户仅看到加载栏之前可以作为Web服务承担的负载。 但是,在三种情况下(连接池,一个共享连接,每个请求一个连接),都会存在此问题! 计算机具有有限的资源,在某些情况下,某些东西会在足够的负载下崩溃。 连接池的优点是可以正常扩展直到无法扩展为止。 处理更多流量的正确解决方案是增加计算机数量。 我们不应该仅仅因为这个问题就避免合并。
在上面的应用程序中,如果由于某种原因数据库连接丢失并且需要重新创建该怎么办? 您将如何恢复呢?
我认为,这些假设分析超出了Stack Overflow的范围,没有比“尝试一下然后看”更好的答案了。 Buuuuuuut假设服务器终止了连接,我可以对可能发生的情况take之以鼻:假设Warp为每个请求派生一个绿色线程(我认为确实如此),则每个线程在尝试写入时都会遇到未经检查的IOException
TCP连接已关闭。 Warp会捕获此异常并将其用作HTTP 500,希望也可以为日志编写一些有用的东西。 假设像现在这样的单连接模型,您可以在“重新启动” main
功能并建立第二个连接的地方做一些聪明的事情(但是代码行很多)。 我为爱好项目所做的事情:万一发生异常情况(例如断开连接),我请主管进程(如systemd)观看日志并重新启动Web服务。 虽然显然不是一个生产,赚钱的网站的好解决方案,但它对于小型应用程序已经足够好了。
使用
auth
函数进行身份auth
怎么办? 应该仅在创建管道之后才将auth
函数调用一次,还是在每次命中“ /”时都调用auth
函数?
创建连接后应调用一次。 MongoDB身份验证是按连接的。 您可以在此处看到db.auth()
命令如何db.auth()
与当前客户端连接相对应的MongoDB服务器的数据结构的示例 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.