1.1 Phân mảnh là gì?

Nếu bạn kiên trì google, thì hóa ra có một ranh giới khá mờ giữa cái gọi là phân vùng và cái gọi là sharding. Ai cũng gọi thế nào cũng được, muốn thế nào cũng được. Một số người phân biệt giữa phân vùng ngang và sharding. Những người khác nói rằng sharding là một loại phân vùng ngang nhất định.

Tôi không tìm thấy một tiêu chuẩn thuật ngữ nào được những người sáng lập chấp thuận và được chứng nhận bởi ISO. Niềm tin nội tâm của cá nhân là như thế này: Phân vùng trung bình là “cắt cơ sở thành từng mảnh” theo cách tùy tiện.

  • Phân vùng dọc - theo cột. Ví dụ: có một bảng khổng lồ với vài tỷ bản ghi trong 60 cột. Thay vì giữ một bảng khổng lồ như vậy, chúng tôi giữ ít nhất 60 bảng khổng lồ với 2 tỷ bản ghi mỗi bảng - và đây không phải là cơ sở cột mà là phân vùng dọc (như một ví dụ về thuật ngữ).
  • Phân vùng ngang - chúng tôi cắt từng dòng, có thể bên trong máy chủ.

Khoảnh khắc khó xử ở đây là sự khác biệt tinh tế giữa phân vùng ngang và phân mảnh. Tôi có thể bị cắt thành từng mảnh, nhưng tôi không thể nói cho bạn biết chắc chắn đó là gì. Có cảm giác rằng sharding và phân vùng ngang là giống nhau.

Nói chung, Sharding là khi một bảng lớn về cơ sở dữ liệu hoặc bộ sưu tập tài liệu, đối tượng chuyên nghiệp, nếu bạn không có cơ sở dữ liệu, mà là kho lưu trữ tài liệu, sẽ bị cắt chính xác bởi các đối tượng. Đó là, từ 2 tỷ đối tượng, các mảnh được chọn bất kể kích thước. Bản thân các đối tượng bên trong mỗi đối tượng không được cắt thành từng mảnh, chúng tôi không xếp chúng thành các cột riêng biệt, cụ thể là chúng tôi xếp chúng thành từng đợt ở những nơi khác nhau.

Có sự khác biệt tinh tế về thuật ngữ. Ví dụ, nói một cách tương đối, các nhà phát triển Postgres có thể nói rằng phân vùng ngang là khi tất cả các bảng mà bảng chính được chia nằm trong cùng một lược đồ và khi trên các máy khác nhau, điều này đã được phân đoạn.

Theo nghĩa chung, không bị ràng buộc với thuật ngữ của một cơ sở dữ liệu cụ thể và một hệ thống quản lý dữ liệu cụ thể, có cảm giác rằng sharding chỉ là cắt từng dòng / tài liệu theo tài liệu, v.v. - chỉ vậy thôi.

Tôi nhấn mạnh điển hình. Theo nghĩa là chúng tôi đang làm tất cả những điều này không chỉ để cắt 2 tỷ tài liệu thành 20 bảng, mỗi bảng sẽ dễ quản lý hơn mà còn để phân phối nó trên nhiều lõi, nhiều đĩa hoặc nhiều máy chủ ảo hoặc vật lý khác nhau .

1.2 Chia cái không chia được

Điều này được hiểu rằng chúng tôi làm điều này để mỗi phân đoạn - mỗi phần dữ liệu - được sao chép nhiều lần. Nhưng thực sự, không.

INSERT INTO docs00 
SELECT * FROM documents WHERE (id%16)=0 
... 
 
INSERT INTO docs15 
SELECT * FROM documents WHERE (id%16)=15 

Trên thực tế, nếu bạn thực hiện việc cắt dữ liệu như vậy và từ một bảng SQL khổng lồ trên MySQL trên máy tính xách tay mạnh mẽ của mình, bạn sẽ tạo ra 16 bảng nhỏ, không vượt ra ngoài một máy tính xách tay, không phải một lược đồ, không phải một cơ sở dữ liệu, v.v. . và như thế. - vậy là xong, bạn đã có sharding.

Điều này dẫn đến kết quả như sau:

  • Băng thông tăng lên.
  • Độ trễ không thay đổi, nghĩa là mỗi người, có thể nói, công nhân hoặc người tiêu dùng trong trường hợp này, đều có của riêng mình. Các yêu cầu khác nhau được phục vụ cùng một lúc.
  • Hoặc cả hai, và cái khác, cũng như tính sẵn sàng cao (sao chép).

Tại sao băng thông? Đôi khi chúng ta có thể có những khối lượng dữ liệu không vừa - không rõ ở đâu, nhưng chúng không vừa - trên 1 {kernel | đĩa | máy chủ | ...}. Không có đủ tài nguyên, thế thôi. Để làm việc với tập dữ liệu lớn này, bạn cần phải cắt nó.

Tại sao độ trễ? Trên một lõi, quét một bảng gồm 2 tỷ hàng chậm hơn 20 lần so với quét 20 bảng trên 20 lõi thực hiện song song. Dữ liệu được xử lý quá chậm trên một tài nguyên duy nhất.

Tại sao tính sẵn sàng cao? Hoặc chúng tôi cắt dữ liệu để thực hiện cả hai cùng một lúc và đồng thời một số bản sao của mỗi phân đoạn - sao chép đảm bảo tính khả dụng cao.

1.3 Một ví dụ đơn giản "làm thế nào để làm điều đó bằng tay"

Có thể cắt bỏ phân đoạn có điều kiện bằng cách sử dụng bảng kiểm tra test.documents cho 32 tài liệu và tạo 16 bảng kiểm tra từ bảng này, mỗi bảng khoảng 2 tài liệu test.docs00, 01, 02, ..., 15.

INSERT INTO docs00 
SELECT * FROM documents WHERE (id%16)=0 
... 
 
INSERT INTO docs15 
SELECT * FROM documents WHERE (id%16)=15 

Tại sao về? Vì tiên nghiệm chúng tôi không biết id được phân phối như thế nào, nếu bao gồm từ 1 đến 32, thì mỗi tài liệu sẽ có đúng 2 tài liệu, nếu không thì không.

Chúng tôi làm điều đó ở đây tại sao. Sau khi chúng tôi đã thực hiện 16 bảng, chúng tôi có thể "lấy" 16 thứ chúng tôi cần. Bất kể những gì chúng ta đạt được, chúng ta có thể sử dụng song song các tài nguyên này. Ví dụ: nếu không có đủ dung lượng đĩa, bạn nên phân tách các bảng này trên các đĩa riêng biệt.

Thật không may, tất cả điều này không miễn phí. Tôi nghi ngờ rằng trong trường hợp tiêu chuẩn SQL chính tắc (tôi đã không đọc lại tiêu chuẩn SQL trong một thời gian dài, có thể nó đã không được cập nhật trong một thời gian dài), không có cú pháp chuẩn chính thức nào để nói với bất kỳ máy chủ SQL nào. : "Máy chủ SQL thân mến, hãy tạo cho tôi 32 phân đoạn và chia chúng thành 4 đĩa. Nhưng trong các triển khai riêng lẻ, thường có một cú pháp cụ thể để thực hiện cùng một việc về cơ bản. PostgreSQL có cơ chế phân vùng, MySQL có MariaDB, Oracle có lẽ đã làm tất cả những điều này từ lâu.

Tuy nhiên, nếu chúng tôi làm điều đó bằng tay, không có hỗ trợ cơ sở dữ liệu và trong khuôn khổ của tiêu chuẩn, thì chúng tôi phải trả giá có điều kiện với sự phức tạp của việc truy cập dữ liệu . Nơi trước đây có một tài liệu CHỌN * TỪ đơn giản WHERE id=123, bây giờ là 16 x CHỌN * TỪ docsXX. Và thật tốt nếu chúng tôi cố gắng lấy bản ghi theo khóa. Sẽ thú vị hơn nhiều nếu chúng tôi cố gắng lấy một loạt các bản ghi sớm. Bây giờ (tôi nhấn mạnh nếu chúng ta là những kẻ ngu ngốc và vẫn nằm trong khuôn khổ của tiêu chuẩn), kết quả của 16 CHỌN * TỪ này sẽ phải được kết hợp trong ứng dụng.

Những thay đổi hiệu suất bạn có thể mong đợi?

  • Trực giác - tuyến tính.
  • Về mặt lý thuyết - tuyến tính phụ, vì luật Amdahl.
  • Thực tế, có thể gần như tuyến tính, có thể không.

Trong thực tế, câu trả lời chính xác là không rõ. Với một ứng dụng thông minh của kỹ thuật sharding, bạn có thể đạt được sự suy giảm siêu tuyến tính đáng kể về hiệu suất của ứng dụng của mình và thậm chí DBA sẽ hoạt động với một bài xì phé nóng đỏ.

Hãy xem làm thế nào điều này có thể đạt được. Rõ ràng là chỉ đặt cài đặt thành PostgreSQL shards=16, rồi nó tự tắt, không có gì thú vị. Hãy suy nghĩ về cách chúng tôi có thể đảm bảo rằng chúng tôi giảm tốc độ từ 16 lần xuống 32 lần - điều này thật thú vị từ quan điểm làm thế nào để không làm điều này.

Những nỗ lực của chúng tôi để tăng tốc hoặc giảm tốc độ sẽ luôn đi vào kinh điển - luật Amdahl cổ điển, nói rằng không có sự song song hoàn hảo nào cho bất kỳ yêu cầu nào, luôn có một số phần nhất quán.

1.4 Định luật Amdahl

Luôn có một phần nối tiếp.

Luôn có một phần thực thi truy vấn được song song hóa và luôn có một phần không được song song hóa. Ngay cả khi đối với bạn, có vẻ như đó là một truy vấn song song hoàn hảo, thì ít nhất tập hợp hàng kết quả mà bạn sẽ gửi cho khách hàng từ các hàng nhận được từ mỗi phân đoạn luôn ở đó và nó luôn tuần tự.

Luôn luôn có một số phần nhất quán. Nó có thể nhỏ bé, hoàn toàn vô hình so với nền chung, nó có thể khổng lồ và theo đó, ảnh hưởng mạnh đến quá trình song song hóa, nhưng nó luôn tồn tại.

Ngoài ra, ảnh hưởng của nó đang thay đổi và có thể tăng lên đáng kể, ví dụ: nếu chúng ta cắt bảng của mình - hãy tăng tiền cược - từ 64 bản ghi thành 16 bảng gồm 4 bản ghi, phần này sẽ thay đổi. Tất nhiên, dựa trên lượng dữ liệu khổng lồ như vậy, chúng tôi đang làm việc trên điện thoại di động và bộ xử lý 2 MHz 86 và chúng tôi không có đủ tệp có thể mở đồng thời. Rõ ràng, với những đầu vào như vậy, chúng tôi mở từng tệp một.

  • Đó là Tổng = Nối tiếp + Song song . Ví dụ, trong đó, song song là tất cả công việc bên trong DB và nối tiếp đang gửi kết quả đến máy khách.
  • Đã trở thành Total2 = Serial + Parallel/N + Xserial . Ví dụ: khi ORDER BY tổng thể, Xserial>0.

Với ví dụ đơn giản này, tôi đang cố gắng chỉ ra rằng một số Xserial xuất hiện. Ngoài thực tế là luôn có một phần được tuần tự hóa và thực tế là chúng tôi đang cố gắng làm việc với dữ liệu song song, còn có một phần bổ sung để cung cấp việc cắt dữ liệu này. Nói một cách đại khái, chúng ta có thể cần:

  • tìm 16 bảng này trong từ điển nội bộ của cơ sở dữ liệu;
  • mở tập tin;
  • cấp phát bộ nhớ;
  • giải phóng bộ nhớ;
  • hợp nhất kết quả;
  • đồng bộ hóa giữa các lõi.

Một số hiệu ứng không đồng bộ vẫn xuất hiện. Chúng có thể không đáng kể và chiếm một phần tỷ tổng thời gian, nhưng chúng luôn khác không và luôn ở đó. Với sự giúp đỡ của họ, chúng tôi có thể giảm đáng kể hiệu suất sau khi phân mảnh.

Đây là một bức tranh tiêu chuẩn về định luật Amdahl. Điều quan trọng ở đây là các đường thẳng, lý tưởng nhất là thẳng và tăng trưởng tuyến tính, chạy thành một đường tiệm cận. Nhưng vì biểu đồ từ Internet không thể đọc được, theo ý kiến ​​​​của tôi, tôi đã tạo ra các bảng trực quan hơn với các con số.

Giả sử chúng ta có một số phần được tuần tự hóa của quá trình xử lý yêu cầu chỉ chiếm 5%: serial = 0,05 = 1/20 .

Theo trực giác, có vẻ như với một phần được tuần tự hóa chỉ chiếm 1/20 quá trình xử lý yêu cầu, nếu chúng tôi xử lý yêu cầu song song cho 20 lõi, nó sẽ trở thành khoảng 20, trong trường hợp xấu nhất là 18, nhanh hơn nhiều lần.

Trên thực tế, toán học là một thứ nhẫn tâm :

tường = 0,05 + 0,95/số_lõi, tăng tốc = 1 / (0,05 + 0,95/số_lõi)

Hóa ra nếu bạn tính toán cẩn thận, với phần nối tiếp là 5%, tốc độ tăng tốc sẽ là 10 lần (10,3), tức là 51% so với lý tưởng lý thuyết.

8 lõi = 5,9 = 74%
10 lõi = 6,9 = 69%
20 lõi = 10,3 = 51%
40 lõi = 13,6 = 34%
128 lõi = 17,4 = 14%

Đã sử dụng 20 lõi (20 đĩa, nếu bạn muốn) cho tác vụ mà một lõi đã từng làm, về mặt lý thuyết, chúng tôi sẽ không bao giờ có được khả năng tăng tốc hơn 20 lần, nhưng trên thực tế - ít hơn nhiều. Hơn nữa, với sự gia tăng số lượng song song, sự kém hiệu quả tăng lên rất nhiều.

Khi chỉ còn lại 1% công việc được nối tiếp và 99% được thực hiện song song, các giá trị tăng tốc sẽ cải thiện phần nào:

8 lõi = 7,5 = 93%
16 lõi = 13,9 = 87%
32 lõi = 24,4 = 76%
64 lõi = 39,3 = 61%

Đối với một truy vấn nhiệt hạch hoàn hảo, vốn mất hàng giờ để hoàn thành và công việc chuẩn bị cũng như lắp ráp kết quả mất rất ít thời gian (serial = 0,001), chúng ta sẽ thấy hiệu quả tốt:

8 lõi = 7,94 = 99%
16 lõi = 15,76 = 99%
32 lõi = 31,04 = 97%
64 lõi = 60,20 = 94%

Xin lưu ý rằng chúng tôi sẽ không bao giờ thấy 100% . Trong những trường hợp đặc biệt tốt, chẳng hạn như bạn có thể thấy 99,999%, nhưng không chính xác 100%.