Rumah > Artikel > pangkalan data > Analisis contoh penyelesaian masalah kebuntuan mysql
Masalah muncul
Pada suatu petang, tiba-tiba sistem membimbangkan dan mengeluarkan pengecualian:
Melihat lebih dekat seolah-olah pengecualian rollback transaksi Ia mengatakan bahawa ia telah dibatalkan kerana kebuntuan Ia ternyata menjadi masalah kebuntuan Memandangkan saya masih mempunyai pemahaman tertentu tentang kunci Mysql, saya mula menyiasat masalah ini secara proaktif .
Mula-mula, cari Status Innodb dalam pangkalan data Innodb Status akan merekodkan maklumat kebuntuan terakhir Masukkan arahan berikut:
PANCANGKAN STATUS INNODB ENJIN
Maklumat kebuntuan adalah seperti berikut, dan maklumat sql telah diproses secara ringkas:
-----------------------
DEADLOCK TERKINI DIKESAN
-----------------------
22-02-2019 15:10:56 0x7eec2f468700
*** (1) TRANSAKSI:
TRANSAKSI 2660206487, AKTIF 0 saat indeks permulaan dibaca
jadual mysql digunakan 1, dikunci 1
LOCK WAIT 2 struct (s) kunci, saiz timbunan 1136, 1 row lock (s)
Id benang MySQL 31261312, pemegang benang OS 139554322093824, id pertanyaan 11624975750 10.23.134.92 erp_crm__6f73 mengemas kini
/*id:3637ba36*/KEMASKINI SET konfigurasi_penyewa
open_card_point = 0
di mana tenant_id = 123
*** (1) MENUNGGU KUNCI INI DIBERIKAN:
REKOD LOCKS id ruang 1322 halaman no 534 n bit 960 indeks uidx_penyewa jadual ——erp_crm_member_plan——. ——tenant_config—— trx id 2660206487 lock_mode X mengunci rec tetapi bukan celah menunggu
*** (2) TRANSAKSI:
TRANSAKSI 2660206486, AKTIF 0 saat indeks permulaan dibaca
jadual mysql digunakan 1, dikunci 1
3 struktur kunci, saiz timbunan 1136, kunci 2 baris
Id benang MySQL 31261311, pemegang benang OS 139552870532864, id pertanyaan 11624975758 10.23.134.92 erp_crm__6f73 mengemas kini
/*id:3637ba36*/KEMASKINI SET konfigurasi_penyewa
open_card_point = 0
di mana tenant_id = 123
*** (2) MEMEGANG KUNCI (S):
REKOD LOCKS id ruang 1322 halaman no 534 n bit 960 indeks uidx_penyewa jadual ——erp_crm_member_plan——. ——tenant_config—— trx id 2660206486 mod kunci S
*** (2) MENUNGGU KUNCI INI DIBERIKAN:
REKOD LOCKS id ruang 1322 halaman no 534 n bit 960 indeks uidx_penyewa jadual ——erp_crm_member_plan——. ——tenant_config—— trx id 2660206486 lock_mode X mengunci rec tetapi bukan celah menunggu
*** KAMI GULUNG BALIK TRANSAKSI (1)
----------------
Biar saya menganalisis secara ringkas dan menerangkan log kebuntuan ini Apabila transaksi 1 melaksanakan pernyataan Kemas kini, ia perlu mendapatkan indeks uidx_tenant dan kemudian kunci X (kunci baris) pada keadaan tempat 2 melaksanakan pernyataan Kemas kini yang sama dan juga memikirkannya uidx_tenant Untuk memperoleh kunci X (kunci baris), jalan buntu berlaku dan transaksi 1 telah ditarik balik. Saya sangat keliru pada masa itu dan teringat keadaan yang diperlukan untuk kebuntuan berlaku:
Saling eksklusif.
Meminta dan menahan syarat.
Tiada kekurangan syarat.
Kitaran menunggu. Daripada log, dapat dilihat bahawa kedua-dua transaksi 1 dan transaksi 2 bersaing untuk kunci baris bagi baris yang sama Ini sedikit berbeza daripada persaingan kitaran sebelumnya untuk kunci Tidak kira bagaimana anda melihatnya, mereka tidak dapat memuaskan keadaan menunggu bulat. Selepas diingatkan oleh rakan sekerja, memandangkan log kebuntuan tidak boleh disiasat, masalah itu hanya boleh disiasat daripada kod perniagaan dan log perniagaan. Logik kod ini adalah seperti berikut:
public int saveTenantConfig(PoiContext poiContext, TenantConfigDO tenantConfig) {
cuba {
kembalikan tenantConfigMapper.saveTenantConfig(poiContext.getTenantId(), poiContext.getPoiId(), tenantConfig);
} tangkapan (DuplicateKeyException e) {
LOGGER.warn("[saveTenantConfig] konflik kunci utama, kemas kini rekod. konteks:{}, konfigurasi:{}", poiContext, tenantConfig);
kembalikan tenantConfigMapper.updateTenantConfig(poiContext.getTenantId(), tenantConfig);
}
}
Maksud kod ini adalah untuk menyimpan fail konfigurasi Jika konflik indeks unik berlaku, sudah tentu, penulisan di sini mungkin tidak sangat standard, anda boleh menggunakan
masukkan ke dalam …
pada kemas kini kunci pendua
Kesan yang sama boleh dicapai, tetapi walaupun ini digunakan, kebuntuan sebenarnya akan berlaku. Selepas membaca kod tersebut, rakan sekerja saya menghantar log perniagaan kepada saya pada masa itu,
Anda boleh melihat bahawa terdapat tiga log yang berlaku pada masa yang sama, menunjukkan bahawa konflik indeks unik telah berlaku dan memasuki pernyataan yang dikemas kini, dan kemudian kebuntuan berlaku. Pada ketika ini jawapan akhirnya kelihatan sedikit lebih jelas.
Pada masa ini, mari lihat struktur jadual kami seperti berikut (dipermudahkan):
BUAT JADUAL ——tenant_config——
——id—— bigint(21) BUKAN NULL AUTO_INNCREMENT,
——tenant_id—— int(11) BUKAN NULL,
——open_card_point—— int(11) NULL,
KUNCI UTAMA (——id——),
KUNCI UNIK ——uidx_tenant—— (——tenant_id——)
) ENGINE=CHARSET LAALA InnoDB=utf8mb4 ROW_FORMAT=COMPACT
tenant_id kami digunakan sebagai indeks unik, dan sisipan serta kemas kini kami di mana keadaan semuanya berdasarkan indeks unik.
KEMASKINI SET tenant_config
open_card_point = 0
di mana tenant_id = 123
Pada ketika ini, saya merasakan bahawa mengunci indeks unik semasa sisipan adalah berkaitan. Seterusnya, kami akan menjalankan analisis yang mendalam dalam langkah seterusnya.
Analisis mendalam
Di atas kami mengatakan bahawa tiga transaksi memasukkan penyata kemas kini Untuk memudahkan penjelasan, kami hanya memerlukan dua transaksi untuk memasukkan penyata kemas kini pada masa yang sama Jadual berikut menunjukkan keseluruhan proses kejadian kami:
Petua: Kunci S ialah kunci kongsi, kunci X ialah kunci pengecualian bersama. Secara umumnya, kunci X, kunci S dan kunci X adalah saling eksklusif, tetapi kunci S dan kunci S tidak saling eksklusif.
Daripada proses di atas, kita melihat bahawa kunci kepada kebuntuan ini adalah untuk memperoleh kunci S Mengapa kita perlu memperoleh kunci S apabila memasukkan semula? Kerana kita perlu mengesan indeks unik? Di bawah tahap pengasingan RR, jika anda ingin membaca, ia adalah bacaan semasa, jadi anda sebenarnya perlu menambah kunci S. Didapati di sini bahawa kunci unik sudah wujud Pada masa ini, pelaksanaan kemas kini akan disekat oleh kunci S bagi kedua-dua transaksi, dengan itu membentuk keadaan menunggu gelung di atas.
Petua: Dalam MVCC, perbezaan antara bacaan semasa dan bacaan syot kilat: bacaan semasa perlu dikunci setiap kali (anda boleh menggunakan kunci kongsi atau kunci mutex) untuk mendapatkan data terkini, manakala bacaan syot kilat membaca transaksi yang bermula Pada masa itu, syot kilat telah dilaksanakan melalui log asal.
Ini adalah sebab untuk keseluruhan kebuntuan Satu lagi situasi di mana kebuntuan jenis ini boleh berlaku ialah terdapat tiga operasi sisipan pada masa yang sama Jika transaksi yang dimasukkan dahulu digulung semula pada akhirnya, ini juga akan berlaku kepada dua yang lain urus niaga.
Penyelesaian
Masalah utama di sini adalah untuk menghilangkan kunci S Berikut adalah tiga penyelesaian untuk rujukan:
Kurangkan tahap pengasingan RR kepada tahap pengasingan RC. Di sini, tahap pengasingan RC akan menggunakan bacaan syot kilat, jadi tiada kunci S akan ditambahkan.
Apabila memasukkan semula, gunakan pilih * untuk kemas kini untuk menambah kunci X, supaya kunci S tidak akan ditambah.
Anda boleh menambah kunci yang diedarkan terlebih dahulu, anda boleh menggunakan Redis, atau ZK, dll. Untuk kunci yang diedarkan, sila rujuk artikel saya ini. Mari bercakap tentang kunci yang diedarkan
Kaedah pertama tidak begitu realistik, lagipun, tahap pengasingan tidak boleh diubah suai dengan mudah. Kaedah ketiga lebih menyusahkan. Jadi kaedah kedua adalah apa yang akhirnya kami selesaikan.
Atas ialah kandungan terperinci Analisis contoh penyelesaian masalah kebuntuan mysql. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!