Mongodb Haskell数据库连接

Mongodb Haskell数据库连接,mongodb,haskell,scotty,Mongodb,Haskell,Scotty,请查看此scotty应用程序(直接取自): 导入Web.Scotty 导入数据库.MongoDB 将限定的Data.Text.Lazy作为T导入 导入控制.Monad.IO.Class 运行查询::管道->查询->IO[文档] runQuery管道查询=访问管道主控“营养”(查找查询>>=rest) main=do 管道您真正想要的是一个数据库连接池。请看下面的代码 如果您的MongoDB服务器处于安全模式,则可以将与MongoDB工具一起使用,而不是auth 这是正确的安排方式吗?而不是为每次

请查看此scotty应用程序(直接取自):

导入Web.Scotty
导入数据库.MongoDB
将限定的Data.Text.Lazy作为T导入
导入控制.Monad.IO.Class
运行查询::管道->查询->IO[文档]
runQuery管道查询=访问管道主控“营养”(查找查询>>=rest)
main=do

管道您真正想要的是一个数据库连接池。请看下面的代码

如果您的MongoDB服务器处于安全模式,则可以将
与MongoDB工具一起使用,而不是
auth

这是正确的安排方式吗?而不是为每次访问“/”创建数据库连接。在后一种情况下,我们可以同时拥有数百万个连接。这是否令人沮丧?这种方法的优点和缺点是什么

您不想打开一个连接然后使用它。您正在使用的HTTP服务器是Scotty的基础,它被称为Warp。翘曲有一个新的方向。您可以在所有线程之间共享相同的连接,因为
数据库。MongoDB
明确表示连接是线程安全的,但会发生的情况是,当一个线程被阻止等待响应()时,web服务中的所有线程都将被阻止。这是不幸的

我们可以根据每个请求创建一个连接。这很容易解决一个线程阻塞另一个线程的问题,但也会导致它自己的问题。建立TCP连接的开销虽然不是很大,但也不是零。回想一下,每当我们想要打开或关闭套接字时,我们必须从用户跳转到内核,等待内核更新其内部数据结构,然后跳回(上下文切换)。我们还必须处理TCP握手和道别。在高负载下,我们也会耗尽文件描述符或内存

如果我们能在两者之间找到解决方案,那就太好了。解决办法应该是

  • 线程安全
  • 让我们最大限度地限制连接数,这样就不会耗尽操作系统的有限资源
  • 快的
  • 在正常负载下跨线程共享连接
  • 在负载增加时创建新连接
  • 允许我们在减少负载的情况下删除连接时清理资源(如关闭句柄)
  • 希望已经被其他生产系统编写和测试过
正是这个问题解决了

有人说我应该使用一个池(Data.pool)。看起来这只会帮助限制同时使用同一数据库连接的访问者数量。但我为什么要这么做?MongoDB连接不是内置了对同时使用的支持吗

不清楚你所说的同时使用是什么意思。我可以猜测有一种解释:你指的是HTTP/2之类的东西,它在协议中内置了管道

上面我们看到客户机向服务器发出多个请求,而不等待响应,然后客户机可以按一定顺序接收响应。(时间从上到下流动。)此MongoDB没有。这是一个相当复杂的协议设计,并不比只要求客户机使用连接池好多少。MongoDB并不是这里唯一的一个:简单的请求和响应设计是Postgres、MySQL、SQL Server和大多数其他数据库已经解决的问题

而且:连接池确实限制了您作为web服务可以承受的负载,直到所有线程都被阻止,并且您的用户只看到一个加载条。但是这个问题在三种场景中的任何一种(连接池、一个共享连接、每个请求一个连接)都会存在!计算机的资源是有限的,在某一点上,某些东西会在足够的负载下崩溃。连接池的优点是,它可以很好地扩展,直到无法扩展为止。处理更多流量的正确方法是增加计算机数量;我们不应该仅仅因为这个问题就避免合并

在上面的应用程序中,如果数据库连接因某种原因丢失,需要重新创建,会发生什么情况?你将如何从中恢复

我相信这类假设超出了堆栈溢出的范围,没有比“试试看”更好的答案了。Buuuuuuuuu假设服务器终止连接,我可以尝试一下可能发生的情况:假设Warp为每个请求分叉一个绿色线程(我认为它是这样的),当每个线程试图写入关闭的TCP连接时,都会遇到未经检查的
IOException
。Warp将捕获此异常并将其用作HTTP500,希望也能为日志编写一些有用的内容。假设像现在这样的单一连接模式,您可以做一些聪明的事情(但代码行数很高),即“重新启动”
main
函数并建立第二个连接。我为爱好项目做的一些事情:如果出现任何异常情况,比如连接断开,我会让我的主管进程(比如systemd)查看日志并重新启动web服务。虽然对于制作赚钱的网站来说,这显然不是一个很好的解决方案,但它对于小型应用程序来说已经足够好了

如何使用
auth
功能进行身份验证?
auth
函数应该在创建管道后只调用一次,还是应该在每次点击“/”时调用

创建连接后应调用一次。MongoDB身份验证是针对每个连接的。你可以看到

  • 即使您为每个客户端创建连接,您也无法创建太多的连接。你会击中乌利米特的。一旦点击该ulimit,点击该ulimit的客户端将获得运行时错误。 之所以没有意义,是因为mongodb服务器将花费太多的时间轮询所有这些连接,并且它将只有与数据库中的CPU数量一样多的有意义的工作线程
    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