Postgres Giao dịch OOM trên các báo cáo DDL 100k


7

Chúng tôi thực hiện khoảng 100 nghìn câu lệnh DDL trong một giao dịch trong PostgreSQL. Trong quá trình thực thi, kết nối Postgres tương ứng tăng dần về mức sử dụng bộ nhớ của nó và một khi nó không thể có thêm bộ nhớ (tăng từ 10MB lên 2.2GB trên ram 3GB), kẻ giết người OOM đánh nó với 9 kết quả là Postgres bị chuyển sang chế độ phục hồi .

BEGIN;

CREATE SCHEMA schema_1;
-- create table stmts - 714
-- alter table add pkey stmts - 714
-- alter table add constraint fkey stmts - 34
-- alter table add unique constraint stmts - 2
-- alter table alter column set default stmts - 9161
-- alter table alter column set not null stmts - 2405
-- alter table add check constraint stmts - 4
-- create unique index stmts - 224
-- create index stmts - 213

CREATE SCHEMA schema_2;
-- same ddl statements as schema_1 upto schema_7
-- ...
-- ...
-- ...
CREATE SCHEMA schema_7;

COMMIT

Bao gồm câu lệnh tạo lược đồ, khoảng 94304 câu lệnh DDL có nghĩa là được thực thi.

Theo DDL giao dịch trong PostgreSQL

Giống như một số đối thủ cạnh tranh thương mại khác, một trong những tính năng nâng cao hơn của PostgreSQL là khả năng thực hiện DDL giao dịch thông qua thiết kế Nhật ký Viết trước. Thiết kế này hỗ trợ sao lưu các thay đổi lớn đối với DDL, chẳng hạn như tạo bảng. Bạn không thể khôi phục từ một thêm / thả trên cơ sở dữ liệu hoặc không gian bảng, nhưng tất cả các hoạt động danh mục khác đều có thể đảo ngược.

Chúng tôi thậm chí đã nhập khoảng 35GB dữ liệu vào PostgreSQL trong một giao dịch mà không gặp vấn đề gì, nhưng tại sao kết nối Postgres lại cần bộ nhớ lớn khi thực hiện hàng ngàn câu lệnh DDL trong một giao dịch?

Chúng tôi có thể giải quyết tạm thời bằng cách tăng RAM hoặc phân bổ trao đổi, nhưng chúng tôi có thể nói rằng số lần tạo lược đồ trong một giao dịch có thể tăng lên tới 50 - 60 (khoảng 1 triệu câu lệnh DDL) sẽ cần hơn 100 Gigs RAM hoặc trao đổi mà không khả thi ngay bây giờ.

Phiên bản PostgreSQL: 9.6.10

Có bất kỳ lý do tại sao thực hiện nhiều câu lệnh DDL đòi hỏi nhiều bộ nhớ hơn trong khi câu lệnh dml không? Không phải cả hai đều xử lý các giao dịch bằng cách viết vào WAL bên dưới sao? Vậy tại sao, đối với DLL thì khác?

Lý do giao dịch đơn

Chúng tôi đồng bộ hóa toàn bộ cơ sở dữ liệu của khách hàng từ Tiền đề khách hàng (Máy chủ SQL) sang đám mây (PostgreQuery). Tất cả các khách hàng không có cơ sở dữ liệu khác nhau. Quá trình là, toàn bộ dữ liệu sẽ được tạo dưới dạng CSV từ SQL Server và nhập vào PostgreQuery bằng cách sử dụng Bảng tạm thời, SAO CHÉP và TRÊN CONFLICT DO CẬP NHẬT. Trong quá trình này, chúng tôi coi mỗi khách hàng là một cơ sở dữ liệu duy nhất trong PG và DB riêng lẻ trong SQL Server của khách hàng như các lược đồ trong PG DB của khách hàng.

Vì vậy, dựa trên dữ liệu CSV, chúng tôi sẽ tạo các lược đồ động và nhập dữ liệu vào đó. Theo thiết kế ứng dụng của chúng tôi, dữ liệu trong PG phải hoàn toàn nhất quán tại bất kỳ thời điểm nào và không nên có bất kỳ lược đồ / bảng / dữ liệu nào. Vì vậy, chúng tôi đã phải đạt được điều này trong một giao dịch duy nhất. Ngoài ra, chúng tôi tăng dần đồng bộ hóa từ khách hàng lên đám mây DB cứ sau 3 phút. Vì vậy, việc tạo lược đồ có thể xảy ra trong đồng bộ hóa đầu tiên hoặc đồng bộ hóa gia tăng. Nhưng xác suất tạo ra rất nhiều lược đồ trong lần đầu tiên đồng bộ hóa là rất cao.

Cập nhật 1

Nhận xét các ALTER TABLE ALTER COLUMNcâu lệnh làm giảm đáng kể việc sử dụng bộ nhớ vì giờ đây chỉ mất tối đa 300 MB. Phải hợp nhất những điều đó vào chính các CREATE TABLEtuyên bố.

Sẽ hỏi vấn đề cốt lõi trong danh sách gửi thư của PG Hackers.


1
Là câu lệnh CREATE DATABASE được ban hành tự động như một phần của quy trình đồng bộ hóa đầu tiên (rõ ràng không phải là một phần của cùng một giao dịch, vì CREATE DATABASEkhông thể được thực thi trong một khối giao dịch ) hoặc được thực hiện trong một quy trình riêng biệt? Câu hỏi liên quan (có thể là viết lại câu hỏi trước): làm thế nào để ứng dụng nhận biết về một khách hàng mới / cơ sở dữ liệu mới?
Andriy M

3
Bạn có thể sửa đổi quy trình tạo DDL để loại bỏ các câu lệnh ALTER COLUMN bằng cách điều chỉnh các câu lệnh CREATE TABLE không? Điều đó sẽ loại bỏ khoảng 11,5 nghìn câu lệnh, chỉ cho lược đồ đầu tiên.
ypercubeᵀᴹ

1
Một cách độc lập, bạn có thể đặt mỗi lược đồ trong một giao dịch riêng biệt.
ypercubeᵀᴹ

5
Bạn có thể giảm đáng kể số lượng câu lệnh ddl bằng cách đóng gói nhiều mệnh đề vào một câu lệnh thay đổi bảng duy nhất cho cùng một bảng ...
Erwin Brandstetter

@AndriyM tạo cơ sở dữ liệu được thực thi trong một quy trình riêng biệt. Tạo khách hàng là một quá trình riêng biệt. Chúng tôi duy trì thông tin khách hàng và các thuộc tính kết nối theo cách phân tán (etcd)
Bộ giải mã

Câu trả lời:


4

Một ý tưởng tốt hơn hoàn toàn là sử dụng SQL Server FDW thực sự có logic để kéo Microsoft SQL Server sang định dạng PostgreQuery (ví dụ: Bitđược ánh xạ tới Bool). Từ điểm này

Sau đó cứ sau ba phút,

  • bạn nhập lược đồ nước ngoài vào last_fetch_schema
  • nếu last_fetch_schemakhác vớilocal_schema
    • bạn đồng bộ lại lược đồ
  • bạn sao chép tất cả dữ liệu qua một INSERT INTO ... SELECT ON CONFLICT DO UPDATEvà bạn chỉ có thể chọn dữ liệu mới nhất.
  • bạn bỏ lược đồ nước ngoài last_fetch_schema

Bạn đạt được gì?

  • Trong lần tải đầu tiên, bạn chỉ cần sử dụng CREATE TABLE local.foo ( LIKE foreign.foo)
  • Bạn có thể dễ dàng so sánh sự khác biệt của siêu dữ liệu
  • CSV mất các loại và khiến bạn phải suy luận mọi thứ, FDW có thể đọc danh mục siêu dữ liệu.
  • Chỉ lấy những thứ mới nhất rất đơn giản nếu các hàng được phiên bản / bạn không phải gửi toàn bộ cơ sở dữ liệu nữa.

Đó là một gợi ý tốt. Nhưng không phải máy chủ SQL của mọi người đều có thể truy cập qua internet. Khách hàng không bị hạn chế trong các kết nối ra ngoài, nhưng hầu hết các khách hàng đều gặp khó khăn trong việc định cấu hình Kết nối trong nước (đây chỉ là một trường hợp, cũng có các trường hợp khác như db / bảng / tạo / xóa / sửa đổi trong bản vá tiền đề, v.v.). Dựa trên khối lượng khách hàng, điều này không khả thi / có thể mở rộng cho chúng tôi.
Bộ giải mã

Thông thường bạn làm điều này với VPN. Tôi chỉ có một cảm giác mạnh mẽ là bạn đang sủa sai cây, nhưng chúc may mắn với nó. Có rất nhiều giải pháp khác phụ thuộc vào số lượng công việc bạn muốn đưa vào đó. =)
Evan Carroll

3

Một chút bình luận trong src / backend / utils / cache / relcache.c có vẻ phù hợp:

    * If we Rebuilt a relcache entry during a transaction then its
    * possible we did that because the TupDesc changed as the result
    * of an ALTER TABLE that ran at less than AccessExclusiveLock.
    * It's possible someone copied that TupDesc, in which case the
    * copy would point to free'd memory. So if we rebuild an entry
    * we keep the TupDesc around until end of transaction, to be safe.
    */
    if (remember_tupdesc)
        RememberToFreeTupleDescAtEOX(relation->rd_att);

Tôi không thực sự hiểu nó, vì "ai đó" có thể có một con trỏ là ai? Đây là bộ nhớ riêng, không chia sẻ bộ nhớ. Dù sao, nó dường như giải thích sự phình to, vì mọi tuyên bố 'thay đổi bảng' trong cùng một giao dịch đều để lại một bản sao khác của TupDesc ​​cho bảng đó. Và rõ ràng, ngay cả khi bạn sử dụng nhiều hành động trong một alter table, mỗi hành động riêng biệt cũng để lại một bản sao. Nhưng bất kể giá trị nào, điều này không giải thích được phần lớn việc sử dụng bộ nhớ.

Xem các tin tặc tin tặc pg để thảo luận thêm.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.