Lock adalah mekanisme manajemen semaphore yang digunakan database untuk mengisolasi eksekusi SQL dari transaksi yang berbeda. Topik ini menjelaskan lock di Hologres dan cara melakukan troubleshooting terkait masalah lock.
Informasi latar belakang
Saat sebuah kueri dikirim, kueri tersebut mengikuti jalur seperti pada gambar di bawah ini di Hologres.
Antarmuka depan (FE) mengurai kueri, mesin kueri menghasilkan rencana eksekusi, dan mesin penyimpanan membaca data. Terdapat dua jenis lock sepanjang jalur ini:
Kunci FE
FE merupakan lapisan akses dan kompatibel dengan protokol PostgreSQL. Oleh karena itu, lock FE mencakup lock kompatibel PostgreSQL tertentu yang terutama digunakan untuk mengelola metadata FE.
Kunci BE
Backend (BE) mencakup mesin kueri dan fixed plan. Lock BE bersifat native di Hologres dan digunakan untuk mengelola skema dan data di mesin penyimpanan.
Perubahan perilaku kunci
Mulai dari Hologres V2.0, mekanisme bebas lock (lock-free) diaktifkan secara default untuk FE. Jika pernyataan Data Definition Language (DDL) dan pernyataan Data Query Language (DQL) pada tabel yang sama saling bertentangan, permintaan baru akan langsung mengembalikan error. Misalnya, jika permintaan kueri baru tiba saat operasi DDL sedang berjalan pada Tabel A, permintaan tersebut gagal. Jika Anda ingin sistem menunggu hingga lock dilepas alih-alih mengembalikan error, Anda dapat menjalankan perintah berikut untuk menonaktifkan mekanisme bebas lock dengan mengatur parameter Grand Unified Configuration (GUC):
ALTER database <db_name> SET hg_experimental_disable_pg_locks = off;Mulai dari Hologres V2.1, operasi bulkload pada tabel tanpa primary key dioptimalkan untuk hanya memperoleh lock tingkat baris (row-level locks) alih-alih lock tingkat tabel (table-level locks).
Pengenalan kunci
Kunci FE
Antarmuka depan Hologres kompatibel dengan PostgreSQL. Oleh karena itu, lock FE selaras dengan model locking PostgreSQL. PostgreSQL menyediakan tiga mode lock untuk mengontrol akses data konkuren: lock tingkat tabel, lock tingkat baris, dan advisory lock. Hologres saat ini mendukung lock tingkat tabel dan advisory lock.
CatatanHologres tidak mendukung perintah lock eksplisit atau user-defined function (UDF) terkait advisory lock.
Kunci Tingkat Tabel
Kategori
Lock tingkat tabel berlaku untuk seluruh tabel. Tabel berikut mencantumkan jenis-jenis lock tingkat tabel.
Nama kunci
Deskripsi
Catatan:
ACCESS SHARE
Perintah
SELECTmemperoleh lock ini pada tabel terkait.N/A
ROW SHARE
Perintah
SELECT FOR UPDATEdanSELECT FOR SHAREmemperoleh lock ROW SHARE pada tabel target. Pada tabel non-target, seperti tabel lain yang terlibat dalam JOIN, perintah ini hanya memperoleh lock ACCESS SHARE.Hologres tidak mendukung perintah
SELECT FOR UPDATEatauSELECT FOR SHARE. Oleh karena itu, lock ini tidak digunakan.ROW EXCLUSIVE
Pernyataan
UPDATE,DELETE, danINSERTyang memodifikasi data memperoleh lock ini.Pantau lock ini bersamaan dengan lock BE.
SHARE UPDATE EXCLUSIVE
Lock ini melindungi tabel dari perubahan skema konkuren dan eksekusi `VACUUM`. Perintah berikut memperoleh lock ini:
lazy VACUUM, selainVacuum Full.ANALYZE.CREATE INDEX CONCURRENTLY.CatatanHologres tidak memperoleh lock SHARE UPDATE EXCLUSIVE untuk perintah ini. Sebagai gantinya, Hologres memperoleh lock
SHARE, mirip dengan perintahCREATE INDEXtanpa opsi `CONCURRENTLY`.CREATE STATISTICS. Hologres tidak mendukung perintah ini.COMMENT ON.ALTER TABLE VALIDATE CONSTRAINT. Hologres tidak mendukung perintah ini.ALTER TABLE SET/RESET (storage_parameter). Hologres hanya mendukung perintah ini untuk mengatur properti tambahannya dan properti PostgreSQL native autovacuum_enabled. Pengaturan properti ini tidak memperoleh lock tabel apa pun. Lock ini diperlukan untuk memodifikasi beberapa nilai storage parameter PostgreSQL bawaan lainnya. Untuk informasi lebih lanjut, lihat ALTER TABLE.ALTER TABLE ALTER COLUMN SET/RESET options.ALTER TABLE SET STATISTICS. Hologres tidak mendukung perintah ini.ALTER TABLE CLUSTER ON. Hologres tidak mendukung perintah ini.ALTER TABLE SET WITHOUT CLUSTER. Hologres tidak mendukung perintah ini.
Perhatikan perintah
ANALYZE.SHARE
Pernyataan
CREATE INDEXyang dieksekusi dalam mode non-konkuren memperoleh lock ini.CatatanLock ini diperlukan saat Anda membuat indeks JSON di Hologres.
Gunakan perintah
CREATE INDEXuntuk membuat indeks terkait JSON.SHARE ROW EXCLUSIVE
Perintah berikut memperoleh lock untuk mencegah modifikasi data konkuren.
CREATE COLLATION: Hologres tidak mendukung pernyataan ini.CREATE TRIGGER: Hologres tidak mendukung pernyataan ini.ALTER TABLEtertentu.DISABLE/ENABLE [ REPLICA | ALWAYS ] TRIGGER: Hologres tidak mendukung pernyataan ini.ADD table_constraint: Hologres tidak mendukung pernyataan ini.
Hologres tidak mendukung perintah yang memperoleh lock ini. Oleh karena itu, tidak diperlukan tindakan apa pun.
EXCLUSIVE
Perintah
REFRESH MATERIALIZED VIEW CONCURRENTLYmemperoleh lock ini.Hologres tidak mendukung pernyataan
REFRESH MATERIALIZED VIEW CONCURRENTLY. Tidak diperlukan tindakan apa pun.ACCESS EXCLUSIVE
Lock ini memberikan akses eksklusif dan bertentangan dengan semua lock lainnya. Perintah berikut memperoleh lock ini:
DROP TABLETRUNCATE TABLEREINDEX: Hologres tidak mendukung perintah ini.CLUSTER: Hologres tidak mendukung perintah ini.VACUUM FULLREFRESH MATERIALIZED VIEW (tanpa CONCURRENTLY): Hologres tidak mendukung perintah ini.LOCK: Perintah `LOCK` eksplisit. Jika Anda tidak menentukan jenis lock, lock ini diperoleh secara default. Hologres tidak mendukung perintah ini.ALTER TABLE: Secara default, semua perintahALTER TABLElainnya memperoleh lock ini, kecuali bentukALTER TABLEyang secara eksplisit disebutkan memperoleh lock spesifik lainnya.
Ini adalah lock kritis. Semua operasi DDL di Hologres memperoleh lock ini. Lock ini bertentangan dengan semua lock lainnya.
Timeout
Secara default, kunci FE tidak memiliki batas waktu. Jika Anda ingin menentukan periode timeout untuk kunci FE untuk mengontrol waktu tunggu, lihat Kelola Query.
Hubungan yang saling bertentangan
Tabel berikut menunjukkan konflik lock. Konflik berarti jika satu operasi memegang lock, operasi lain yang meminta lock yang bertentangan harus menunggu.
Catatanmenunjukkan tidak ada konflik. menunjukkan adanya konflik.
Mode kunci yang diminta
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
Kunci Penasihat
Advisory lock adalah lock yang ditentukan aplikasi yang disediakan oleh PostgreSQL. Dalam sebagian besar kasus penggunaan Hologres, Anda tidak perlu khawatir tentang advisory lock.
Kunci BE
Kategori
Hologres menggunakan kategori lock BE berikut:
Kategori lock
Pengenalan Kunci
Eksklusif(X)
Sebuah transaksi meminta lock eksklusif, juga disebut lock saling eksklusif, untuk memodifikasi satu atau beberapa entri data. Misalnya, pernyataan Data Manipulation Language (DML) seperti DELETE, INSERT, dan UPDATE memerlukan lock eksklusif. Lock eksklusif hanya dapat diberikan pada resource jika tidak ada lock bersama (shared) atau eksklusif lainnya yang ada. Setelah lock eksklusif diberikan, tidak ada lock lain yang dapat ditempatkan pada resource tersebut.
Bersama(S)
Sebuah transaksi meminta lock bersama untuk membaca satu atau beberapa entri data. Lock ini mencegah transaksi lain memodifikasi data tersebut. Sebuah resource dapat memiliki beberapa lock bersama. Oleh karena itu, beberapa pernyataan Data Query Language (DQL) dapat dieksekusi pada resource tersebut secara bersamaan, karena pernyataan DQL tidak mengubah resource.
Niat(I)
Lock intent mendefinisikan hierarki lock. Sebuah resource tunggal dapat memiliki beberapa lock intent. Setelah sebuah resource memiliki lock intent, tidak ada lock eksklusif yang dapat ditempatkan padanya. Misalnya, jika sebuah transaksi meminta lock eksklusif pada sebuah baris, transaksi tersebut juga harus meminta lock intent pada tabelnya. Hal ini karena tabel merupakan resource tingkat lebih tinggi dibandingkan baris. Lock intent pada tabel mencegah transaksi lain menempatkan lock eksklusif padanya.
Timeout
Timeout default untuk lock BE adalah 5 menit. Error terjadi jika waktu tunggu lock melebihi durasi ini.
Konflik Hubungan
Tabel berikut menunjukkan konflik lock BE. Konflik berarti jika satu operasi memegang lock, operasi lain yang meminta lock yang bertentangan harus menunggu.
Catatanmenunjukkan tidak ada konflik. menunjukkan adanya konflik.
Operasi
DROP
ALTER
SELECT
UPDATE
DELETE
INSERT (termasuk INSERT ON CONFLICT)
DROP
ALTER
SELECT
UPDATE
DELETE
INSERT (termasuk INSERT ON CONFLICT)
Ruang lingkup kunci
Cakupan lock bervariasi tergantung jenis lock-nya.
Kunci FE
Lock FE hanya berlaku untuk objek tabel, bukan untuk data tabel. Lock ini memiliki dua status: berhasil atau macet. Status macet menunjukkan adanya konflik lock di mana operasi lain sedang menunggu.
Kunci BE
Lock BE berlaku untuk data atau skema tabel, sehingga menghasilkan tiga cakupan: lock data tabel, lock data baris, dan lock skema tabel.
Lock data tabel: Lock ini berlaku untuk semua data dalam sebuah tabel. Jika beberapa tugas meminta lock data tabel secara bersamaan, tugas-tugas tersebut akan masuk antrian, yang menyebabkan penundaan tugas.
Lock data baris: Lock ini diterapkan pada seluruh baris data dan memberikan efisiensi eksekusi yang lebih tinggi. Kueri yang dipercepat menggunakan fitur Fixed Plan untuk mempercepat eksekusi SQL memperoleh lock data baris atau lock skema tabel.
Lock skema tabel: Lock ini diperoleh saat transaksi membaca atau memodifikasi skema tabel. Sebagian besar transaksi memperoleh lock skema. Jenis utamanya sebagai berikut:
SchX: Lock eksklusif skema untuk pernyataan DDL. Saat ini, hanya perintah
DROP TABLEyang memperoleh lock ini.SchU: Lock SchU diperoleh oleh pernyataan DDL yang memodifikasi skema tabel, seperti perintah
ALTER TABLEdanset_table_property.SchE: Lock keberadaan skema yang digunakan oleh pernyataan DML dan DQL untuk memastikan bahwa tabel tidak dihapus selama operasi baca atau tulis.
CatatanSchU menyediakan kontrol DDL detail halus, yang memungkinkan DQL berjalan normal selama operasi ALTER TABLE tanpa perlu menunggu. SchX adalah lock eksklusif DDL paling kasar, dan semua operasi DDL, DML, serta DQL harus menunggu.
Jika fase Start Query memakan waktu lama, kueri tersebut mungkin sedang menunggu lock BE.
Tabel berikut menunjukkan cakupan lock untuk perintah umum Hologres. menunjukkan bahwa perintah tersebut memperoleh lock yang sesuai.
Operasi tulis, pembaruan, dan penghapusan yang tidak menggunakan Fixed Plan dianggap sebagai operasi bulkload.
Anda dapat menggunakan perintah
CREATE INDEXuntuk membuat indeks JSON.Pernyataan DDL mencakup
CREATE,DROP, danALTER.
Operasi dan Lingkup Kunci | Kunci Tingkat Tabel | Kunci Data Tabel | Kunci baris data | Kunci skema tabel |
CREATE | N/A | |||
DROP | Catatan Saat pernyataan `DROP` memperoleh lock, semua pernyataan lain yang sedang menunggu akan gagal setelah tabel dihapus. Catatan: | N/A | N/A | Catatan Operasi ini saling eksklusif dengan semua operasi lainnya. |
ALTER | Catatan Ini sama dengan perintah DROP. | N/A | N/A | Catatan Anda dapat menjalankan perintah |
SELECT | Catatan Pernyataan | N/A | N/A | Catatan Saat perintah |
INSERT (termasuk INSERT ON CONFLICT) | Catatan Pernyataan |
Catatan Pernyataan bulkload dan Fixed Plan saling eksklusif. | Sebuah pernyataan memperoleh lock data baris jika menggunakan Fixed Plan. Di Hologres V2.1 dan versi lebih baru, pernyataan bulkload yang dieksekusi pada tabel tanpa kunci utama hanya memperoleh kunci data baris. Catatan
| Catatan Lock ini bertentangan dengan pernyataan DDL dan DML. |
UPDATE | Catatan Lock ini bertentangan dengan | Catatan Lock ini bertentangan dengan pernyataan DDL dan DML. | ||
DELETE | Catatan Lock ini bertentangan dengan | Catatan Lock ini bertentangan dengan pernyataan DDL dan DML. | ||
Kunci terkait transaksi
Hologres hanya mendukung transaksi DDL eksplisit. Hologres tidak mendukung transaksi DML murni atau transaksi campuran DDL/DML.
Hologres tidak mendukung subtransaksi bersarang.
Transaksi DML murni lolos pemeriksaan sintaksis tetapi tidak mendukung komit atomik atau rollback.
Dalam contoh DML berikut, jika operasi
insertberhasil tetapi operasiupdateberikutnya gagal, data dari operasiinserttidak di-rollback.begin; insert into t1(id, salary) values (1, 0); update t1 set salary = 0.1 where id = 1; commit;Transaksi DDL murni berfungsi sebagaimana mestinya.
Jika salah satu pernyataan DDL gagal, seluruh transaksi di-rollback. Misalnya, jika pernyataan
ALTERberikut gagal, pernyataanCREATEdanDROPjuga di-rollback.begin; create table t1(i int); drop table if exists t2; alter table t1 add column n text; commit;Transaksi campuran DDL dan DML tidak diizinkan.
Dalam contoh berikut, menyertakan pernyataan DDL dan DML dalam satu transaksi menyebabkan pernyataan DML gagal.
begin; create table t1(i int); update t1 set i = 1 where i = 1; -- Kesalahan pernyataan DML ERROR: UPDATE dalam transaksi ddl tidak didukung saat ini.Lock yang diperoleh oleh perintah apa pun dalam transaksi eksplisit hanya dilepas ketika seluruh transaksi berakhir, baik melalui commit maupun rollback.
Misalnya, saat Anda melakukan operasi
ALTERpada tabel induk, lock ACCESS EXCLUSIVE diperoleh pada tabel induk (login_history) dan tabel anak (login_history_202001). Namun, lock tersebut tidak dilepas segera setelah perintah selesai. Sebaliknya, lock tersebut baru dilepas setelah perintahCOMMITakhir dieksekusi, terlepas dari apakah perintah tersebut berhasil atau gagal. Jika perintahCOMMITtidak pernah dieksekusi, lock tersebut akan dipegang tanpa batas. Dalam kasus ini, semua operasi DDL lain pada tabel tersebut akan diblokir dan menyebabkan error.-- misalkan kita memiliki tiga tabel 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;
Penyelesaian masalah lock FE
Anda dapat mengikuti langkah-langkah berikut untuk memeriksa dan menyelesaikan lock FE:
Jika kueri memerlukan waktu lama untuk dieksekusi, Anda dapat memeriksa bidang
wait_event_typeuntuk menentukan apakah kueri saat ini diblokir oleh lock.Dalam contoh perintah berikut, jika nilai bidang
wait_event_typedalam hasilnya adalahlock, kueri tersebut diblokir oleh lock FE.-- Hologres V2.0 dan versi lebih baru: 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; -- Hasil berikut dikembalikan: ----------------+---------------------------------------------------------------- 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 | {} + -- Hologres V1.3 dan sebelumnya: select datname, pid, application_name, wait_event_type, state,query_start, query from pg_stat_activity where backend_type in ('client backend'); -- Hasil berikut dikembalikan: ----------------+---------------------------------------------------------------- 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 xxxLihat pemilik lock.
Anda dapat menjalankan perintah berikut untuk melihat pemegang lock:
select * from pg_locks where pid = <pid>;Dalam perintah di atas, atur pid ke nilai
pidyang dikembalikan pada Langkah 1.Identifikasi proses yang memegang lock.
Jika Anda menentukan dari Langkah 2 bahwa pernyataan SQL saat ini memiliki lock, Anda dapat menggunakan perintah berikut dengan
oid-nya (relasi tabel) untuk memeriksa apakah lock sedang dipegang. Dalam perintah ini,tmerepresentasikantrue, yang menunjukkan bahwa lock sedang dipegang.-- Kueri proses yang memegang lock tabel. select pid from pg_locks where relation = <OID> and granted = 't';Identifikasi kueri yang memegang lock.
Menggunakan PID dari Langkah 3, Anda dapat menjalankan perintah berikut untuk menemukan kueri yang memegang lock tersebut.
select * from pg_stat_activity where pid = <PID>;Lepaskan lock.
Setelah Anda mengidentifikasi kueri yang memegang lock, Anda dapat menjalankan perintah berikut untuk menghentikan kueri tersebut dan melepaskan lock.
select pg_cancel_backend(<pid>);
Penyelesaian masalah lock BE
Jika bidang be_lock_waiters pada tampilan hg_stat_activity tidak kosong, kueri tersebut telah memperoleh lock BE atau sedang menunggu pelepasan lock BE di backend. Anda dapat menggunakan langkah-langkah berikut untuk memeriksa lock BE.
Tampilan hg_stat_activity hanya tersedia di Hologres V2.0 dan versi setelahnya.
Skenario 1: Kueri saat ini memegang lock sementara kueri lain menunggu pelepasannya.
Anda dapat menjalankan pernyataan SQL berikut untuk memeriksa apakah kueri saat ini memegang lock BE dan kueri mana yang menunggunya.
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 != ''; -- Hasil berikut dikembalikan: ----------------+------------------ query_id | 10005xxx transaction_id | 10005xxx be_lock_waiters | 13235xxxSkenario 2: Identifikasi kueri yang memblokir dan tunggu hingga lock dilepas.
Anda dapat menjalankan pernyataan SQL berikut untuk menemukan kueri yang memegang lock yang sedang ditunggu oleh kueri saat ini.
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"]
Pertanyaan Umum (FAQ)
Error:
internal error: Cannot acquire lock in time, current owners: [(Transaction =302xxxx, Lock Mode = SchS|SchE|X)]..Kemungkinan penyebab: Tabel yang sedang dikueri dikunci oleh kueri lain dengan lock BE. Hal ini menyebabkan kueri saat ini timeout setelah 5 menit. Misalnya, error
Lock Mode = SchS|SchE|Xmenunjukkan lock Stabilitas Skema, lock keberadaan, atau lock eksklusif.Solusi:
transactiondalam pesan error, sepertiTransaction =302xxxx, adalah ID kueri. Anda dapat menggunakan ID kueri tersebut untuk menemukan kueri yang memegang lock di log kueri lambat atau kueri aktif.
Error:
ERROR: The schema version update timed out because the server's current version (xxx) is older than the requested version (yyy).Kemungkinan penyebab: Setelah pernyataan DDL dieksekusi pada node FE, pernyataan tersebut dijalankan secara asinkron pada mesin penyimpanan (SE). Node FE segera memperbarui versinya setelah operasi DDL selesai. Jika SE belum menyelesaikan operasi DDL, versinya tertinggal dari versi FE. Kueri kemudian menunggu SE menyusul. Jika proses ini memakan waktu lebih dari 5 menit, error terjadi.
Solusi:
Hentikan pernyataan DDL yang sedang menunggu dan coba ulang kueri.
Restart instans. Ini hanya boleh digunakan sebagai upaya terakhir.
Error:
The requested table name: xxx (id: 10, version: 26) mismatches the version of the table (id: 10, version: 28) from server.Kemungkinan penyebab: Operasi DDL pertama kali dijalankan pada satu node FE, lalu secara asinkron pada SE. SE menyelesaikan operasi dan memperbarui versinya, tetapi replikasi di beberapa node FE belum selesai. Beberapa node FE memiliki versi lama. Jika kueri Anda diarahkan ke salah satu node tersebut, error terjadi.
Solusi:
Coba ulang kueri beberapa kali.
Jika error tetap muncul setelah beberapa menit, restart instans.
Error:
internal error: Cannot find index full ID: 86xxx (table id: 20yy, index id: 1) in storages or it is deleting!.Kemungkinan penyebab: Saat operasi
DROP TableatauTruncate Tabledieksekusi, operasi tersebut memperoleh lock DDL pada tabel. Kueri DML, seperti SELECT atau DELETE, pada tabel yang sama harus menunggu lock tersebut. Setelah operasi DDL selesai dan tabel dihapus, kueri yang sedang menunggu gagal dan melaporkan error.Solusi: Jangan mengeksekusi kueri lain pada tabel saat Anda menjalankan perintah
DROPatauTRUNCATEpada tabel tersebut.