ข้อความถอดรหัสเชิงตรรกะของการคอมมิตสองเฟสใน PostgreSQL 14

อัปเดต: 2 กรกฎาคม 2023

ข้อความถอดรหัสเชิงตรรกะของการคอมมิตสองเฟสใน 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 และเป็นหนึ่งในแนวทางสำหรับการปรับปรุงในอนาคต

  ลิงค์:

6mbi25l-120

500uz-2h