[英]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.