日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

《HBase权威指南》一3.4 行锁

發布時間:2023/12/10 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《HBase权威指南》一3.4 行锁 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本節書摘來異步社區《HBase權威指南》一書中的第3章,第3.4節,作者: 【美】Lars George 譯者: 代志遠 , 劉佳 , 蔣杰 責編: 楊海玲,更多章節內容可以訪問云棲社區“異步社區”公眾號查看。

3.4 行鎖

像put()、delete()、checkAndPut()這樣的修改操作是獨立執行的,這意味著在一個串行方式的執行中,對于每一行必須保證行級別的操作是原子性的。region服務器提供了一個行鎖(row lock)的特性,這個特性保證了只有一個客戶端能獲取一行數據相應的鎖,同時對該行進行修改。在實踐中,大部分客戶端應用程序都沒有提供顯式的鎖,而是使用這個機制來保障每個操作的獨立性。

文字用戶應該盡可能地避免使用行鎖。就像在RDBMS中,兩個客戶端很可能在擁有對方要請求的鎖時,又同時請求對方已擁有的鎖,這樣便形成了一個死鎖。

鎖超時之前,兩個被阻塞的客戶端會占用一個服務器端的處理線程(handler),而這個線程是一種十分稀缺的資源。如果在一個頻繁操作的行上發生了這種情況,那么很多其他的客戶端會占用掉其所有的處理線程,阻塞所有其他客戶端訪問這臺服務器,導致這個region服務器將不能為其負責的region內的行提供服務。

重申一下:在不必要的情況下,盡量不要使用行鎖。如果必須使用,那么一定要節約占用鎖的時間!
比如,當使用put()訪問服務器時,Put實例可以通過以下構造函數生成:

Put(byte[] row)

這個構造函數就沒有RowLock實例參數,所以服務器會在調用期間創建一個鎖。實際上,通過客戶端的API,得不到這個生存期短暫的服務器端的鎖的實例。

除了服務器端隱式加鎖之外,客戶端也可以顯式地對單行數據的多次操作進行加鎖,通過以下調用便可以做到:

RowLock lockRow(byte[] row) throws IOException void unlockRow(RowLock rl) throws IOException

第一個調用lockRow()需要一個行鍵作為參數,返回一個RowLock的實例,這個實例可以供后續的Put或者Delete的構造函數使用。一旦不再需要鎖時,必須通過unlockRow()調用來釋放它。

每一個排他鎖(unique lock),無論是由服務器提供的,還是通過客戶端API傳入的,都能保護這一行不被其他鎖鎖定。換句話說,鎖必須針對整個行,并且指定其行鍵,一旦它獲得鎖定權就能防止其他的并發修改。

當一個鎖被服務器端或客戶端顯式獲取之后,其他所有想要對這行數據加鎖的客戶端將會等待,直到當前鎖被釋放,或者鎖的租期超時。后者是為了確保錯誤進程不會占用鎖太長時間或無限期占用。

圖像說明文字默認的鎖超時時間是一分鐘,但是可以在hbase-site.xml文件中添加以下配置項來修改這個默認值,時間以毫秒為單位:

< property>< name>hbase.regionserver.lease.period< /name>< value>120000< /value> < /property>

通過添加以上代碼,超時時間被設置為原來的兩倍——120秒也就是2分鐘。小心不要將這個值設得太大,因為每一個想獲取被鎖住的行的客戶端都會阻塞并等待鎖的恢復。
例3.17展示了如何在行上創建一個鎖,該鎖阻塞所有的并發讀取。

例3.17 顯式使用行鎖

static class UnlockedPut implements Runnable { @Overridepublic void run() {try {HTable table = new HTable(conf,"testtable");Put put = new Put(ROW1);put.add(COLFAM1,QUAL1,VAL3);long time = System.currentTimeMillis();System.out.println("Thread trying to put same row now...");table.put(put);System.out.println("Wait time: " +(System.currentTimeMillis() - time)+ "ms");} catch(IOException e){System.err.println("Thread error: " + e);}} }System.out.println("Taking out lock..."); RowLock lock = table.lockRow(ROW1); System.out.println("Lock ID: " + lock.getLockId());Thread thread = new Thread(new UnlockedPut()); thread.start();try {System.out.println("Sleeping 5secs in main()...");Thread.sleep(5000); } catch(InterruptedException e){// ignore }try {Put put1 = new Put(ROW1,lock);put1.add(COLFAM1,QUAL1,VAL1);table.put(put1);Put put2 = new Put(ROW1,lock);put2.add(COLFAM1,QUAL1,VAL2);table.put(put2); } catch(Exception e){System.err.println("Error: " + e); } finally {System.out.println("Releasing lock...");table.unlockRow(lock); }

使用一個異步的線程更新同一個行,但是不顯式加鎖。

put()調用會阻塞,直到鎖被釋放。

給整行加鎖。

啟動那個會阻塞的異步線程。

休眠一會兒,以阻塞其他寫入操作。

在擁有鎖的情況下創建Put。

在擁有鎖的情況下創建另外一個Put。

釋放鎖,讓阻塞線程繼續執行。

執行這個例子代碼時,應該能在控制臺看到以下輸出:

Taking out lock... Lock ID: 4751274798057238718 Sleeping 5secs in main()... Thread trying to put same row now... Releasing lock... Wait time: 5007ms After thread ended... KV: row1/colfam1:qual1/1300775520118/Put/vlen=4,Value: val2 KV: row1/colfam1:qual1/1300775520113/Put/vlen=4,Value: val1 KV: row1/colfam1:qual1/1300775515116/Put/vlen=4,Value: val3

從這個例子能看出,一個顯示的鎖是如何阻塞另一個使用隱式鎖的線程的。主線程休眠了5秒,一醒來就調用了兩次put(),分別將同一列設置為兩個不同的數值。

主線程的鎖一釋放,阻塞線程的run()方法就繼續執行并調用了第三個put。觀察put操作在服務器端的執行情況,會覺得很有意思。讀者可能注意到了,KeyValue實例的時間戳顯示第三個put擁有最小的時間戳,雖然這個put表面上是最后執行的。這是因為線程中的put()調用是在兩個主線程中的put()之前執行的,這之后主線程休眠了5秒。當put被發送到服務器時,如果它的時間戳沒有被顯式指定,服務器端會幫它設定時間戳,同時試圖獲得這一行的鎖。但是示例代碼中主線程已經獲得了該行的鎖,因此服務器端的處理一直等待了5秒多,鎖被釋放才得已繼續。從上面的輸出可以看出,主線程中兩個put調用的執行以及行的解鎖只花費了7毫秒的時間。

Get需要鎖嗎?

修改行時鎖定行是有意義的,那么獲取數據時是否需要加鎖呢?Get類有一個構造器允許用戶指定一個顯式的鎖:

Get(byte[] row,RowLock rowLock)

這是遺留的方法,但服務器端根本用不著這種方法,因為在獲取數據的過程中,服務器根本不需要任何鎖,而是應用了一個多版本的并發控制(multiversion concurrencycontrol-style)⑦機制來保證行級讀操作。例如,get()調用永遠不會返回寫了一半的數據,比如當這些數據是另一個線程或者客戶端寫的。

這個就像是小規模的事務系統:只有當一個變動被應用到整個行之后,客戶端才能讀出這個改動。當改動在進行中時,所有的客戶端讀取操作得到的都將是所有列以前的狀態。
當用戶試圖使用之前申請的顯式鎖,但鎖的租約已經超時并恢復,用戶將會從服務器得到一個以UnknownRowLockException形式報告的錯誤。這個異常告訴用戶服務器已經廢棄了用戶嘗試使用的鎖。用戶應該在代碼中丟棄這個鎖,然后請求一個新的鎖再試圖恢復鎖定狀態。

總結

以上是生活随笔為你收集整理的《HBase权威指南》一3.4 行锁的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。