ข้อความถอดรหัสเชิงตรรกะของการคอมมิตสองเฟสใน PostgreSQL 14
ทีมงาน Fujitsu OSS และชุมชนโอเพ่นซอร์ส PostgreSQL ได้ร่วมมือกันเพื่อเพิ่มฟังก์ชันการถอดรหัสการคอมมิตแบบสองเฟสในการจำลองแบบลอจิคัลใน PG14 มาดูกันว่าฟีเจอร์นี้คืออะไร?
พื้นหลัง
การคอมมิตแบบสองเฟสเป็นกลไกที่การทำธุรกรรมเกิดขึ้นในสองขั้นตอน มักใช้ในฐานข้อมูลแบบกระจายเพื่อให้แน่ใจว่ามีความสอดคล้องกัน สองเฟสของธุรกรรมคือเฟส PREPARE และเฟส COMMIT/ROLLBACK คำสั่งที่ส่งในสองขั้นตอนใน PG คือ:
เตรียมธุรกรรม
มุ่งมั่นเตรียมการ
เตรียมย้อนกลับ
PG รองรับการคอมมิตสองเฟสในเวอร์ชัน 8.0 แล้ว และเวอร์ชัน 10.0 รองรับการจำลองแบบลอจิคัล อย่างไรก็ตาม การคอมมิตแบบสองเฟสไม่เคยได้รับการสนับสนุนในการจำลองแบบลอจิคัล คำสั่ง PREPARE TRANSACTION, COMMIT PREPARED และ ROLLBACK PREPARED ได้รับการสนับสนุนในอินสแตนซ์เดียว แต่เมื่อคำสั่งเหล่านี้จำเป็นต้องคัดลอกตามตรรกะไปยังเครื่องสแตนด์บาย คำสั่งเหล่านี้จะไม่คงความหมายดั้งเดิมไว้อีกต่อไป คำสั่ง PREPARE TRANSACTION จะถือเป็น NOP และไม่มีการถอดรหัสเลย คำสั่ง COMMIT PREPARED ถือเป็น COMMIT และคำสั่ง ROLLBACK PREPARED จะถือเป็น ABORT
คอมมิตสองเฟสคืออะไร
การคอมมิตแบบสองเฟสเป็นโปรโตคอลการคอมมิตแบบอะตอมที่ช่วยรักษาความสอดคล้องระหว่างฐานข้อมูลแบบกระจาย การคอมมิตธรรมดาที่ให้อะตอมมิกในฐานข้อมูลนั้นไม่เพียงพอที่จะทำให้มีความสอดคล้องกันสำหรับธุรกรรมข้ามฐานข้อมูล เพื่อแสดงปัญหานี้ ให้ยกตัวอย่าง:
1) จอห์นมี 300$ ในธนาคาร A
2) มาร์คมี 100$ ในธนาคาร B
3) John ต้องการโอน 100$ ให้ Mark
ระหว่างการทำธุรกรรม คุณต้องถอนเงิน 100$ จากธนาคาร A ไปยังธนาคาร B ในตอนท้ายของธุรกรรม ควรมี 200$ หากธุรกรรมใดล้มเหลวในระหว่างกระบวนการโอน สถานะบัญชีควรถูกเรียกคืนเป็นสถานะก่อนเริ่มการโอน การทำธุรกรรมอาจล้มเหลวด้วยเหตุผลหลายประการ หากเกิดการหยุดชะงักก่อนทำธุรกรรม ธุรกรรมจะถูกย้อนกลับ ในตัวอย่างของเรา หากการหยุดชะงักเกิดขึ้นเมื่อบัญชีของ John ถูกหัก บัญชีของ John เกี่ยวกับพอร์ตการหยุดชะงักก็ไม่ควรลดลง นี่เป็นวิธีที่คอมมิทแบบธรรมดารักษาความสอดคล้องภายในฐานข้อมูล
แต่เราพิจารณาสถานการณ์ดังกล่าว นั่นคือ ธุรกรรมที่หัก 100$ จากบัญชีของ John นั้นสำเร็จในการส่งครั้งเดียว แต่ธุรกรรมที่เพิ่ม 100$ ในบัญชีของ Mark ใน Bank B ล้มเหลวและถูกย้อนกลับ หลังจากการดำเนินการนี้สิ้นสุดลง แม้ว่าบัญชีของ John จะถูกหักแล้ว แต่ Mark จะไม่ได้รับเงินจำนวนนั้น 100$ หายไป เมื่อจัดการกับธุรกรรมแบบกระจาย การคอมมิตแบบธรรมดาอาจล้มเหลว
การดำเนินการทีละขั้นตอนของธุรกรรมแบบกระจาย
สำหรับการคอมมิตแบบสองเฟส หนึ่งในฐานข้อมูลจะทำหน้าที่เป็นผู้ประสานงานของธุรกรรมแบบกระจาย
1 เวที
ฐานข้อมูลเริ่มใช้ธุรกรรม และเตรียมการ มันส่งธุรกรรมที่เตรียมไว้ไปยังฐานข้อมูลอื่นในรูปแบบของการเตรียมข้อความ ฐานข้อมูลที่สองได้รับข้อความเตรียม จากนั้นจึงเตรียมธุรกรรม การจัดเตรียมเกี่ยวข้องกับการเปลี่ยนแปลงในการทำธุรกรรมแต่ไม่กระทำการ ข้อมูลสกปรกถูกเขียนลงดิสก์เพื่อความคงอยู่ เมื่อฐานข้อมูลทั้งหมดได้เตรียมธุรกรรม และข้อมูลทั้งหมดเกี่ยวกับธุรกรรมถูกจัดเก็บไว้ในดิสก์ ขั้นตอนการเตรียมจะเสร็จสมบูรณ์
2 เวที
ถัดไป ผู้ตัดสินจะเริ่มขั้นตอนการส่งคำสั่ง ถ้าฐานข้อมูลที่สองล้มเหลวในการเตรียมธุรกรรมด้วยเหตุผลบางประการ ผู้ตัดสินจะเริ่มขั้นตอนการย้อนกลับ ดังนั้น ขึ้นอยู่กับว่าการเตรียมการสำเร็จหรือไม่ ธุรกรรมมีความมุ่งมั่นหรือย้อนกลับ การหยุดชะงักในเฟสการคอมมิตสุดท้ายสามารถกู้คืนได้ เนื่องจากธุรกรรมการจัดเตรียมที่จำเป็นได้ถูกเขียนลงดิสก์แล้วและสามารถนำกลับมาใช้ใหม่ได้
การคอมมิตแบบสองเฟสไม่เกี่ยวข้องกับฐานข้อมูลอินสแตนซ์เดียว แต่มีความเกี่ยวข้องเมื่อมีการจำลองข้อมูลข้ามอินสแตนซ์ฐานข้อมูลหลายรายการ
สิ่งสำคัญคือต้องสนับสนุนการคอมมิตแบบสองเฟสในการจำลองแบบลอจิคัล
ภาพรวมการทำงาน
ก่อนเวอร์ชัน PG14 ธุรกรรมการจำลองแบบลอจิคัลจะถูกถอดรหัสและจำลองแบบหลังจากทำธุรกรรมแล้วเท่านั้น ทั้งนี้เพื่อหลีกเลี่ยงไม่ให้ธุรกรรมการจำลองแบบอาจถูกยกเลิกในที่สุด
ถอดรหัสธุรกรรมบนคอมมิต
การจำลองแบบลอจิคัลของ PG14 รองรับคำสั่ง PREPARE TRANSACTION, COMMIT PREPARED และ ROLBACK PREPARED เมื่อคำสั่ง PREPARE TRANSACTION ถูกถอดรหัส ธุรกรรมจะถูกถอดรหัสและคัดลอก PREPARE TRANSACTION เริ่มเล่นซ้ำธุรกรรมและถอดรหัสเหมือนกับ COMMIT ใน WAL SENDER
ถอดรหัสรายการระหว่างเตรียม
เรายังกำหนดการโทรกลับของปลั๊กอินใหม่เพื่อให้อนุญาตการถอดรหัสปลั๊กอินเพื่อรองรับการส่งแบบสองเฟส
โทรกลับ
บรรยาย
ตัวกรอง_เตรียม_cb
อนุญาตให้ปลั๊กอินกรองธุรกรรมที่ไม่จำเป็นต้องถอดรหัสเมื่อเตรียมตาม GID ที่ใช้ในคำสั่ง PREPARE TRANSACTION
เริ่มต้น_เตรียม_cb
เริ่มเตรียมรายการ
เตรียม_cb
เรียกเมื่อคำสั่ง PREPARE TRANSACTION ถูกถอดรหัส
กระทำ_เตรียมไว้_cb
เรียกเมื่อคำสั่ง COMMIT PREPARED ถูกถอดรหัส
ย้อนกลับ_เตรียมไว้_cb
เรียกเมื่อคำสั่ง ROLLBACK PREPARED ถูกถอดรหัส
การปรับเปลี่ยนปลั๊กอิน
ทดสอบ_ถอดรหัส
ปลั๊กอินเป็นปลั๊กอินเอาต์พุตการถอดรหัสเชิงตรรกะ เป็นตัวอย่างเพื่อช่วยให้ผู้ใช้พัฒนาปลั๊กอินถอดรหัสเชิงตรรกะของตนเอง test_decoding ได้รับ WAL ผ่านกลไกการถอดรหัสเชิงตรรกะ และถอดรหัสเป็นการแสดงข้อความของการดำเนินการที่ดำเนินการ
ได้รับการแก้ไขเพื่อให้สามารถใช้ฟังก์ชันเรียกกลับแบบสองขั้นตอนใหม่และถอดรหัสธุรกรรมระหว่างการเตรียมการได้
การปรับเปลี่ยน API
pg_create_ตรรกะ_การจำลอง_สล็อต()
API เพิ่มตัวเลือกใหม่เพื่อระบุว่าสล็อตรองรับการคอมมิตแบบสองเฟสหรือไม่ ปลั๊กอินเอาท์พุตสามารถใช้สล็อตการจำลองแบบที่มีตัวเลือกแบบสองเฟสเพื่อรองรับการคอมมิตแบบสองเฟส
pg_create_logical_replication_slot (ชื่อสล็อต, ชื่อปลั๊กอิน [, บูลีนชั่วคราว, บูลีนสองเฟส ] )
กรณีศึกษา
มาดูวิธีการตรวจหาเอาต์พุตที่ถอดรหัสของธุรกรรมการคอมมิตสองเฟส:
1) สร้างช่องการจำลองแบบ
ใช้ test_decoding เป็นเอาต์พุตปลั๊กอิน และส่งต่อเป็น true เพื่อให้สล็อตสนับสนุนการส่งและถอดรหัสแบบสองขั้นตอน
postgres=# SELECT * FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding',false,true);
slot_name | lsn
- -
การถดถอย_สล็อต | 0/16B1970
(1 แถว)
2) สร้างตาราง
postgres=# CREATE TABLE data (รหัสซีเรียลคีย์หลัก ข้อความข้อมูล)
สร้างตาราง
3) ตรวจจับเนื้อหาเอาต์พุตที่ถอดรหัสของการเตรียมธุรกรรมและดำเนินการธุรกรรม
โพสเกรส=# BEGIN;
postgres=*# INSERT INTO data(data) ค่า('5');
postgres=*# เตรียมการทำธุรกรรม 'test_prepared1';
postgres=# เลือก * จาก pg_ตรรกะ_สล็อต_รับ_การเปลี่ยนแปลง ('การถดถอย_สล็อต', NULL, NULL);
lsn | xid | data
- - - - - - - - - - - - - -
0/1689DC0 | 529 | เริ่มต้น 529
0/1689DC0 | 529 | ตารางสาธารณะ.data: INSERT: id[integer]:3 data[text]:'5'
0/1689FC0 | 529 | เตรียมการทำธุรกรรม 'test_prepared1', txid 529
(3 แถว)
postgres=# เตรียมคอมมิชชัน ' ทดสอบ_ เตรียมพร้อม 1';
postgres=# เลือก * จาก pg_logical_slot_get_changes('regression_slot', NULL, NULL);
lsn | xid | data
- - - - - - - - - - - - - - -
0/168A060 || 529 | COMMIT PREPARED 'test_prepared1', txid 529
(4 แถว)
postgres=# เลือก * จากข้อมูล;
id | ข้อมูล
เชอะ
1 | 5
(1 แถว)
อนาคต
การเปลี่ยนแปลงฟังก์ชันนี้ของ PG14 มีโครงสร้างพื้นฐานด้านตัวถอดรหัสที่อนุญาตให้ส่งการถอดรหัสแบบสองขั้นตอนระหว่างการเตรียมการ นอกจากนี้เรายังแก้ไขปลั๊กอิน test_decoding เพื่อใช้ประโยชน์จากโครงสร้างพื้นฐานนี้
ขั้นตอนต่อไปคือการปรับใช้การสนับสนุนสองขั้นตอนกับปลั๊กอินถอดรหัสลอจิคัลที่ใหญ่ที่สุดในปลั๊กอิน PG-the pgoutput ปลั๊กอินนี้สนับสนุนโหมด PUBLISHER/SUBSCRIBER ของการจำลองแบบลอจิคัล เป็นปลั๊กอินที่ใช้กันอย่างแพร่หลายในการจำลองแบบลอจิคัล ทีมงาน Fujitsu OSS กำลังทำงานร่วมกับชุมชนโอเพ่นซอร์สเพื่อเพิ่มคุณลักษณะนี้ใน PG15
สำหรับธุรกรรมสองเฟสในฐานข้อมูลแบบกระจาย PG ยังต้องการการสนับสนุน: เครื่องสแตนด์บายจะแจ้งโฮสต์ว่า PREPARE ล้มเหลวและเริ่มการย้อนกลับ กลไกป้อนกลับนี้ไม่ได้รับการสนับสนุนใน PG และเป็นหนึ่งในแนวทางสำหรับการปรับปรุงในอนาคต
ลิงค์: