歡迎光臨
每天分享高質量文章

淺談C#在網絡波動時防重覆提交

    前幾天,公司資料庫出現了兩條相同的資料,而且時間相同(毫秒也相同)。排查原因,發現是網絡波動造成了重覆提交。

    由於網絡波動而重覆提交的例子也比較多:

    網絡上,防重覆提交的方法也很多,使用redis鎖,代碼層面使用lock。

    但是,我沒有發現一個符合我心意的解決方案。因為網上的解決方案,第一次提交傳回成功,第二次提交傳回失敗。由於兩次傳回信息不一致,一次成功一次失敗,我們不確定客戶端是以哪個傳回信息為準,雖然我們希望客戶端以第一次傳回成功的信息為準,但客戶端也可能以第二次失敗信息運行,這是一個不確定的結果。

在重覆提交後,如果客戶端的接收到的信息都相同,都是成功,那客戶端就可以正常運行,就不會影響用戶體驗。

    我想到一個快取類,來源於PetaPoco。

Cache代碼如下:



    Cache符合我的要求,第一次運行後,會將值快取,第二次提交會傳回第一次的值。

    但是,細細分析Cache 類,可以發現有以下幾個缺點

         1、 不會自動清空快取,適合一些key不多的資料,不適合做為網絡接口。

         2、 由於_lock.EnterWriteLock,多執行緒會變成並單執行緒,不適合做為網絡接口。

         3、 沒有過期快取判斷。

    於是我對Cache進行改造。

AntiDupCache代碼如下:



代碼分析:

      使用兩個ReaderWriterLockSlim鎖 + 一個AntiDupLockSlim鎖,實現併發功能。

      Dictionary> _map實現快取,long型別值記錄時間,實現快取過期

      int _maxCount + Queue _queue,_queue 記錄key列隊,當數量大於_maxCount,清除多餘快取。

      AntiDupLockSlim繼承ReaderWriterLockSlim,實現垃圾回收,

代碼使用 :


測試性能資料:

———————– 開始  從1到100   重覆次數:1 單位: ms ———————–

      併發數量: 1    2    3    4    5    6    7    8    9    10   11   12

      普通併發: 188  93   65   46   38   36   28   31   22   20   18   19

  AntiDupCache: 190  97   63   48   37   34   29   30   22   18   17   21

  AntiDupQueue: 188  95   63   46   37   33   30   25   21   19   17   21

     DictCache: 185  96   64   47   38   33   28   29   22   19   17   21

         Cache: 185  186  186  188  188  188  184  179  180  184  184  176

第二次普通併發: 180  92   63   47   38   36   26   28   20   17   16   20

———————– 開始  從1到100   重覆次數:2 單位: ms ———————–

      併發數量: 1    2    3    4    5    6    7    8    9    10   11   12

      普通併發: 368  191  124  93   73   61   55   47   44   37   34   44

  AntiDupCache: 180  90   66   48   37   31   28   24   21   17   17   22

  AntiDupQueue: 181  93   65   46   39   31   27   23   21   19   18   19

     DictCache: 176  97   61   46   38   30   31   23   21   18   18   22

         Cache: 183  187  186  182  186  185  184  177  181  177  176  177

第二次普通併發: 366  185  127  95   71   62   56   48   43   38   34   43

———————– 開始  從1到100   重覆次數:4 單位: ms ———————–

      併發數量: 1    2    3    4    5    6    7    8    9    10   11   12

      普通併發: 726  371  253  190  152  132  106  91   86   74   71   69

  AntiDupCache: 189  95   64   49   37   33   28   26   22   19   17   18

  AntiDupQueue: 184  97   65   51   39   35   28   24   21   18   17   17

     DictCache: 182  95   64   45   39   34   29   23   21   18   18   16

         Cache: 170  181  180  184  182  183  181  181  176  179  179  178

第二次普通併發: 723  375  250  186  150  129  107  94   87   74   71   67

———————– 開始  從1到100   重覆次數:12 單位: ms ———————–

      併發數量: 1    2    3    4    5    6    7    8    9    10   11   12

      普通併發: 2170 1108 762  569  450  389  325  283  253  228  206  186

  AntiDupCache: 182  95   64   51   41   32   28   25   26   20   18   18

  AntiDupQueue: 189  93   67   44   37   35   29   30   27   22   20   17

     DictCache: 184  97   59   50   38   29   27   26   24   19   18   17

         Cache: 174  189  181  184  184  177  182  180  176  176  180  179

第二次普通併發: 2190 1116 753  560  456  377  324  286  249  227  202  189

仿線上環境,性能測試資料:

———————– 仿線上環境  從1到1000  單位: ms ———————–

      併發數量: 1    2    3    4    5    6    7    8    9    10   11   12

      普通併發: 1852 950  636  480  388  331  280  241  213  198  181  168

  AntiDupCache: 1844 949  633  481  382  320  267  239  210  195  174  170

  AntiDupQueue: 1835 929  628  479  386  318  272  241  208  194  174  166

     DictCache: 1841 935  629  480  378  324  269  241  207  199  176  168

         Cache: 1832 1854 1851 1866 1858 1858 1832 1825 1801 1797 1788 1785

第二次普通併發: 1854 943  640  468  389  321  273  237  209  198  177  172

專案:

      Github:https://github.com/toolgood/ToolGood.AntiDuplication

      Nuget: Install-Package ToolGood.AntiDuplication

後記:

     嘗試添加 一個Queue 或Stack 用來快取鎖,後發現性能效率相差不大,上下浮動。

     使用 lock關鍵字加鎖,速度相差不大,代碼看似更簡單,但隱藏了一個地雷:一般人使用唯一鍵都是使用string,就意味著可能使用lock(string),鎖定字串尤其危險,因為字串被公共語言運行庫 (CLR)“暫留”。 這意味著整個程式中任何給定字串都只有一個實體,就是這同一個物件表示了所有運行的應用程式域的所有執行緒中的該文本。因此,只要在應用程式行程中的任何位置處具有相同內容的字串上放置了鎖,就將鎖定應用程式中該字串的所有實體。

已同步到看一看
赞(0)

分享創造快樂