10
Phần 5: THỰC HIỆN HIỆU QUẢ CỦA ĐÔNG HỒ VECTOR Nếu số lượng các tiến trình trong một tính toán phân tán là lớn, thì đồng hồ vector sẽ yêu cầu kèm thêm một lượng lớn thông tin trong các thông điệp nhằm phục vụ mục đích của quá trình khuyếch tán thời gian và cập nhật đồng hồ. Chi phí thông điệp tăng tuyến tính với số lượng tiến trình trong hệ thống và khi có đến hàng nghìn tiến trình trong hệ thống, kích cỡ thông điệp trở lên rất lớn ngay cả khi chỉ có một vài sự kiện diễn ra trong vài tiến trình. Phần này thảo luận đến các cách hiệu quả để duy trì đồng hồ vector, các phương pháp cơ bản tương tự có thể dùng để thực hiện hiêu quả đồng hồ ma trận. Charron-Bost đã chỉ ra [2] rằng nếu đồng hồ vector phải đáp ứng tính chất nhất quán mạnh, thì nhìn chung nhãn vector thời gian phải có cỡ ít nhất phải là n, tất cả các tiến trình. Do vậy, nhìn chung kích thước của một nhãn vector thời gian là số lượng tiến trình liên quan trong tính toán phân tán; tuy nhiên, một vài sự tối ưu hóa có thể xảy ra và tiếp theo chúng tôi sẽ thảo luận về các kĩ thuật thực hiện đồng hồ vector một cách hiệu quả. 5.1 Phương pháp vi phân của Singhal-Kshemkalyani Phương pháp vi phân của Singhal-Kshemkalyani [25] dựa trên việc quan sát giữa thông điệp gửi thành công đến các tiến trình tương tự, chỉ một vài thành phần của đồng hồ vector có thể bị thay đổi trong quá trình gửi thông điệp. Điều này dễ xảy ra hớn khi số lượng tiến trình lớn do chỉ

Phần Của Nam_checked

Embed Size (px)

Citation preview

Page 1: Phần Của Nam_checked

Phần 5: THỰC HIỆN HIỆU QUẢ CỦA ĐÔNG HỒ VECTOR

Nếu số lượng các tiến trình trong một tính toán phân tán là lớn, thì đồng hồ vector sẽ

yêu cầu kèm thêm một lượng lớn thông tin trong các thông điệp nhằm phục vụ mục đích

của quá trình khuyếch tán thời gian và cập nhật đồng hồ. Chi phí thông điệp tăng tuyến

tính với số lượng tiến trình trong hệ thống và khi có đến hàng nghìn tiến trình trong hệ

thống, kích cỡ thông điệp trở lên rất lớn ngay cả khi chỉ có một vài sự kiện diễn ra trong

vài tiến trình. Phần này thảo luận đến các cách hiệu quả để duy trì đồng hồ vector, các

phương pháp cơ bản tương tự có thể dùng để thực hiện hiêu quả đồng hồ ma trận.

Charron-Bost đã chỉ ra [2] rằng nếu đồng hồ vector phải đáp ứng tính chất nhất quán

mạnh, thì nhìn chung nhãn vector thời gian phải có cỡ ít nhất phải là n, tất cả các tiến

trình. Do vậy, nhìn chung kích thước của một nhãn vector thời gian là số lượng tiến trình

liên quan trong tính toán phân tán; tuy nhiên, một vài sự tối ưu hóa có thể xảy ra và tiếp

theo chúng tôi sẽ thảo luận về các kĩ thuật thực hiện đồng hồ vector một cách hiệu quả.

5.1 Phương pháp vi phân của Singhal-Kshemkalyani

Phương pháp vi phân của Singhal-Kshemkalyani [25] dựa trên việc quan sát giữa

thông điệp gửi thành công đến các tiến trình tương tự, chỉ một vài thành phần của đồng

hồ vector có thể bị thay đổi trong quá trình gửi thông điệp. Điều này dễ xảy ra hớn khi số

lượng tiến trình lớn do chỉ một vài tiến trình sẽ tương tác với thường xuyên bằng cách gửi

các thông điệp. Trong kỹ thuật này, khi một tiến trình pi gửi một thông điệp đến một tiến

trình pj, nó chỉ kèm thêm những thành phần của đồng hồ vector khác với thông điệp cuối

cùng được gửi đến pj.

Kỹ thuật này hoạt động như sau: nếu các thành phần i1,i2,…,in của đồng hồ vector tại

pi thay đổi tương ứng thành v1,v2,…vn, kể từ thông điệp cuối cùng được gửi đến pj, thì

tiến trình pi kèm theo một nhãn thời gian theo dạng

{(i1,v1), (i2,v2),…(in1,vn1)}

cùng thông điệp tiếp theo tới pj. Khi pj nhận được thông điệp này, nó sẽ cập nhật

đồng hồ vector của nó như sau:

vti[ik] = max(vti[ik],vk) với k=1,2,…n1.

Như vậy, phương pháp này cắt giảm kích thước thông điệp, băng thông truyền và yêu

câu vùng đệm (để lưu giữ thông điệp). Trong trường hợp xấu nhất, mọi thành phần của

Page 2: Phần Của Nam_checked

đồng hồ vector được cập nhật tại pi do thông điệp cuối cùng tới tiến trình p j, và thông

điệp tiếp theo từ pi đến pj sẽ cần mang nhãn vector thời gian hoàn chỉnh của kích cỡ n.

Tuy nhiên, thường thì kích thước của nhãn thời gian trên một thông điệp sẽ ít hơn n. Lưu

ý rằng kỹ thuật này yêu cầu mỗi tiến trình ghi nhớ nhãn vector thời gian trong thông điệp

cuối gửi đến mọi tiến trình khác. Thực thi trực tiếp việc này sẽ dẫn đến chi phí lưu trữ

O(n2) tại mỗi tiến trình. Kỹ thuật này còn yêu cầu các kênh giao tiếp theo FIFO cho việc

truyền (gửi) thông điệp.

Singhal và Kshemkalyani đã phát triển một kỹ thuật thông minh cắt giảm chi phí lưu

trữ này tại mỗi tiến trình xuống O(n). Kỹ thuật này hoạt động theo cách sau: tiến trình p i

duy trì hai vector bổ sung sau:

LSi[l…n] (lần gửi cuối cùng): LSi[j] thể hiện giá trị của vti[i] khi tiến trình pi

gửi đi thông điệp cuối cùng đến tiến trình pj.

LUi[l…n] (lần cập nhật cuối cùng): LUi[j] thể hiện giá trị của vti[j] khi tiến

trình pi cập nhật lần cuối thành phần vti[j].

Rõ ràng, LUi[i]=vti[i] tại mọi thời điểm và LUi[j] cần được cập nhật chỉ khi nhận

được một thông điệp khiến pi cập nhật thành phần vti[j]. Đồng thời, LSi[j] cần cập nhật

chỉ khi pi gửi một thông điệp đến pj. Kể từ lần giao tiếp cuối cùng từ pi đến pj, chỉ những

thành phần k của đồng hồ vector vti[k] thay đổi do LSi[j] < LUi[k]. Do đó, những thành

phần này chỉ cần gửi trong thông điệp từ pi tới pj. Khi pi gửi một thông điệp tới pj, nó chỉ

gửi một bộ dữ liệu,

{(x, vti [x])|LSi[j]<LUi[x]},

là nhãn vector thời gian đến pj, thay vì gửi một vector n thành phần trong một thông điệp.

Do vậy, vector nguyên với kích thước n không phải gửi cùng với thông điệp. Thay

vào đó, chỉ các thành phần trong đồng hồ vector đã thay đổi từ thông điệp cuối cùng gửi

tới tiến trình kia được gửi theo dạng {(p1, latest_value), (p2,latest_value),..}, trong đó pi

thể hiện rằng thành phần lần thứ pi của đồng hồ véc tơ đã thay đổi.

Phương pháp này được minh họa trong hình 3.4. Ví dụ, thông điệp thứ hai từ p 3 tới p2

(bao gồm một nhãn thời gian {(3,2)} thông báo tới p2 rằng thành phần thứ ba của đồng hồ

vector đã được điều chỉnh và giá trị mới là 2. Điều này là do tiến trình p 3 (được thể hiện

bởi thành phần thứ ba của vector) làm tăng giá trị đồng hồ từ 1 lên 2 kể từ thông điệp

cuối cùng gửi tới p2.

Page 3: Phần Của Nam_checked

Chi phí duy trì đồng hồ vector trong hệ thống lớn có thể giảm đáng kể bằng kỹ thuật

này, đặc biệt nếu sự tương tác tiến trình diễn ra cục bột heo không gian và thời gian. Kỹ

thuật này sẽ trở nên có lợi trong nhiều ứng dụng bao gồm cả bộ nhớ chia sẻ phân tán

nhân quả, phát hiện bế tắc phân tán, thi hành loại trừ lẫn nhau và truyền thông cục bộ

điển hình được quan sát trong hệ thống phân tán.

5.2 Kỹ thuật phụ thuộc trực tiếp của Fowler – Zwaenepoel

Kỹ thuật phụ thuộc trực tiếp [6] Fowler – Zwaenepoel làm giảm kích thước của

thông điệp bằng cách chỉ truyền một giá trị vô hướng trong thông điệp. Không có đồng

hồ vector được duy trì tức thời (on-the-fly). Thay vào đó, một tiến trình chỉ duy trì thông

tin liên quan đến tính phụ thuộc trực tiếp đến các tiến trình khác. Một vectơ thời gian cho

một sự kiện, thể hiện cho tính phụ thuộc bắc cầu trên tiến trình khác, được xây dựng

ngoại tuyến từ một tìm kiếm đệ quy của thông tin phụ thuộc trực tiếp vào các tiến trình.

Mỗi tiến trình pi duy trì một vector phụ thuộc Di. Ban đầu, Di[j] = 0 với j = 1, …, n.

Di được cập nhật như sau:

1. Bất cứ khi nào một sự kiện xảy ra tại pi, Di[i] := Di[i]+1. Có nghĩa là, các thành

phần của vector tương ứng với thời gian cục bộ được tăng lên một.

2. Khi một tiến trình pi gửi một thông điệp tới tiến trình pj, nó mang (piggybacks)

giá trị cập nhật của Di[i] trong thông điệp.

3. Khi tiến trình pi nhận một thông điệp từ pj với giá trị piggybacks d, pi cập nhật

vector phụ thuộc của nó như sau: Di[j]:= max {Di[j],d}.

Page 4: Phần Của Nam_checked

Do vậy, vector phụ thuộc Di chỉ phản ánh phụ thuộc trực tiếp. Tại bất cứ thời điểm

nào, Di[j] biểu thị số thứ tự của các sự kiện mới nhất trên tiến trình p j cái mà trực tiếp ảnh

hưởng đến trạng thái hiện tại. Lưu ý rằng sự kiện này có thể đứng trước sự kiện mới nhất

tại pj nào ảnh hưởng đến trạng thái hiện tại.

Hình 3.5 minh họa kỹ thuật Fowler – Zwaenepoel. Ví dụ, khi tiến trình p4 gửi một

thông điệp tới tiến trình p3, nó piggybacks một đại lượng vô hướng chỉ ra sự phụ thuộc

trực tiếp của p3 vào p4 bởi thông điệp này. Sau đó, tiến trình p3 sẽ gửi một thông điệp tới

tiến trình p2 piggybacking một đại lượng vô hướng để chỉ sự phụ thuộc trực tiếp của p2

vào p3 bởi thông điệp này. Bây giờ, tiến trình p2 trên thực tế gián tiếp phụ thuộc vào quá

trình p4 vì tiến trình p3 là phụ thuộc vào tiến trình p4. Tuy nhiên, tiến trình p2 không bao

giờ được biết về tính phụ thuộc gián tiếp của nó vào p4.

Như vậy mặc dù tính phụ thuộc trực tiếp được thông báo hợp lệ cho các tiến trình

tiếp nhận, phụ thuộc bắc cầu (gián tiếp) không được duy trì bởi phương pháp này. Chúng

chỉ có thể thu được bằng cách đệ quy tìm dấu vết các vectơ phụ thuộc trực tiếp của các sự

kiện không trực tuyến. Điều này liên quan đến việc tính toán chi phí và độ trễ.

Như vậy phương pháp này là lý tưởng chỉ cho những ứng dụng mà không đòi hỏi

tính toán tính phụ thuộc bắc cầu tức thì. Tổng phí tính toán đặc trưng của phương pháp

này làm cho nó phù hợp nhất cho các ứng dụng như điểm ngắt nhân quả và phục hồi tính

năng kiểm tra từng điểm không đồng bộ trong đó các tính toán của quan hệ phụ thuộc

nhân quả được thực hiện ngoại tuyến.

Kỹ thuật này giúp tiết kiệm đáng kể chi phí; chỉ có một đại lượng vô hướng

piggybacked trên mỗi thông điệp. Tuy nhiên, các vector phụ thuộc không thể hiện tính

Page 5: Phần Của Nam_checked

phụ thuộc bắc cầu (tức là, một nhãn thời gian vector). Tính phụ thuộc bắc cầu (hoặc

nhãn thời gian vector) của một sự kiện thu được bằng cách đệ quy truy tìm các vectơ phụ

thuộc trực tiếp của tiến trình. Rõ ràng, điều này sẽ có chi phí và sẽ liên quan đến độ trễ.

Do đó, kỹ thuật này là không phù hợp với các ứng dụng yêu cầu tính toán nhãn vector

thời gian tức thì. Tuy nhiên, kỹ thuật này là lý tưởng cho các ứng dụng mà các tính toán

của quan hệ nhân quả phụ thuộc thực hiện ngoại tuyến (ví dụ, điểm ngắt nhân quả, phục

hồi không đồng bộ checkpointing).

Tính phụ thuộc bắc cầu có thể được xác định bằng cách kết hợp sự kiện phụ thuộc

trực tiếp của một sự kiện với sự phụ thuộc trực tiếp vào nó. Trong hình 3.5, sự kiện thứ

tư của tiến trình p3 phụ thuộc vào sự kiện đầu tiên của tiến trình p4 và sự kiện thứ tư của

tiến trình p2 phụ thuộc vào sự kiện thứ tư của tiến trình p3. Bằng cách kết hợp hai phụ

thuộc trực tiếp, có thể suy luận rằng sự kiện thứ tư của tiến trình p2 phụ thuộc vào sự kiện

đầu tiên của tiến trình p4. Cần hết sức lưu ý rằng nếu sự kiện ej tại tiến trình pj xảy ra

trước sự kiện ei tại tiến trình pi, thì tất cả các sự kiện từ e0 đến ej-1 trong tiến trình pj cũng

xảy ra trước ei. Do đó, ghi lại cho ei sự kiện mới nhất của tiến trình pj đã xảy ra trước ei là

đủ. Bằng cách này, mỗi sự kiện sẽ ghi lại sự phụ thuộc của nó vào các sự kiện mới nhất

trên mỗi tiến trình khác mà nó phụ thuộc vào và duy trì những sự kiện phụ thuộc riêng

của chúng. Kết hợp tất cả các phụ thuộc, các tập nguyên (tức là vector nguyên bản) của

một sự kiện cụ thể phụ thuộc vào các sự kiện có thể được xác định ngoại tuyến.

Tính toán ngoại tuyến của phụ thuộc bắc cầu có thể được thực hiện bằng cách sử

dụng một thuật toán đệ quy đề xuất trong [6] và được minh họa bằng một dạng thức có

sửa đổi trong thuật toán 3.1. DTV là vector theo dõi phụ thuộc có kích thước n (trong đó

n là số tiến trình) mà lẽ ra phải theo dõi tất cả các phụ thuộc quan hệ nhân quả của một sự

kiện cụ thể ei ở tiến trình pi. Các thuật toán sau đó cần phải được gọi là DependencyTrack

(i, Die[i] ). Các thuật toán khởi tạo DTV có giá trị nhãn thời gian ít nhất có thể là 0 cho tất

cả các thành phần trừ i mà giá trị được đặt cho Die[i]: với mọi k = 1, …,n và k i,

DTV[k] = 0 và DTV[i] = Die[i] .

Sau đó thuật toán gọi giải thuật VisitEvent đối với tiến trình pi và sự kiện ei.

VisitEvent kiểm tra tất cả các thành phần (1, …,n) của DTV và Die và nếu giá trị trong Di

e

là lớn hơn giá trị trong DTV tại thành phần đó, sau đó DTV giả định giá trị của D ie cho

thành phần đó. Điều này đảm bảo rằng sự kiện mới nhất trong tiến trình j mà e i đó phụ

thuộc vào được ghi lại trong DTV. VisitEvent được gọi đệ qui đối với tất cả các thành

Page 6: Phần Của Nam_checked

phần mà mới được đưa vào trong DTV để các thông tin phụ thuộc mới nhất có thể được

theo dõi một cách chính xác.

Minh họa cho thuật toán theo dõi phụ thuộc đệ quy bằng cách theo dõi các phụ thuộc

của sự kiện thứ tư tại tiến trình p2. Các thuật toán được gọi là DependencyTrack (2 4).

DTV ban đầu được thiết lập là <0 4 0 0> bởi DependencyTrack. Sau đó nó gọi

VisitEvent(2 4). Các giá trị được tổ chức bởi D42 là < 1 4 4 0 >. Vì vậy, DTV lúc này

được cập nhật thành < 1 4 0 0 > và VisitEvent (1 1) được gọi.

Các giá trị được tổ chức bởi D11 là < 1 0 0 0 >. Vì khi không có thành phần nào là lớn

hơn các thành phần tương ứng trong DTV, thuật toán lặp lại. Một lần nữa các giá trị được

tổ chức bởi D24 được kiểm tra và ần này thành phần 3 được tìm thấy là trong D2

4 lớn hơn

DTV. Vì vậy, DTV được cập nhật thành < 1 4 4 0 > và VisiEvent(3 4) được gọi. Các giá

trị được tổ chức bởi D34 là < 0 0 4 1 >. Vì thành phần 4 của D3

4 lớn hơn của DTV, nó

được cập nhật thành < 1 4 4 1 > và VisitEvent(4 1) được gọi. Vì tất cả các thành phần đã

được kiểm tra, Visit(2,4) được giải phóng và DependencyTrack cũng vậy.

Kỹ thuật này có thể tiết kiệm đáng kể chi phí chỉ có một đại lượng vô hướng

piggybacked trên mỗi thông điệp. Một trong những yêu cầu quan trọng là một tiến trình

Page 7: Phần Của Nam_checked

cập nhật và ghi lại vectơ phụ thuộc của nó sau khi nhận được một thông điệp và trước khi

gửi đi bất kỳ thông điệp nào. Ngoài ra, nếu sự kiện xảy ra thường xuyên, kỹ thuật này sẽ

cần ghi lại lịch sử của một số lớn các sự kiện.