这是设置的正确方法吗?而不是为每次访问“/”创建一个数据库连接。在后一种情况下,我们可以同时拥有数百万个连接。这是气馁吗?这种方法的优点和缺点是什么?
您不想打开一个连接然后使用它。您使用的支持 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 鉴于服务器终止了连接,我可以试一试可能发生的情况:假设 Warp 为每个请求分叉一个绿色线程(我认为它确实如此),每个线程IOException
在尝试写入已关闭的线程时都会遇到未经检查的情况TCP 连接。Warp 会捕获这个异常并将其作为 HTTP 500 提供,希望也能写一些对日志有用的东西。假设你现在有一个单连接模型,你可以做一些聪明的(但代码行数很高)“重启”你的main
功能并建立第二个连接。我为爱好项目做的事情:如果发生任何奇怪的事情,例如连接断开,我会要求我的主管进程(如 systemd)查看日志并重新启动 Web 服务。虽然对于制作、赚钱的网站来说显然不是一个很好的解决方案,但它对于小型应用程序来说已经足够好了。
使用该auth
功能进行身份验证怎么样?该auth
函数应该在创建管道后只调用一次,还是应该在每次点击“/”时调用它?
它应该在创建连接后调用一次。MongoDB 身份验证是按连接进行的。您可以在此处查看该db.auth()
命令如何改变与当前客户端连接对应的 MongoDB 服务器数据结构的示例。