golang的sql.DB的一些注意事項及讀寫鎖的總結

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

最近在寫一個用於儲存protobuf配置的組態管理服務,商務邏輯不難,2天就搞定,但是後續bug不少,也踩了很多坑,在這裡記錄下。


首先,一直以為golang內的sql模組是單連結的,所以一開始在每個goroutine內都open了一個DB,並寫了一個串連池進行管理。後續發現是多此一舉,白白寫了好多代碼。golang的sql模組內建串連池功能,在執行sql語句的時候才會分配串連,執行完畢後歸還給串連池,所以假設用golang的sql模組,一個程式一個DB就行了。


既然有串連池的支援,那麼也要注意千萬不要泄露串連池的串連。假設你採用Query來執行查詢語句,那麼會返回一個sql.Rows結構,這個結構會佔用一個串連,只有在遍曆完才會自動關閉,所以最好是獲得了Rows後執行一次Rows的Close方法,多次Close是沒事的。


然後,因為被上級否定了使用transaction的想法,只能在程式內進行事務控制。一開始整個sql執行model共用一個讀寫鎖,在執行效能測試的情況下,讀的tps在3k左右,效能還行,可是寫卻只是200。這是無法接受的,後來仔細分析了下代碼,在寫前面鎖了寫,那麼並行的幾個routine會等待佔有鎖的那個routine寫入完畢才會有第二個routine進行寫操作,就等於白白的排隊了,而測試案例是insert新的記錄而已,不會有衝突的問題。現在想想一個鎖雖然寫起來方便,但是效能影響很大,於是今天寫了一個新的讀寫鎖管理器,綁定特定的key,每一個key在當前key的鎖被佔用的情況下,會返回被佔用的鎖,並且將引用計數值+1,假設沒有對應的鎖,則返回新的鎖。釋放鎖的時候,判定當前key的鎖的引用值,假設已經為0了,說明沒有被其它routine進行鎖wait,則銷毀這個鎖,否則引用計數值-1。


這樣的話,將不同的sql產生一個key,採用這個key來進行寫衝突管理,當兩個sql有相同的key的時候,則會進行鎖競爭,假設key不相同,則不會有競爭。同時採用引用計數來避免讀寫鎖的泄露,對長期穩定運行伺服器有好處。

讀操作的話,則當前沒有寫鎖的情況下,則直接進行讀取,所以讀的效能不會有很大的影響。


在這個新的鎖的設計下,tps從200提升到了1200,算是可接受的範圍了。這個方案的關鍵點在於key的產生,在於提取每個sql操作影響的行,只要能得到這個key,則產生讀寫鎖將十分方便。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.