日本熟妇hd丰满老熟妇,中文字幕一区二区三区在线不卡 ,亚洲成片在线观看,免费女同在线一区二区

鎖以及排查鎖

鎖是一種數據庫的信號量管理機制,作用是保證SQL執行上不同事務的隔離性。本文為您介紹Hologres中的鎖及如何排查鎖。

背景信息

當一個Query發起時,在Hologres中其經過的鏈路如下圖所示。Query鏈路Frontend解析Query,Query Engine生成執行計劃,然后Storage Engine讀取數據,整個鏈路的鎖有如下兩種。

  • Frontend Locks(前端鎖)

    Frontend為接入層,兼容PostgreSQL協議,因此鎖也會兼容PostgreSQL的部分鎖,主要用來管理Frontend(FE)元數據信息。

  • Backend Locks(后端鎖)

    Backend是指Query Engine和Fixed Plan,將會享有Hologres自帶的鎖,主要用于管理Storage Engine的Schema和數據。

鎖行為變更說明

  • 自Hologres V2.0版本開始,FE默認啟用了無鎖機制。當表的DDL、DQL發生沖突時(例如,在表A發生DDL變更期間有新的查詢請求),新的請求會直接報錯。如果您希望在沖突發生時不報錯,而是等待鎖釋放后再執行新的請求,您可以執行以下命令來設置GUC參數,關閉無鎖機制。

    ALTER database <db_name> SET hg_experimental_disable_pg_locks = off;
  • 從Hologres V2.1版本開始,對于無主鍵表的Bulkload操作進行了優化,改為僅獲取行鎖,而不再獲取表鎖。

鎖介紹

  • Frontend Locks(FE Locks)

    Hologres接入層Frontend兼容PostgreSQL,因此在接入層的鎖與PostgreSQL兼容。PostgreSQL提供了Table-level Lock、Row-level Lock和Advisory Lock三種鎖模式來控制并發的數據訪問。 目前Hologres兼容的是Table-level Lock和Advisory Lock。

    說明

    Hologres目前不支持顯式的設置鎖命令以及Advisory Lock相關的UDF。

    • Table-level Lock

      • 分類

        Table-level Lock是指表鎖,表鎖包含如下種類。

        鎖名稱

        說明

        備注

        ACCESS SHARE

        一般情況下只有SELECT命令會獲取相關表的這個鎖。

        不涉及。

        ROW SHARE

        只有SELECT FOR UPDATESELECT FOR SHARE這兩個命令需要獲取目標表的這個鎖,非目標表(比如JOIN關聯的其他表)僅獲取ACCESS SHARE鎖。

        Hologres不支持SELECT FOR UPDATESELECT FOR SHARE命令,因此無需關注。

        ROW EXCLUSIVE

        UPDATEDELETEINSERT 修改數據的命令需要獲取此鎖。

        需要結合Backend Locks一起關注。

        SHARE UPDATE EXCLUSIVE

        為了防止Vacuum和并發的Schema變更發生沖突的鎖,如下命令需要獲取此鎖。

        • lazy VACUUM 即非 Vacuum Full

        • ANALYZE

        • CREATE INDEX CONCURRENTLY

          說明

          Hologres使用此命令時不會獲取 SHARE UPDATE EXCLUSIVE鎖,而是與非 CONCURRENTLY形式的CREATE INDEX一樣獲取SHARE鎖。

        • CREATE STATISTICS,此命令Hologres不支持。

        • COMMENT ON

        • ALTER TABLE VALIDATE CONSTRAINT,此命令Hologres不支持。

        • ALTER TABLE SET/RESET (storage_parameter),Hologres僅支持使用此命令設置自己擴展的屬性以及PostgreSQL原生的 autovacuum_enabled屬性,不支持設置其他屬性;且設置上述屬性時不會獲取表的任何鎖。修改PostgreSQL內置的其他某些storage parameter參數需要獲取此鎖,詳情請參見ALTER TABLE

        • ALTER TABLE ALTER COLUMN SET/RESET options

        • ALTER TABLE SET STATISTICS,此命令Hologres不支持。

        • ALTER TABLE CLUSTER ON,此命令Hologres不支持。

        • ALTER TABLE SET WITHOUT CLUSTER,此命令Hologres不支持。

        重點關注ANALYZE命令。

        SHARE

        只有非concurrently的 CREATE INDEX 需要獲取此鎖。

        說明

        Hologres中創建JSON索引時會需要拿此鎖。

        關注 CREATE INDEX命令(創建JSON相關索引)。

        SHARE ROW EXCLUSIVE

        為了防止并發的數據修改的鎖,需要獲取此鎖的命令如下。

        • CREATE COLLATION,此命令Hologres不支持。

        • CREATE TRIGGER:,此命令Hologres不支持。

        • 部分ALTER TABLE命令。

          • DISABLE/ENABLE [ REPLICA | ALWAYS ] TRIGGER,此命令Hologres不支持。

          • ADD table_constraint,此命令Hologres不支持。

        Hologres不支持獲取此鎖的命令,所以無需關注。

        EXCLUSIVE

        僅有REFRESH MATERIALIZED VIEW CONCURRENTLY命令需要獲取此鎖。

        Hologres不支持REFRESH MATERIALIZED VIEW CONCURRENTLY命令,無需關注。

        ACCESS EXCLUSIVE

        完全獨占訪問需要的鎖,與其他所有的鎖都沖突,需要獲取此鎖的命令如下。

        • DROP TABLE

        • TRUNCATE TABLE

        • REINDEX,此命令Hologres不支持。

        • CLUSTER,此命令Hologres不支持。

        • VACUUM FULL

        • REFRESH MATERIALIZED VIEW (without CONCURRENTLY),此命令Hologres不支持。

        • LOCK,顯式的LOCK命令,如果不指明具體的鎖類型,默認需要這個鎖;此命令Hologres不支持。

        • ALTER TABLE,除去上面明確提到獲取特定鎖的ALTER TABLE形式以外,其他的ALTER TABLE命令形式都默認獲取這個鎖。

        需要重點關注的鎖,在Hologres中執行的DDL操作都會獲取該鎖,與其他鎖沖突。

      • 超時時間

        FE Locks沒有默認超時時間,需要業務設置超時時間,防止鎖等待時間過長,詳情請參見Query管理

      • 沖突關系

        鎖之間的沖突關系如下表所示,沖突意味著一個操作獲取鎖,其他操作獲取的鎖都需要等待。

        說明

        已開通表示不沖突,未開通表示沖突。

        Requested Lock Mode

        ACCESS SHARE

        ROW SHARE

        ROW EXCLUSIVE

        SHARE UPDATE EXCLUSIVE

        SHARE

        SHARE ROW EXCLUSIVE

        EXCLUSIVE

        ACCESS EXCLUSIVE

        ACCESS SHARE

        已開通

        已開通

        已開通

        已開通

        已開通

        已開通

        已開通

        未開通

        ROW SHARE

        已開通

        已開通

        已開通

        已開通

        已開通

        已開通

        未開通

        未開通

        ROW EXCLUSIVE

        已開通

        已開通

        已開通

        已開通

        未開通

        未開通

        未開通

        未開通

        SHARE UPDATE EXCLUSIVE

        已開通

        已開通

        已開通

        未開通

        未開通

        未開通

        未開通

        未開通

        SHARE

        已開通

        已開通

        未開通

        未開通

        已開通

        未開通

        未開通

        未開通

        SHARE ROW EXCLUSIVE

        已開通

        已開通

        未開通

        未開通

        未開通

        未開通

        未開通

        未開通

        EXCLUSIVE

        已開通

        未開通

        未開通

        未開通

        未開通

        未開通

        未開通

        未開通

        ACCESS EXCLUSIVE

        未開通

        未開通

        未開通

        未開通

        未開通

        未開通

        未開通

        未開通

    • Advisory Lock

      Advisory Lock指咨詢鎖,PostgreSQL提供了一種方法創建由應用定義其含義的鎖。Hologres大部分業務情況無需額外關注。

  • Backend Locks(BE Locks)

    • 分類

      在Hologres中BE Locks鎖分類如下。

      鎖分類

      鎖介紹

      Exclusive(X)

      排他鎖(也稱互斥鎖),當事務需要修改一批或一條數據時申請排他鎖,例如DML語句(DELETE、INSERT、UPDATE)。排他鎖申請成功的前提是同一資源上沒有其他的共享鎖或排他鎖,當排他鎖申請成功后,鎖資源上將不能同時有其他鎖。

      Shared(S)

      共享鎖,當事務需要讀取一批或一條數據時申請共享鎖,以免其他事務對將要讀取的數據做修改。同一個資源上允許存在多個共享鎖,即允許DQL之間并發執行,因為DQL不會改變資源本身。

      Intent(I)

      意向鎖,這種類型的鎖通常用于表達鎖的層次結構,同一個資源上允許存在多個意向鎖,當申請成功后,該資源上就不能有排他鎖。例如,當事務申請一行的排他鎖時,它會同時申請表的意向鎖(表是比行更高層次的資源),以防止其他事務申請表的排他鎖。

    • 超時時間

      BE Locks超時時間默認為5min,超過該時間則報錯。

    • 沖突關系

      BE Locks的沖突關系如下,沖突表示一個操作獲取鎖,其余操作都需要等待鎖。

      說明

      已開通表示不沖突,未開通表示沖突。

      操作

      DROP

      ALTER

      SELECT

      UPDATE

      DETELE

      INSERT(包含INSERT ON CONFLICT)

      DROP

      未開通

      未開通

      未開通

      未開通

      未開通

      未開通

      ALTER

      未開通

      未開通

      已開通

      未開通

      未開通

      未開通

      SELECT

      未開通

      已開通

      已開通

      已開通

      已開通

      已開通

      UPDATE

      未開通

      未開通

      已開通

      未開通

      未開通

      未開通

      DETELE

      未開通

      未開通

      已開通

      未開通

      未開通

      未開通

      INSERT(包含INSERT ON CONFLICT)

      未開通

      未開通

      已開通

      未開通

      未開通

      未開通

鎖的作用范圍

根據鎖的分類,不同的鎖作用范圍不同。

  • FE Locks

    FE Locks只會作用在表對象上,與表數據無關,且鎖只有成功或者卡住兩種狀態,卡住就代表有鎖沖突在等待鎖。

  • BE Locks

    BE Locks會作用在數據或者表結構上,因此在作用范圍上會分為表數據鎖、行數據鎖、表結構(Schema)鎖。

    • 表數據鎖:代表整個表的數據都需要獲取鎖,如果多個任務同時都需要獲取表數據鎖,會造成任務等待鎖現象,從而任務延遲。

    • 行數據鎖:指整行數據獲取鎖,在執行效率上會更高,其中走Fixed Plan加速SQL執行的Query都是行數據鎖或者表Schema鎖。

    • 表Schema鎖:即表結構鎖,當事務需要讀取或修改表結構時申請Schema鎖,大部分的事務都會申請Schema鎖。目前主要有如下類型的Schema鎖。

      • SchX:Schema排他鎖,用于DDL語句,目前只支持DROP TABLE命令。

      • SchU:Schema更新鎖,用于修改表結構的DDL語句包含ALTER TABLEset_table_property命令。

      • SchE:Schema存在鎖,用戶DML和DQL語句,確保讀寫數據期間表不會被刪除。

      說明
      • SchU是DDL鎖更細粒度的管控,允許ALTER TABLE期間DQL正常運行,無需等待;SchX是最粗粒度的DDL排他鎖,所有的DDL、DML、DQL都會等待。

      • 如果Start Query耗時較長,則可能在等待BE Locks。

在Hologres中,其中常見命令作用的鎖范圍如下。已開通表示操作命令會獲取該鎖。

說明
  • 非Fixed Plan的寫入、更新、刪除都為Bulkload。

  • CREATE INDEX命令目前是指創建JSON相關索引。

  • DDL命令包括CREATEDROPALTER等。

操作/鎖范圍

表鎖

表數據鎖

行數據鎖

表Schema鎖

CREATE

已開通

不涉及

DROP

已開通

說明

一旦DROP命令獲取鎖,無法執行其他命令,其他命令會等待鎖,直到發現表被刪除了,則其他命令失敗。

說明:

不涉及

不涉及

已開通

說明

與其他操作都沖突。

ALTER

已開通

說明

與DROP命令一致。

不涉及

不涉及

已開通

說明

在獲取表Schema鎖的同時可以對表執行SELECT命令。

SELECT

已開通

說明

在獲取表鎖的同時可以對表執行INSERTUPDATEDELETE命令,只與DDL鎖沖突。

不涉及

不涉及

已開通

說明

執行SELECT命令時除了不能執行DROP命令,其他操作都可以做。

INSERT (包含INSERT ON CONFLICT)

已開通

說明

INSERT命令與 CREATE INDEX、DDL沖突。

  • Hologres V2.0及以前版本的Bulkload方式會獲取表數據鎖。

  • Hologres V2.1版本起,僅有主鍵表的Bulkload會獲取表數據鎖。

說明

Bulkload與Fixed Plan相互沖突。

如果是通過Fixed Plan方式則獲取行數據鎖。

Hologres V2.1版本起,無主鍵表的Bulkload也改為僅獲取行數據鎖。

說明
  • Hologres V2.0及以前版本不支持離線寫入和Fixed Plan實時寫入同時進行。

  • Hologres V2.1版本起支持無主鍵表的離線寫入和Fixed Plan實時寫入同時進行。

已開通

說明

與DDL、DML沖突。

UPDATE

已開通

說明

CREATE INDEX、DDL鎖沖突。

已開通

說明

與DDL、DML沖突。

DELETE

已開通

說明

CREATE INDEX、DDL鎖沖突。

已開通

說明

與DDL、DML沖突。

事務相關的鎖說明

Hologres目前僅支持DDL的顯式事務,并不支持單純的DML事務,也不支持DDL和DML混合的事務。

  • Hologres不支持嵌套子事務。

  • 單純的DML事務雖然語法上可以通過,但是實際不支持原子提交和回滾。

    如下DML即使insert成功,如果之后的update失敗了,insert的數據也不會被回滾。

    begin;
    insert into t1(id, salary) values (1, 0);
    update t1 set salary = 0.1 where id = 1;
    commit;
  • 純DDL事務可以按預期的方式工作

    其中任何一行DDL命令失敗則會整個事務被回滾。例如下面alter命令失敗時,前面createdrop操作會被回滾。

    begin;
    create table t1(i int);
    drop table if exists t2;
    alter table t1 add column n text;
    commit;
  • DDL和DML命令混合的事務會被禁止

    如下示例,當事務中包含DDL和DML命令時,DML命令就會報錯。

    begin;
    create table t1(i int);
    update t1 set i = 1 where i = 1;
    -- DML命令報錯
    ERROR:  UPDATE in ddl transaction is not supported now.
  • 顯式事務中任何一個命令獲得的鎖都只會在整個事務結束(提交或回滾)時才統一釋放。

    如下示例,當對父表做alter操作時,會同時獲取父表(login_history)和子表(login_history_202001)的ACCESS EXCLUSIVE鎖, 但是這個命令執行完不會立即釋放對應的鎖,而是要等待最后的commit執行完(不管成功還是失敗)才會釋放鎖。若是一直不執行commit,則會一直保持鎖,這時若有其他對這個表的DDL操作,則會鎖表并報錯。

     -- suppose we have three tables
    create table temp1(i int, t text);
    create table login_history(ds text, user_id bigint, ts timestamptz) partition by list (ds);
    create table login_history_202001 partition of login_history for values in ('202001');
    
    begin;
    alter table login_history_s1 add column user_id bigint;
    drop table temp1;
    create table tx2(i int);
    commit;

FE鎖排查

可以通過如下步驟排查是否有FE的鎖,以及出現鎖之后如何解決:

  1. 如果Query耗時較長,可以通過wait_event_type字段查詢當前Query是否有鎖。

    如下命令示例,如果結果中wait_event_type字段值為lock,說明該Query有FE的鎖。

    --2.0及其以上版本
    select query,state,query_id,transaction_id,pid,wait_event_type,wait_event,running_info,extend_info FROM hg_stat_activity where query_id = 200640xxxx;
    --返回結果
    ----------------+----------------------------------------------------------------
    query           | drop table test_order_table1;
    state           | active
    query_id        | 200640xxxx
    pid             | 123xx
    transaction_id  | 200640xxxx
    wait_event_type | Lock
    wait_event      | relation
    running_info    | {"current_stage":{"stage_duration_ms":47383,"stage_name":"PARSING"},"fe_id":1,"warehouse_id":0}+
                    |
    extend_info     | {}                                                                                                                                           +
    
    --1.3及以下版本
    select datname, pid, application_name, wait_event_type, state,query_start, query from pg_stat_activity where backend_type in ('client backend');
    --返回結果
    ----------------+----------------------------------------------------------------
    datname           | holo_poc
    pid               | 321xxx
    application_name  | PostgreSQL JDBC Driver
    wait_event_type   | lock
    state             | active
    query_start       |2023-04-20 14:31:46.989+08
    query             | delete from xxx
  2. 查看鎖的持有者。

    使用如下命令查看鎖的持有者:

    select * from pg_locks where pid = <pid>;

    pid為步驟1中返回結果中的pid

  3. 排查哪個進程在拿鎖。

    通過步驟2判斷出當前SQL有鎖,根據其oid(即表關系)通過以下命令查看是否有拿鎖,t代表true,代表正在拿鎖。

    -- 查看拿到了表鎖的進程信息
    select pid from pg_locks where relation = <OID> and granted = 't';
  4. 排查拿鎖的Query。

    通過步驟3返回結果的PID,使用如下命令查詢真正拿鎖的Query。

    select * from pg_stat_activity where pid = <PID>;
  5. 釋放鎖。

    找到拿鎖的Query之后,使用如下命令可以直接將Query結束,以釋放鎖。

    select pg_cancel_backend(<pid>);

BE鎖排查

如果在hg_stat_activity視圖的be_lock_waitersbe_lock_converting_waiters字段有數據,說明Query在后端有鎖或者被鎖,可以通過如下步驟排查。

  • 情況1:當前Query產生鎖,其余Query在等該鎖釋放。

    通過以下SQL可以看到當前SQL是否有BE鎖,以及哪些Query被該SQL鎖住,等待其釋放鎖。

    select query_id, transaction_id, ((extend_info::json)->'be_lock_waiters'->>0)::text as be_lock_waiters 
    FROM hg_stat_activity as h where h.state = 'active' and ((extend_info::json)->'be_lock_waiters')::text != '';
    
    --返回結果
    ----------------+------------------
    query_id        | 10005xxx
    transaction_id  | 10005xxx
    be_lock_waiters | 13235xxx
  • 情況2:查看當前Query被哪個Query鎖住,等待它釋放鎖。

    通過如下SQL,查詢當前Query被誰拿著鎖,等待這個Query釋放鎖。

    select query_id, transaction_id, ((extend_info::json)->'be_lock_waiters')::text as be_lock_waiters 
    FROM hg_stat_activity as h where h.state = 'active' and ((extend_info::jsonb)->'be_lock_waiters')::jsonb ? '10005xxx';
    
    -[ RECORD 1 ]---+------------------------------------------
    query_id        | 200740017664xxxx
    transaction_id  | 200740017664xxxx
    be_lock_waiters | ["200640051468xxxx","200540035746xxxx"]

常見問題

  • 報錯:internal error: Cannot acquire lock in time, current owners: [(Transaction =302xxxx, Lock Mode = SchS|SchE|X)].

    • 可能原因:執行Query的表有被其他Query獲取了BE Locks(如報錯Lock Mode = SchS|SchE|X,則為Schema穩定鎖、存在鎖、排他鎖),導致Query等待BE Locks超時(5min)從而報錯。

    • 解決方法:報錯中的transactionTransaction =302xxxx對應Query ID,可以通過Query ID在慢Query日志或者活躍Query中查看對應獲取鎖的Query。

  • 報錯:ERROR: Operation timed out: Wait schema version timeout.: Server current target schema version:xxx is late from request schema version: yyy

    • 可能原因:執行DDL后,會先在Frontend(FE)節點執行,再異步在Storage Engine(SE)執行,當FE執行DDL結束后會對節點版本(Version)進行更新,若SE的DDL還沒執行完成,導致SE的版本比FE的版本低,此時Query會等待SE執行DDL,如果超過5min后SE仍然沒有執行完成,就會報錯等待Schema版本超時。

    • 解決方法:

      • 先終止(Kill)掉等待鎖的DDL,然后重試Query。

      • 重啟實例(極端手段)。

  • 報錯:The requested table name: xxx (id: 10, version: 26) mismatches the version of the table (id: 10, version: 28) from server

    • 可能原因:執行DDL后,會先在Frontend(FE)單個節點執行,再異步在Storage Engine(SE)執行。SE已經完成DDL并更新版本,但是因為FE節點較多,節點間Replay未完成,導致部分FE節點的版本低于SE,而Query正好在版本較低的FE中執行,從而出現報錯。

    • 解決方法:

      • 多重試幾次Query。

      • 若是超過幾分鐘還報錯建議重啟實例。

  • 報錯:internal error: Cannot find index full ID: 86xxx (table id: 20yy, index id: 1) in storages or it is deleting!

    • 可能原因:執行DROP Table或者Truncate Table時,對這個表進行DML(SELECT、DELETE等)需要獲取DDL鎖,導致Query需要等鎖,直到發現表被刪除了從而報錯。

    • 解決方法:執行DROPTRUNCATE命令時,不對表執行其他Query。