Thuật toán Hi / Lo là gì?


464

Thuật toán Hi / Lo là gì?

Tôi đã tìm thấy điều này trong tài liệu NHibernate (đó là một phương pháp để tạo các khóa duy nhất, phần 5.1.4.2), nhưng tôi không tìm thấy một lời giải thích tốt về cách thức hoạt động của nó.

Tôi biết rằng Nhibernate xử lý nó và tôi không cần biết bên trong, nhưng tôi chỉ tò mò.

Câu trả lời:


540

Ý tưởng cơ bản là bạn có hai số để tạo thành khóa chính - số "cao" và số "thấp". Về cơ bản, một khách hàng có thể tăng chuỗi "cao", biết rằng sau đó nó có thể tạo các khóa một cách an toàn từ toàn bộ phạm vi của giá trị "cao" trước đó với nhiều giá trị "thấp".

Chẳng hạn, giả sử bạn có một chuỗi "cao" với giá trị hiện tại là 35 và số "thấp" nằm trong khoảng 0-1023. Sau đó, khách hàng có thể tăng trình tự lên 36 (để các khách hàng khác có thể tạo khóa trong khi sử dụng 35) và biết rằng các khóa 35/0, 35/1, 35/2, 35/3 ... 35/1023 là tât cả co hiệu lực.

Nó có thể rất hữu ích (đặc biệt là với ORM) để có thể đặt các khóa chính ở phía máy khách, thay vì chèn các giá trị không có khóa chính và sau đó tìm nạp lại vào máy khách. Ngoài bất cứ điều gì khác, điều đó có nghĩa là bạn có thể dễ dàng tạo mối quan hệ cha mẹ / con cái và có sẵn các khóa trước khi bạn thực hiện bất kỳ thao tác chèn nào , giúp việc sắp xếp chúng trở nên đơn giản hơn.


14
Bạn có nói rằng "phạm vi thấp" được phối hợp trong máy khách, trong khi "chuỗi cao" tương ứng với chuỗi DB?
Chris Noe

14
Các giá trị hi & lo thường được tạo thành một giá trị số nguyên duy nhất hoặc dưới dạng khóa doanh nghiệp hai phần?
Chris Noe

51
giống như một địa chỉ IP sau đó - ICANN cung cấp cho bạn số 'mạng' cao, khi đó bạn có số lượng 'máy chủ' thấp như bạn muốn, trong giới hạn phạm vi CIDR bạn đưa ra.
gbjbaanb

6
@Adam: Về cơ bản, không có gì - nó chỉ có khả năng rẻ hơn để tăng một giá trị (phần "cao") hơn là tạo ra một loạt các khóa. (Nó có khả năng rẻ hơn nhiều về mặt truyền dữ liệu - bạn có thể "dự trữ" một số lượng lớn các khóa với băng thông tối thiểu.)
Jon Skeet

4
@Adam: Điều đó đúng nếu các phím chỉ là số. Không quá nhiều cho GUID :) Nhưng vâng, trong trường hợp số đơn giản, bất kỳ nguyên tử "tăng thêm một lượng cố định" nào cũng sẽ làm được. Đó thực sự là những gì hi-lo đang làm, nếu bạn nghĩ đó là một số được chia thành hai phần.
Jon Skeet

157

Ngoài câu trả lời của Jon:

Nó được sử dụng để có thể làm việc bị ngắt kết nối. Sau đó, một khách hàng có thể yêu cầu máy chủ cho một số hi và tạo các đối tượng tăng số lo. Nó không cần liên hệ với máy chủ cho đến khi phạm vi lo được sử dụng hết.


1
Tôi thích điều này cho ngắn gọn.
Nhà phát triển Marius ilėnas

34

Vì đây là một câu hỏi rất phổ biến, tôi đã viết bài viết này , trên đó câu trả lời này dựa trên.

Các thuật toán hi / lo chia miền thứ tự thành các nhóm hi hi. Một giá trị hi hi hi được gán đồng bộ. Mỗi nhóm của Hi hi được cung cấp một số lượng tối đa các mục nhập lo Lo, có thể bằng cách gán ngoại tuyến mà không phải lo lắng về các mục trùng lặp đồng thời.

  1. Mã thông báo hi hi được phân bổ bởi cơ sở dữ liệu và hai cuộc gọi đồng thời được đảm bảo để xem các giá trị liên tiếp duy nhất
  2. Sau khi nhận được mã thông báo của Hi hi, chúng tôi chỉ cần tăng số lần kích thước của Google (số lượng mục nhập Lo Lo)
  3. Phạm vi định danh được đưa ra theo công thức sau:

    [(hi -1) * incrementSize) + 1, (hi * incrementSize) + 1)

    và giá trị của Lo Lo sẽ nằm trong phạm vi:

    [0, incrementSize)

    được áp dụng từ giá trị bắt đầu của:

    [(hi -1) * incrementSize) + 1)
  4. Khi tất cả các giá trị của Lo Lo được sử dụng, một giá trị mới của Hi hi được tải xuống và chu kỳ tiếp tục

Bạn có thể tìm thấy một lời giải thích chi tiết hơn trong bài viết này :

Và trình bày trực quan này cũng dễ dàng để làm theo:

nhập mô tả hình ảnh ở đây

Mặc dù trình tối ưu hóa hi / lo rất tốt để tối ưu hóa việc tạo định danh, nhưng nó không hoạt động tốt với các hệ thống khác chèn các hàng vào cơ sở dữ liệu của chúng tôi mà không biết gì về chiến lược định danh của chúng tôi.

Hibernate cung cấp trình tối ưu hóa gộp , cung cấp các lợi thế của chiến lược trình tạo hi / lo đồng thời cung cấp khả năng tương tác với các khách hàng bên thứ 3 khác không biết về chiến lược phân bổ trình tự này.

Vừa hiệu quả vừa có thể tương tác với các hệ thống khác, trình tối ưu hóa gộp là một ứng cử viên tốt hơn nhiều so với chiến lược định danh hi / lo kế thừa.


Đôi khi tôi thực sự không hiểu bạn hahaha vì vậy: Mặc dù trình tối ưu hóa hi / lo rất tốt để tối ưu hóa việc tạo định danh (Ok tốt), nhưng nó không chơi tốt với các hệ thống khác (ý ​​của các hệ thống khác là gì? những cái nào?) chèn các hàng vào cơ sở dữ liệu của chúng tôi (Không tạo ra định danh được sử dụng để chèn các hàng quá?), mà không biết gì về chiến lược định danh của chúng tôi.
Adelin

Các hệ thống khác, như một DBA đang cố chạy một câu lệnh INSERT. Nếu cô ấy đọc dữ liệu chuỗi hiện tại, bạn có nghĩ rằng thật dễ dàng để tìm ra giá trị định danh tiếp theo khi biết chúng tôi sử dụng hilo trong bảng DB cụ thể này không?
Vlad Mihalcea

Tôi xin lỗi nếu nhận xét không phù hợp với câu trả lời của bạn, nhưng tôi đã tự hỏi mặc định trình tối ưu hóa nào được sử dụng? Hay nó phụ thuộc vào DB (Tôi đang sử dụng PostgreSQL)? Bởi vì tôi không thể tìm ra mối quan hệ giữa giá trị chuỗi hiện tại và ID được tạo. Tôi đang sử dụng @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "name") @SequenceGenerator(name="name", sequenceName = "name_seq", allocationSize=100)cho ID của mình.
Stefan Golubović

1
Vì Hibernate 5, Pooled là Trình tối ưu hóa mới, không phải Hi / lo. Kiểm tra bài viết này để biết thêm chi tiết về Trình tối ưu hóa gộp.
Vlad Mihalcea

@VladMihalcea, tôi tin rằng bạn có một lỗi đánh máy trong viên đạn thứ ba, đoạn trích đầu tiên tại , (hi * incrementSize) + 1)... nó phải vậy , hi * incrementSize), phải không?
Huiagan

23

Lo là một bộ cấp phát được lưu trong bộ nhớ cache, phân chia không gian khóa thành nhiều phần lớn, thường dựa trên một số kích thước từ của máy, thay vì các phạm vi có kích thước có ý nghĩa (ví dụ: lấy 200 phím cùng lúc) mà con người có thể chọn một cách hợp lý.

Việc sử dụng Hi-Lo có xu hướng lãng phí số lượng lớn các khóa khi khởi động lại máy chủ và tạo ra các giá trị khóa không thân thiện với con người.

Tốt hơn so với công cụ cấp phát Hi-Lo, là công cụ phân bổ "Tuyến tính". Điều này sử dụng một nguyên tắc dựa trên bảng tương tự nhưng phân bổ các khối nhỏ, có kích thước thuận tiện và tạo ra các giá trị thân thiện với con người.

create table KEY_ALLOC (
    SEQ varchar(32) not null,
    NEXT bigint not null,
    primary key (SEQ)
);

Để phân bổ tiếp theo, giả sử, 200 khóa (sau đó được giữ dưới dạng một phạm vi trong máy chủ và được sử dụng khi cần thiết):

select NEXT from KEY_ALLOC where SEQ=?;
update KEY_ALLOC set NEXT=(old value+200) where SEQ=? and NEXT=(old value);

Cung cấp cho bạn có thể cam kết giao dịch này (sử dụng thử lại để xử lý sự tranh chấp), bạn đã phân bổ 200 khóa và có thể phân phối chúng khi cần.

Với kích thước chunk chỉ 20, sơ đồ này nhanh hơn gấp 10 lần so với phân bổ từ chuỗi Oracle và có khả năng di động 100% trong số tất cả các cơ sở dữ liệu. Hiệu suất phân bổ tương đương với hi-lo.

Không giống như ý tưởng của Ambler, nó coi không gian phím là một số tuyến tính liền kề.

Điều này tránh sự thúc đẩy cho các khóa tổng hợp (điều này không bao giờ thực sự là một ý tưởng tốt) và tránh lãng phí toàn bộ từ ngữ khi máy chủ khởi động lại. Nó tạo ra các giá trị chính "thân thiện", quy mô của con người.

Bằng cách so sánh, ý tưởng của ông Ambler sẽ phân bổ 16 hoặc 32 bit cao và tạo ra các giá trị khóa không thân thiện với con người khi gia tăng các từ hi.

So sánh các khóa được phân bổ:

Linear_Chunk       Hi_Lo
100                65536
101                65537
102                65538
.. server restart
120                131072
121                131073
122                131073
.. server restart
140                196608

Về mặt thiết kế, giải pháp của ông về cơ bản phức tạp hơn trên dòng số (khóa tổng hợp, sản phẩm hi_word lớn) so với linear_Chunk trong khi không đạt được lợi ích so sánh.

Thiết kế Hi-Lo nảy sinh sớm trong việc lập bản đồ và kiên trì OO. Ngày nay, các khung kiên trì như Hibernate cung cấp các bộ cấp phát đơn giản hơn và tốt hơn làm mặc định.


4
Bài đăng hay, nhưng bạn không trả lời câu hỏi.
orbfish

1
+1 cho một câu trả lời thú vị. Tôi đồng ý rằng phần lớn các ứng dụng không nhận được lợi thế từ Hi-Lo so với cách tiếp cận đơn giản hơn; tuy nhiên tôi nghĩ Hi-Lo phù hợp hơn với trường hợp đặc biệt của nhiều bộ cấp phát trong các ứng dụng đồng thời cao.
richj

1
Cảm ơn @richj! Quan điểm của tôi là bạn có thể sử dụng nhiều bộ cấp phát hoặc kích thước khối lớn với "phân bổ khối tuyến tính", nhưng điều đó - không giống như Hi / Lo - nó duy trì sự tương ứng tuyến tính của bộ cấp phát NEXT_VAL cho các khóa trong bảng và có thể điều chỉnh được. Không giống như HiLo, không cần nhân - không cần thiết! Các nhân và lưu trữ NEXT_HI làm HiLo phức tạp hơn và phá vỡ tuneability, kể từ khi thay đổi kích cỡ khối tùy tiện sẽ làm thay đổi quan trọng tiếp theo sẽ được phát hành .. Xem: literatejava.com/hibernate/...
Thomas W

2
Tôi quan tâm đến nhiều phân bổ độc lập. Với Hi-Lo, rõ ràng giá trị cao có thể được phân chia thành ID phân bổ / ID khối. Không rõ ràng ngay lập tức (với tôi) rằng cách tiếp cận tương tự có thể được áp dụng cho Tuyến Chunk, nhưng về cơ bản, đó là cùng một vấn đề phân chia tổng phạm vi giữa các cấp phát. Tôi đã có nó ngay bây giờ. Cảm ơn.
richj

1
Ồ, sau khi nghĩ về nó, tôi nghĩ cột SEQ ánh xạ tới một tên bảng. Ví dụ: có một bảng phân bổ bảng Khách hàng, một bảng cho bảng Đơn hàng, v.v. Tha lỗi cho tôi, đôi khi tôi chậm chạp.
Rock Anthony Johnson

1

Tôi thấy thuật toán Hi / Lo là hoàn hảo cho nhiều cơ sở dữ liệu với các kịch bản sao chép dựa trên kinh nghiệm của tôi. Hãy tưởng tượng điều này. bạn có một máy chủ ở New York (bí danh 01) và một máy chủ khác ở Los Angeles (bí danh 02) thì bạn có một bảng CÁ NHÂN ... vì vậy ở New York khi một người được tạo ... bạn luôn sử dụng 01 làm giá trị HI và giá trị LO là giá trị tiếp theo. ví dụ por.

  • 010000010 Jason
  • 010000011 David
  • 010000012 Theo

ở Los Angeles bạn luôn sử dụng HI 02. ví dụ:

  • 020000045 Rupert
  • 020000046 Oswald
  • 020000047 Mario

Vì vậy, khi bạn sử dụng sao chép cơ sở dữ liệu (bất kể thương hiệu nào), tất cả các khóa chính và dữ liệu kết hợp dễ dàng và tự nhiên mà không phải lo lắng về các khóa chính, bộ sưu tập, v.v.

Đây là cách tốt nhất để đi trong kịch bản này.


Nó không hoạt động trong Hibernate. HiLo algrotirm nhận được một giá trị mới của chuỗi trong mỗi giao dịch, do đó, bộ đếm HI tăng lên một cách chính thức. Nhưng trong ví dụ của bạn, bộ đếm HI luôn không đổi cho một DB.
Dmitry1405
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.