Dimensionality reduction: SVD and its applications
Pregel: Hệ thống xử lý đồ thị lớn
1. Pregel: Hệ thống xử lý đồ thị lớn.
Grzegorz Malewicz, Matthew H. Austern, Aart J. C. Bik, James C. Dehnert, Ilan Horn,
Naty Leiser, and Grzegorz Czajkowski
Google, Inc.
{malewicz, austern, ajcbik, dehnert, ilan, naty, gczaj}@google.com
Nhóm dịch: Phùng Đức Nhật, Đặng Minh Hiếu, Lưu Trung Hiếu, Phạm Đức Đạo
TỔNG QUAN
Nhiều vấn đề thực tế về tính toán liên quan đến
đồ thị lớn. Ví dụ điển hình bao gồm đồ thị Web
và các mạng xã hội. Độ lớn của đồ thị, trong một
vài trường hợp, có hàng tỉ đỉnh, triệu tỷ cạnh,
tạo ra thách thức đối với hệu năng xử lý. Trong
bài viết này ta sẽ giới thiệu một mô hình tính
toán phù hợp với vấn đề này. Chương trình
được biểu diễn bởi một chuỗi các vòng lặp, đối
với mỗi vòng lặp một đỉnh có thể nhận các thông
điệp được gửi đi trong vòng lặp trước, gửi thông
điệp tới những đỉnh khác, thay đổi trạng thái của
chính nó và trạng thái của các cạnh đi ra từ nó
hoặc biến đổi cấu trúc của đồ thị. Cách tiếp cận
tập trung vào các đỉnh đủ linh hoạt để biểu diễn
các thuật toán. Mô hình được thiết kế cho phiên
bản cài đặt có hiệu năng cao, khả năng mở rộng
và chịu lỗi trên các cụm máy chủ gồm hàng
nghìn các máy tính thông thường, và khả năng
đồng bộ của nó giúp cho việc lập trình trở nên
dễ dàng hơn. Các chi tiết liên quan đến sự phân
tán được che giấu bên dưới một API trừu tượng.
Kết quả là một framework cho việc xử lý một đồ
thị lớn mà thuận tiện cho việc biểu đạt và dễ
dàng cho việc lập trình.
1. Giới thiệu chung
Mạng internet đã làm cho đồ thị mạng trở
thành đề tài phần tích và nghiên cứu phổ biến.
Web 2.0 tăng thêm sự quan tâm của mạng xã
hội. Các đồ thị lớn, ví dụ bao gồm chuyển tin qua
các router, sự tương đồng của các bài báo,
đường phát tán của bệnh tật, hoặc các đường
trích dẫn đến các bài báo khoa học khác nhau,
đã được xử lý trong hàng thập kỷ. Các thuật toán
phổ biến bao gồm tìm đường đi ngắn nhất, các
loại phân loại khác nhau, và các biến thể xếp
hạng các trang. Có nhiều vấn đề tính toàn đồ thị
đối với các giá trị thực tế, như đường cắt nhỏ
nhất và các thành phần được nối.
Hiệu năng xử lý của một đồ thị lớn là một
thách thức. Các thuật toàn đồ thị thường cho
thấy sự ít ỏi trong khả năng truy cập bộ nhớ cục
bộ, gần như không có công việc nào được thực
thi ở mỗi đỉnh và sự kém linh hoạt trong việc xử
lý song song. Sự phân tán trên nhiều máy làm
tăng các vấn đề cục bộ và làm tăng khả năng thấ
bại trong việc tính toàn của một máy. Mặc dù sự
tồn tại của đồ thị lớn ở khắp nơi và tính thương
mại cao của chúng, nhwng chúng ta biết được
không có hệ thống có khả năng mở rộng và
hướng tới một mục đích chung nào cho việc cài
đặt thuật toán đồ thị phù hợp với tất cả các đồ
thị trong môi trường phân tán lớn.
Cài đặt một thuật toán cho việc xử lý một đồ
thị lớn nghĩa là chọn một trong các lựa chọn sau:
1. Tự xây dựng một cơ sở hạ tầng phân tán
riêng, thường đòi hỏi sự nỗ lực trong việc
thực thi mà phải lặp đi lặp lại mỗi khi thay
đổi thuật toán hoặc cách biểu diễn đồ thị.
2. Dựa trên các nền tảng hệ phân tán có sẵn,
thường không phù hợp cho việc xử lý đồ thị.
MapReduce là một ví dụ điển hình cho sự
2. phù hợp của một mảng lớn trong việc tính
toán vấn đề đồ thị lớn. Nó đôi khi được
dùng để khai phá đồ thị lớn, nhưng điều này
có thể dẫn đến việc phải tối ưu hóa hiệu
năng và vấ đề về bộ nhớ. Mô hình cơ bản
cho việc xử lý dữ liệu đã được mở rộng để
làm thuận tiên hơn cho việc kết tập và thực
thi các câu truy vấn giống như SQL, nhưng
những mở rộng này thường không được lý
tưởng cho các thuật toán đồ thị mà thường
phù hợp hơn cho mô hình truyền tin.
3. Sử dụng thư viện thuật toán đồ thị cho một
máy tính, như là BGL, LEDA, NetworkX,
JDSL, Standford GraphBase, hoặc FGL, giới
hạn độ lớn của vấn đề tới mức mà có thể xử
lý được.
4. Sử dụng những hệ thống đồ thị song song
có sẵn. Sử dụng song song thư viện BGL và
CGMgraph biểu diễn thuật toán đồ thị song
song, nhưng không cho phép chịu lỗi hay xử
lý các vấn đề khác – những vấn đề rất quan
trọng đối với những hệ thống phân tán lớn.
Không có một phương pháp thay thế nào phù
hợp. Để giải quyết vấn đề xử lý sự phân tán của
các đồ thị lớn, chúng tôi đã xây dựng một nền
tảng có khả năng mở rộng và có khả năng chịu
lỗi với một API mà đủ linh hoạt trong việc thể
hiện tham vọng của thuật toán đồ thị. Bài báo
này miêu tả hệ thống được gọi là Pregel và báo
cáo các kinh nghiệm của chúng tôi với hệ thống
này.
3. Cách thức tổ chức ở mức cao của Pregel lấy cảm
hứng từ mô hình đồng bộ song song cụm của
Valiant. Pregel tính toán bằng những vòng lặp
được gọi là superstep. Trong một superstep,
framework gọi tới chức năng do người dùng
định nghĩa cho mỗi đỉnh một cách song song.
Chức năng chỉ rõ hoạt động ở một đỉnh V ở một
superstep S. Nó có thể đọc thông điệp gửi đến V
trong superstep S–1, gửi thông điệp tới những
đỉnh khác mà sẽ nhận được trong superstep S +
1, và thay đổi trạng thái của V và của những
cạnh đi ra từ nó. Thông điệp thường được gửi đi
thông qua các cạnh, nhưng thông điệp có thể gửi
đi tới bất kỳ đỉnh nào với điều kiện biết được
định danh của nó.
Cách thức tiếp cận tập trung vào các đỉnh
giống MapReduce ở điểm là người dùng tập
trung vào các hoạt động ở cục bộ, xử lý mỗi đối
tượng một cách độc lập, và hệ thống biên soạn
những hoạt động này để có thể xử lý tập dữ liệu
lớn. Bằng cách xây dựng mô hình phù hợp cho
hệ phân tán: nó không để lộ bất kỳ cơ chế nào
để phát hiện thứ tự thực hiện lệnh trong một
superstep và các giao tiếp giữa các superstep.
Sự đồng bộ của mô hình này làm nó dễ dàng
hơn trong việc suy luật ngữ nghĩa của chương
trình khi cài đặt giải thuật, và chắc chắn rằng
chương trình viết bằng pregel sẽ không gặp
trường hợp dead-lock và data races thường thấy
trong các hệ thống đồng bộ. Theo nguyên tắc,
hiệu năng của chương trình pregel có tính cạnh
tranh với những hệ thống bất đồng bộ mà được
cấp đủ slack song song. Bởi vì tính toán đồ thị
thông thường có nhiều đỉnh hơn các máy rất
nhiều, nên một giải thuật cần phải cân bằng tải
của máy để việc đồng bộ giữa các superstep
không phải chịu thêm độ trễ đáng kể.
2. Mô hình tính toán
Đầu vào cho việc tính toán Pregel là một đồ thị
có hướng. Trong đó mỗi đỉnh được đặc trưng
bởi một xâu định danh. Mỗi đỉnh được liên kết
với một giá trị có thể thay đổi được định nghĩa
bởi người sử dụng. Cạnh có hướng được liên kết
với các đỉnh nguồn và mỗi cạnh bao gồm bởi
một giá trị có thể thay đổi được định nghĩa bởi
người sử dụng.
Việc tính toán Pregel đặc trưng bao gồm đầu
vào, được bắt đầu từ khi đô thị được khởi tạo,
theo sau là một chuỗi liên tiếp các superstep
được ngăn cách với nhau bởi điểm đồng bộ hóa
toàn cục và tiếp diễn cho tới khi thuật toán được
ngắt và kết thúc với đầu ra.
Trong các superstep các đỉnh được tính toán
song song. Mỗi superstep thực thi một chức
năng của người sử dụng và thể hiện ra logic
thuật toán. Một đỉnh có thể tự thay đổi trạng
thái của nó hoặc trạng thái của các cạnh đi ra từ
nó, nhận các thông điệp được gửi tới nó trong
superstep đó, gửi thông điệp tới các đỉnh khác (
sẽ được nhận trong superstep tiếp theo), hoặc
thậm chí thay đổi cấu trúc của đồ thị. Các cạnh
không phải là đối tượng bậc nhất trong mô hình
và không có bất cứ liên quan gì đến với việc tính
toán.
Vote to halt
Active Inactive
Message received
Figure 1: Vertex State Machine
Việc dừng thuật toán dựa trên việc các đỉnh đề
xuất dừng. Trong superstep 0, mọi đỉnh đều
trong trạng thái hoạt động. Tất cả các đỉnh đang
hoạt động đều tham gia vào việc tính toán của
bất kỳ superstep nào. Mội đỉnh tự ngưng hoạt
động bằng cách đề xuất để ngắt. Điều này có
nghĩa là đỉnh đó không còn bất cứ công việc nào
để thực hiện trừ khi nó được kích hoạt từ bên
ngoài và Pregel framework sẽ không thực thi
đỉnh đó trong các superstep tiếp theo nếu như
nó không nhận được thông điệp. Nếu như được
khởi động lại bằng các thông điệp, một đỉnh bắt
buộc phải tự ngừng hoạt động lại một cách
4. tường minh. Thuật toán được ngắt hoàn toàn
khi tất cả các đỉnh đều ngừng hoạt động và
không có bất cứ thông điệp nào được truyền đi.
Mô hình đơn giản của trạng thái được mô tả
trong hình 1.
Đầu ra của một chương trình Pregel là một tập
các giá trị tường minh được đưa ra bởi các đỉnh.
Nó thường là các đồ thị định hướng đẳng cấu với
đầu vào nhưng không nhất thiết bởi các đỉnh và
các cạnh có thể được thêm vào hoặc bớt đi
trong quá trình tính toán. Ví dụ một thuật toán
phân cụm có thể sinh ra một tập các đỉnh không
liên kết với nhau được chọn từ đồ thị lớn. Một
thuật toán khai phá đồ thị đơn giản có thể cho
đầu ra là tập hợp các thống kê được khai phá từ
đồ thị.
Hình 2 minh họa các khái niệm này sử dụng
một ví dụ đơn giản: Cho một đồ thị được kết nối
chặt. Mỗi đỉnh bao gồm một giá trị và nó sẽ
truyền giá trị lớn nhất tới tất cả các đỉnh. Trong
mỗi superstep, bất cứ đỉnh nào tìm được giá trị
lớn hơn từ các thông điệp sẽ gửi giá trị đó cho
các đỉnh liền kề nó. Khi không còn thêm bất cứ
thay đổi nào của các đỉnh trong các superstep thì
thuật toán sẽ dừng lại.
Chúng ta chọn mô hình truyền thông điệp
thuần túy, bỏ đọc từ xa và các phương pháp
khác để thực hiện việc chia sẻ dữ liệu bởi 2 lí do
sau. Thứ nhất, mô hình truyền thông điệp đủ để
thể hiện rằng không nhất thiết phải có quá trình
đọc từ xa. Thứ 2, lựa chọn này sẽ tốt hơn về hiệu
năng. Trong môi trường phân cụm, việc đọc một
giá trị từ một máy chủ ở xa gây ra độ trễ cao khó
có thể tránh được. Mô hình truyền thông điệp
cho phép chúng ta có thể bù lại độ trễ bằng cách
gửi các thông điệp một cách bất đồng bộ theo
nhiều lô.
Thuật toán đồ thị có thể được viết như một
chuỗi liên liên tục các lời gọi MapReduce. Chúng
ta chọn một mô hình khác vì khả năng sử dụng
và hiệu năng. Pregel giữ các cạnh và đỉnh trên
một máy chủ mà thực hiện việc tính toán và chỉ
sử dụng mạng để truyền các thông điệp. Tuy
nhiên MapReduce cũng thuần túy là lập trình
hướng chức năng, do đó việc thực hiện thuật
toán như một chuỗi MapReduce đòi hỏi cần phải
truyền toàn bộ trạng thái của đò thị từ một giai
đoạn sang giai đoạn tiếp theo – nói chung nó sẽ
đòi hỏi nhiều việc giao tiếp và các vấn đề tuần tự
hóa kết hợp. Hơn nữa, các vòng lặp thông qua
các superstep sẽ tránh được việc lập trình phức
tạp – cái mà sẽ xảy ra khi điều phối các bước
trong một chuỗi MapReduce.
5. 3 6 2 1
Superstep
0
6 6 2 6
Superstep
1
6 6 6 6
Superstep
2
6 6 6 6
Superstep
3
Figure 2: Maximum Value Example. Dotted lines
are messages. Shaded vertices have voted to
halt.
3. C++ API
Phần này sẽ nói về khía cạnh quan trọng nhất
của pregel, C++ API, bỏ qua những vẫn để liên
quan đến cơ chế.
Viết một chương trình Pregel liên quan đến
việc kế thừa lại (subclassing) lớp Vertex đã được
định nghĩa trước. Các tham số mẫu của nó định
nghĩa 3 loại giá trị, liên quan đến các đỉnh, cạnh
và các thông điệp. Mỗi đỉnh có một giá trị liên
kết của một loại nhất định. Sự bất tương đồng
dường như gây ra hạn chế, nhưng người dùng có
thể xử lý bằng cách sử dụng các kiểu linh hoạt
như bộ đệm của giao thức. Các kiểu cạnh và
thông điệp xử lý tương tự.
Người dùng ghi đè phương thức Compute (),
phương thức mà sẽ được thực hiện tại mỗi đỉnh
đang hoạt động trong mỗi superstep. Các
phương thức được định nghĩa trước của lớp
Vertex cho phép Compute() truy xuất thông tin
về đỉnh hiện tại và các cạnh của nó, và gửi thông
điệp tới các đỉnh khác. Compute() có thể dò giá
trị liên quan tới đỉnh của nó thông qua phương
thức GetValue() hoặc thay đổi nó thông qua
phương thức MutableValue(). Nó có thể dò và
thay đổi những giá trị của những cạnh đi ra bằng
cách sử dụng phương thức được đã được cung
cấp thông qua việc duyệt các cạnh đi ra. Việc cập
nhật trạng thái sẽ được nhìn thấy ngay lập tức.
Vì khả năng hiển thị bị hạn chế đối với các đỉnh
bị sửa đổi, sẽ không có hiện tượng data
racestrên các giá trị đồng thời được truy cập từ
các đỉnh khác nhau.
Các giá trị liên kết với các đỉnh và các cạnh của
nó chỉ là trạng thái cho từng đỉnh mà không đổi
trong suốt các superstep. Giới hạn trạng thái đồ
thị được quản lý bởi framework tới một giá trị
mỗi đỉnh và cạnh đơn giản hóa chu kỳ tín toán
chính, phân tán đồ thị và phục hồi khi gặp lỗi.
3.1 Truyền tin
Các đỉnh giao tiếp trực tiếp với nhau bằng các
gửi các thông điệp. Mỗi thông điệp chứa giá trị
của thông điệp và tên của đích đến. Kiểu của giá
trị thông điệp sẽ được chỉ rõ bởi người dùng ở
tham số mẫu của lớp Vertex.
Một dỉnh có thể gửi các thông điệp với số
lượng bất kỳ trong 1 superstep. Tất cả các thông
điệp được gửi đến đỉnh V trong superstep S sẽ
được thực thi khi phương thức Compute() của
đỉnh V được gọi ở superstep S+1 thông qua một
con trỏ lặp. Thứ tự của các thông điệp sẽ không
được lưu trữ trong con trỏ lặp, nhưng các thông
điệp chắc chắn sẽ được gửi đi và chúng sẽ không
bị trùng lặp.
Một cách dùng thông dụng là cho 1 đỉnh V
duyệt qua các cạnh đi ra từ nó, gửi thông điệp
đến đỉnh đích của mỗi cạnh, như trong thuật
toán PageRank. Tuy nhiên, dest_vertex không
cần phải là đỉnh kề của V.
6. template <typename
VertexValue,
typename
EdgeValue,
typename
MessageValue>
class Vertex
{ public:
virtual void Compute(MessageIterator* msgs)
= 0;
const string& vertex_id()
const; int64 superstep()
const;
const VertexValue& GetValue();
VertexValue* MutableValue();
OutEdgeIterator
GetOutEdgeIterator();
void SendMessageTo (const string&
dest_vertex, const
MessageValue&
message);
void VoteToHalt ();
};
Figure 3: The Vertex API foundations.
Một đỉnh có thể học được định danh của một
đỉnh không kề từ thông điệp nhận từ trước, hoặc
các định danh của các đỉnh có thể được ngầm
định. Ví dụ như đồ thị có thể là một cụm, và
được định danh công khai từ V1 đến Vn, trong
trường hợp này thậm chí có thể không cần tới
những cạnh rõ ràng trên đồ thị.
Khi một đỉnh đích của một thông điệp bất kỳ
không tồn tại, các bộ xử lý được người dùng
định nghĩa sẽ được thực thi. Ví dụ bộ xử lý có
thể tạo ra một đỉnh đang thiếu hoặc gỡ bỏ một
cạnh thừa từ đỉnh của nó.
3.2 Bộ kết hợp
Việc gửi một thông điệp, đặc biệc tới một đỉnh
trên một máy khác, chịu một số chi phí. Điều này
có thể được giảm thiểu trong một số trường hợp
với sự trợ giúp của người dùng. Ví dụ, giả sử
rằng Compute() nhận các thông điệp dưới dạng
số nguyên và chỉ cần tính tổng chứ không cần
các giá trị từng phần. Trong trường hợp đó, hệ
thống có thể kết hợp nhiều thông điệp hướng
tới đỉnh V vào thành 1 thông điệp chứa tổng,
giúp giảm thiểu số lượng thông điệp cần chuyển
đi và lưu trong buffer.
Bộ kết hợp không được kích hoạt theo mặc
định, bởi vì không có một cơ chế nào để tìm ra
một hàm kết hợp mà đồng bộ với phương thức
Compute() của người dùng. Để kích hoạt phương
thức tối ưu này, người dùng sẽ viết lớp con của
lớp Combiner, ghi đề phương thức Combine ().
Không thể biết được những thông điệp nào sẽ
được kết hợp (nếu có), các nhóm nào sẽ được
kết hợp, hoặc thứ tự kết hợp, vì vậy bộ kết hợp
sẽ chỉ được kích hoạt cho các tiến trình có tính
giao hoán và kết hợp.
Đối với một số thuật toán, ví dụ như thuật
toán tìm đường ngắn nhất từ đỉnh nguồn, chúng
ta sẽ tìm hiểu cách giảm lưu lượng thông điệp 4
lần bằng cách sử dụng combiners.
3.3 Aggregators
Pregel aggregators là một cơ chế cho giao tiếp
toàn cục, giám sát và dữ liệu. Mỗi đỉnh có thể
cung cấp một giá trị cho một aggregator trong
superstep S, hệ thống kết hợp các giá trị đó bằng
toán tử tối giảm, và giá trị trả về được cấp cho
mọi đỉnh trong superstep S + 1. Pregel bao gồm
một số aggregtors được định nghĩa sẵn, ví dụ
như min, max, hoặc sum đối với kiểu số nguyên
hoặc chuỗi.
Các aggregator có thể sử dụng cho thống kê. Ví
dụ sum aggregator áp dụng cho các cạnh đi ra
của mỗi đỉnh là tổng các cạnh của đồ thị.
7. Các toán tử tối giản phức tạp có thể tạo ra
những biểu đồ thống kê.
Các aggregator còn có thể được sử dụng cho
việc điều phối toàn cục. Ví dụ như, một nhánh
của Compute() có thể thực thi cho các superstep
cho đến khi một aggregator nhận định là tất cả
các đỉnh đã thỏa mãn một số điều kiện nào đó,
tiếp theo một nhánh khác có thể thực thi cho
đến khi kết thúc. Một aggregator min hoặc max,
áp dụng cho ID của đỉnh, có thể được sử dụng
để chọn một đỉnh để đóng vai trò phân biệt
trong một thuật toán.
Để định nghĩa một aggregator mới, người dùng
viết lớp con của lớp Aggregator đã được định
nghĩa trước, và chỉ rõ cách giá trị tổng hợp được
khởi tạo của từ giá trị đầu vào và cách từ nhiều
phân của giá trị tổng hợp tối giản về một giá trị.
Các toán tử của Aggregation nên có tính giao
hoán và kết hơp.
Theo mặc định một aggregator chỉ nên giảm
thiểu giá trị đầu vào từ một superstep, nhưng có
thể định nghĩa một sticky aggregator mà dùng
những giá trị đầu vào từ tất cả các superstep.
Điều này rất hữu dụng, ví dụ như, để giữ một số
đếm số cạnh toàn cục mà chỉ thay đổi khi mà các
cạnh được thêm vào hay loại bỏ.
Những chức năng nâng cao có thể được cài
đặt. Ví dụ như, một aggregator có thể được sử
dụng để cài đặt một hàng đợi ưu tiên phân tán
cho thuật toán đường delta ngắn nhất. Mỗi đỉnh
được chỉ định tới một đống ưu tiên dựa trên
khoảng cách ước lượng của nó. Điểm nhỏ nhất
được quảng bá tất cả các máy thợ trong
superstep tiếp theo và các đỉnh trong đống có
index nhỏ nhất nới lỏng các cạnh.
3.4 Biến đổi cấu trúc
Một số thuật toán đồ thị cần thay đổi cấu trúc
của đồ thị. Ví dụ như một thuật toán gom nhóm
có thể thay thế một nhóm bằng một đỉnh, và
một thuật toán nhánh cây nhỏ nhất có thể loại
bỏ tất cả trừ các nhánh cây. Cũng như hàm
Compute() của người dùng có thể gửi các thông
điệp, việc biến đổi cấu trúc có thể xử lý các yêu
cầu thêm hoặc loại bỏ các đỉnh hoặc các cạnh.
Nhiều đỉnh có thể gặp xung đột yêu cầu trong
cùng một superstep (Ví dụ như 2 yêu cầu để
thêm đỉnh V với 2 giá trị khởi tạo khác nhau).
Chúng ta sử dụng 2 cơ chế để đạt được sự thống
nhất: sắp xếp thứ tự từng phần và bộ xử lý.
Đối với các thông điệp, sự biến đổi trở nên
hiệu quả trong superstep sau khi mỗi yêu cầu
được gửi đi. Trong superstep đó việc loại bỏ
được thực thi đầu tiên, loại bỏ cạnh trước khi
loại bỏ đỉnh, vì việc loại bỏ một đỉnh mặc định
loại bỏ tất cả các cạnh đi ra từ nó. Việc thêm vào
diễn ra tiếp theo việc loại bỏ, với việc thêm đỉnh
trước khi thêm cạnh và tất cả các biến đổi đều
gọi tới Compute(). Việc sắp xếp thứ tự từng
phần giải quyết cho hầu hết các xung đột.
Những xung đột còn lại được xử lý bởi bộ xử lý
do người dùng định nghĩa. Nếu như nhiều yêu
cầu sinh thêm cùng một đỉnh trong cùng một
superstep, thì theo mặc định của hệ thống sẽ
chọn một cách tùy tiện, nhưng người dùng với
những yêu cầu đặc biệt có thể cụ thể hóa một
chính sách giải quyết xung đột tốt hơn bằng
cách định nghĩa một phương thức của bộ xử lý
phù hợp trong lớp con của Vertex. Cơ chế tương
tự bộ xử lý có thể được sử dụng để giải quyết
xung đột do nhiều yêu cầu loại bỏ đỉnh, thêm
cạnh cũng như loại bỏ cạnh. Chúng ta ủy thác
phương thức giải quyết cho bộ xử lý để giữ cho
code của phương thức Compute() đơn giản,
điều này giảm thiểu việc ảnh hưởng lẫn nhau
của bộ xử lý và Compute(), nhưng điều này chưa
bao giờ là vấn đề trong thực tế.
Cơ chế phối hợp rất lỏng lẻo: sự thay đổi toàn
cục không yêu cầu sự điều phối cho đến khi
chúng được áp dụng. Lựa chọn thiết kế này làm
đơn giản hóa việc xử lý luồng.
Mấu chốt là xung đột liên quan đến sự thay
đổi của một đỉnh V được xử lý bởi chính đỉnh V
đó. Pregel cũng hỗ trợ biến đổi cục bộ, ví dụ như
một đỉnh thêm hoặc xóa các cạnh đi ra từ chính
nó hoặc tự xóa chính nó. Biến đổi cục bộ không
8. thể gây ra xung đội và ngay lập tức làm chúng
hiệu quả và dễ dàng cho việc lập trình phần tán
bằng cách sử dụng một loại các câu lệnh dễ hiểu
hơn.
3.5 Đầu vào và đầu ra
Có những nhiều định dạng file cho đồ thị, ví dụ
như file text, một tập các đỉnh trong hệ cơ sở dữ
liệu quan hệ hoặc các hàng trong Bigtable. Để
tránh áp đặt một định dạng nhất định của file,
Pregel phân giải nhiệm vụ của việc thông dịch
một file đầu vào như một đồ thị từ nhiệm vụ của
việc tính toán đồ thị. Tương tự, đầu ra có thể
được sinh ra trong một định dạng tùy ý và có thể
lưu trữ trong form mà phù hợp nhất cho ứng
dụng. Thư viện Pregel cung cấp Readers và
Writers cho nhiều định dạng file phổ biến, nhưng
người dùng với những nhu cầu bất thường cần
phải tự viết các lớp con của các lớp trừu tượng
cơ sở Reader và Writer để xử lý vấn đề này.
4. Cài đặt
Pregel được thiết kế cho kiến trúc phân cụm
của Google. Mỗi cụm gồm hàng nghìn PC thông
thường được sắp xếp vào các rãnh với băng
thông nội rãnh rộng. Các cụm được nội kết nối
với nhau nhưng được phân tán theo địa lý.
Chương trình thường được xử lý trên một hệ
thống quản lý cụm có chức năng lập lịch các công
việc để tối ưu hóa việc cấp phát các tài nguyên,
đôi khi loại bỏ các thể hiện hoặc chuyển chúng
đến những máy khác. Hệ thông bao gồm dịch vụ
quản lý tên, để các thể hiện có thể tham chiếu
đến thông qua tên logic không bị phụ thuộc vào
máy mà chúng đang được lưu trữ. Dữ liệu ít thay
đổi được lưu trữ dưới dạng file trên hệ thông
lưu trữ phân tán, GFS, hoặc trong Bigtable, và dữ
liệu tạm thời ví dụ như thông điệp trong buffer
lưu trữ trên ổ đĩa cục bộ.
4.1 Kiến trúc cơ bản
Thư viện của Pregel chia đồ thị thành nhiều
phần, mỗi phần chứa một tập các đỉnh và tất cả
các cạnh đi ra từ các đỉnh đó. Việc gán một đỉnh
vào một phần dựa hoàn toàn vào ID của đỉnh đó,
vì vậy có thể biết được một đỉnh thuộc phần nào
của đồ thị cho dù đỉnh đó thuộc về một máy tính
khác, hoặc thậm chí là đỉnh đó chưa được tạo ra.
Chức năng chia phần mặc định là lấy phần dư
của phép chia của hash(ID) cho N với N là số
phần mà đồ thị được phân chia, nhưng người
dùng có thể ghi đè chức năng này.
Việc gán các đỉnh với các máy thợ là phần
chính mà người dung có thể thấy được. Một số
ứng dụng hoạt động tốt với cách gán mặc định,
nhưng một số lại hoạt động tốt hơn với các cách
gán tự đề xuất để khai thác tốt hơn tính cục bộ
vốn có của đồ thị. Ví dụ như, một hàm đánh giá
thông dụng sử dụng cho đồ thị Web là để ghép
các đỉnh đại diện cho các trang của cùng một
web site.
Nếu không xảy ra lỗi, việc thực thi của chương
trình Pregel bao gồm các giai đoạn:
1. Nhiều bản sao của chương trình người dùng
bắt đầu bằng cách thực thi trên một nhóm
các máy tính. Một trong số chúng hoạt động
như một máy chủ chính. Nó không được
gán vào bất kỳ phần nào của đồ thị, nhưng
nó chịu trách nhiệm điều phối các hoạt
động của máy thợ. Các máy thợ sử dụng
dịch vụ quản lý tên của hệ thống quản lý
cụm để tìm ra địa điểm của máy chủ, và gửi
thông điệp đang ký đến máy chủ chính.
9. 2. Máy chủ chính quyết định đồ thị sẽ được
phân chia ra làm bao nhiêu phân vùng, và
gán một hoặc nhiều phân vùng của đồ thị
cho từng máy thợ. Số lượng có thể được
điều chỉnh bởi người dùng. Có nhiều hơn
một phân vùng mỗi máy thợ cho phép song
song hóa giữa các phân vùng và cân bằng tải
tốt hơn, và thường sẽ tăng hiệu năng. Mỗi
máy thợ có nhiệm vụ bảo trì trạng thái của
các phần đồ thị của nó, thực thi Compute()
của người dùng trên các đỉnh mà nó quản
lý, và quản lý các thông điệp đến và đi. Mỗi
máy thợ đều biết máy nào được gán phần
đồ thị nào.
3. Máy chủ chính phân một phần của các giá
trị đầu vào của người dùng cho các máy thợ.
Đầu vào được coi như một tập các bản ghi,
mà mỗi bản ghi chứa một số lượng bất kỳ
các đỉnh và các cạnh. Sự phân chia đầu vào
khớp với phân vùng của đồ thị của nó, và
thông thường dựa trên giới hạn của file.
Nếu một máy thợ tải một cạnh thuộc về
một máy khác, cấu trúc dữ liệu phù hợp sẽ
được cập nhật ngay lập tức. Nếu không máy
thợ đó sẽ đưa một thông điệp vào hàng đợi
cho máy thợ chưa đỉnh đó. Sau khi đầu vào
tải xong, tất cả các đỉnh sẽ được đánh dấu là
đang hoạt động.
4. Máy chủ chính hướng dẫn cho từng máy
thợ để thực hiện một superstep. Máy thợ sẽ
duyệt qua các đỉnh đang hoạt động, mỗi
phần sẽ sử dụng một luồng riêng biệt. Máy
thợ gọi hàm Compute() cho từng đỉnh đang
hoạt động, truyền những thông điệp mà
được gửi tới trong những superstep trước.
Những thông điệp mà được gửi đi một cách
không đồng bộ gây nên sự chồng chéo trong
tính toán và giao tiếp và xếp lô, nhưng được
gửi đi trước khi kết thúc superstep. Khi một
máy thợ hoàn thành, nó sẽ phàn hồi cho
máy chủ chính, trả về số lượng đỉnh sẽ hoạt
động trong superstep tiếp theo.
Bước này được lặp đi lặp lại cho đến khi tất
cả các đỉnh đều không còn hoạt động, hoặc
không còn thông điệp đang được chuyển
giao.
5. Sau khi công việc tính toán kết thúc, máy
chủ chính có thể đưa ra chỉ thị cho từng
máy thợ lưu lại phần đồ thị của nó.
4.2 Khả năng chịu lỗi
Khả năng chịu lỗi được thể hiện qua các điểm
mốc. Ở điểm bắt đầu của superstep, máy chủ
chính chỉ định cho các máy thợ lưu lại trạng thái
của chúng vào kho, bao gồm các giá trị của các
đỉnh, giá trị các cạnh và các thông điệp đến; máy
chủ chính lưu một cách riêng biệt các giá trị
aggregator.
Các lỗi ở máy thợ được phát hiện bằng cách
máy chủ chính sẽ “ping” đến các máy thợ. Nếu
một máy thợ không nhận được ping sau một
khoảng thời gian nhất định, máy thợ đó sẽ
ngừng lại. Nếu máy chủ chính không nhận phản
hồi từ máy thợ, máy chủ chính đánh dấu tiến
trình của máy thợ đó gặp lỗi.
Khi một hay nhiều hơn một máy thợ gặp sự cố,
trạng thái hiện tại được gán cho chúng sẽ bị mất.
Máy chủ chính sẽ gán lại phần của đồ thị đó cho
các máy thợ đang hoạt động còn lại, và chúng sẽ
tải lại các trạng thái gần nhất ở đầu của một
superstep S. Điểm mốc đó có thể từ những
superstep trước superstep gần nhất S0
một vài
superstep và được hoàn thành bởi bất kỳ phần
nào trước khi gặp lỗi, việc cần thực hiện là phục
hồi những superstep bị mất. Việc chọn những
mốc thường dựa trên tần suất gặp lỗi của mô
hình, cân bằng chi phí tạo mốc và chi phí ước
tính cho việc phục hồi.
Việc hạn chế trong phục hồi đang được phát
triển để giảm chi phí và độ trễ của việc phục hồi.
Ngoài các mốc cơ bản, máy thợ có thể ghi lại các
thông điệp chuyển đi từ phần của nó trong khi
đồ thị được tải và giữa các superstep. Việc phục
hồi từ đó được giới hạn trong các phần bị mất
mà được phục hồi từ các mốc. Hệ thông tính
toán lại những superstep bị mất cho đến
superstep S0
bằng cách sử dụng các thông điệp
từ các phần không bị lỗi và tính toán lại các
superstep từ các phần đang được phục hồi.
10. Hướng tiếp cận này tiết kiệm tài nguyên tính
toán trong khi phục hồi bằng cách chỉ tính toán
lại phần bị mất, và có thể giảm độ trễ của phục
hồi vì mỗi máy thợ có thể phục hồi một vài phần.
Lưu lại nhưng thông điệp được chuyển đi tăng
thêm chi phi, nhưng một máy tính thông thường
có ở nhớ phù hợp để đảm bảo rằng việc vào ra
không trở thành một nút thắt cổ chai.
Giới hạn việc phục hồi đòi hỏi thuật toán của
người dùng phải được xác định, để tránh sự
thiếu đồng bộ vì trộn lẫn các thông điệp được
lưu từ những thực thi gốc với những thông điệp
mới từ việc phục hồi. Thuật toán ngẫu nhiên có
thể được làm cho rõ ràng bằng cách thêm vào
một bộ tạo số ngẫu nhiên với kết quả dựa trên
superstep và các phần được phân. Thuật toán
không xác định có thể vô hiệu hóa giới hạn phục
hồi và trở lại cơ chế phục hồi cơ bản.
4.3 Cài đặt máy thợ
Một máy thợ lưu trữ trạng thái của phân vùng
đồ thị của nó trong bộ nhớ. Khái niệm này có thể
hiểu như một bảng quy chiều từ ID của đỉnh đến
trạng thái của từng đỉnh, trạng thái của từng
đỉnh bao gồm giá trị hiện tại của nó, một danh
sách các cạnh đi từ nó ra (cạnh đi ra từ nó bao
gồm ID của đỉnh, và giá trị hiện tại của cạnh),
một hàng đợi bao gồm những thông điệp gửi tới,
và một cờ để chỉ định đỉnh có hoạt động hay
không. Khi một máy thợ thực hiện một
superstep nó duyệt qua tất cả các đỉnh và gọi
Compute(), truyền vào đó giá trị hiện tại, một
con trỏ lặp đến các thông điệp gửi tới, và một
con trỏ lặp đến các cạnh đi ra. Không có truy
nhập đến các cạnh đi vào vì mỗi cạnh đi vào là
một phần của một danh sách lưu b ởi đỉnh
nguồn, thường ở một máy tính khác.
Vì vấn đề về hiệu năng, cờ của các đỉnh đang
hoạt động được lưu trữ một cách riêng biệt với
hàng đợi các thông điệp gửi tới. Hơn nữa, trong
khi chỉ có một bản sao lưu của đỉnh và giá trị
cạnh tồn tại, thì có tới 2 bản sao lưu của cờ của
đỉnh hoạt động và hàng đợi các thông điệp gửi
tới: một bản cho superstep hiện tại và bản còn
lại cho superstep tiếp theo.
Trong khi các máy thợ xử lý đỉnh của nó trong
superstep S, trong một luồng khác, nó nhận các
thông điệp từ những máy thợ khác đang thực thi
cùng superstep. Vì các đỉnh nhận được thông
điệp mà được gửi tới trong superstep trước đó,
các thông điệp cho superstep S và S + 1 phải
được giữ riêng biệt. Tương tự, các thông điệp
đến đỉnh V nghĩa là V sẽ hoạt động trong
superstep tiếp theo, mà không nhất thiết phải là
superstep hiện tại.
Khi Compute() yêu cầu gửi một thông điệp tới
một đỉnh khác, đầu tiên máy thợ sẽ quyết định
xem đỉnh đích có thuộc máy khác hay không hay
thuộc chính máy đó. Nếu đỉnh đích thuộc máy
ngoài, thông điệp được đưa vào buffer để đưa
đến máy đích. Khi kích thước của buffer đạt một
ngưỡng nhất định, buffer lớn nhất bị xóa một
cách bất đồng bộ, gửi từng thông điệp đến máy
đích như một thông điệp đơn. Trong trường hợp
đỉnh đích thuộc máy gửi, thông điệp sẽ được
đưa trực tiếp vào hàng đợi các thông điệp đến
của đỉnh đích.
Nếu người dùng sử dụng bộ kết hợp, nó sẽ
được thực thi khi các thông điệp được đưa vào
hàng đợi các thông điệp gửi đi và khi chúng
được nhận tại hàng đợi các thông điệp gửi tới.
Khi chúng được nhận, chúng sẽ không làm giảm
lượng băng thông được sử dụng, nhưng làm
giảm bộ nhớ cần để lưu trữ các thông điệp.
11. 4.4 Cài đặt máy chủ chính
Máy chủ chính có chức năng điều phối các
hoạt động của các máy thợ. Mỗi máy thợ được
gán một định danh duy nhất ở thời điểm nó
được thêm vào hệ thống. Máy chủ chính lưu trữ
danh sách các máy thợ hiện tại đang hoạt động,
bao gồm định danh, thông tin về địa chỉ, phần
đồ thị mà nó quản lý. Kích thước của cấu trúc dữ
liệu của máy chủ chính tỉ lệ với lượng máy thợ,
chứ không phải lượng đỉnh hay cạnh, vì thế mỗi
máy chủ chính có thể điều phối tính toán cho cả
những đồ thị rất lớn.
Hầu hết các hoạt động của máy chủ chính, bao
hồm đầu vào, đầu ra, tính toán, lưu trữ và phục
hồi từ các mốc đều kết thúc tại điểm biên: máy
chủ chính gửi cùng một thông điệp đến các máy
thợ đang được cho là hoạt động từ lúc bắt đầu
phiên làm việc và đợi phàn hồi từ những máy
đó. Nếu bất kỳ máy thợ nào gặp lỗi, máy chủ
chính sẽ được đưa vào trạng thái phục hồi. Nếu
điểm biên đồng bộ thành công, máy chủ chính
tiếp tục phiên làm việc tiếp theo. Ví dụ như
trong trường hợp nếu một điểm biên tính toán,
máy chủ chính sẽ tăng chỉ số của superstep toàn
cục và xử lý tiếp superstep tiếp theo.
Máy chủ chính cũng thống kê về quá trình tính
toán và trạng thái của đồ thị, như tổng kích
thước của đồ thị, biểu đồ thống kê sự phân tán
của các cạnh, số lượng đỉnh đang hoạt động,
thời gian và lưu lượng thông điệp của những
superstep gần đấy, và giá trị của tất cả
aggregator mà người dùng định nghĩa. Để kích
hoạt giao diện người dùng, máy chủ chính chạy
những server HTTP hiển thị các thông tin.
4.5 Aggregators
Một aggregator tính toán một giá trị toàn cục
bằng cách áp dụng một hàm kết tập cho một tập
những giá trị mà người dùng cung cấp. Mỗi máy
thợ duy trì một tập các aggregator, định danh
bởi kiểu và tên. Khi một máy thợ thực thi một
superstep cho bất kỳ phần nào của đồ thị, nó sẽ
kết hợp tất cả các giá trị được cung cấp cho biến
aggregator thành một giá trị cục bộ duy nhất:
một aggreagator tối giản trên tất cả các đỉnh của
máy thợ trong phần đó. Đến cuối superstep các
máy thợ hình thành một cây để tối giản các
aggregator đã được tối giản thành một giá trị
toàn cục và chuyển nó đến máy chủ chính. Sử
dụng tối giản cây cân bằng hơn là sử dụng
đường ống với một chuỗi các máy thợ để sử
dụng CPU song song trong khi giảm tải. Máy chủ
chính gửi các giá trị toàn cục tới tất cả các máy
thợ tại đầu superstep tiếp theo.
5. Các ứng dụng
5.1 Phân hạng trang
Cách áp dụng Pregel với thuật toán PageRank
được chỉ ra ở hình
4. Lớp `PageRankVertext` được kế thừa từ `Vert
ex`. Các đỉnh của chúng có giá trị thuộc kiểu `dou
ble` để chứa các giá trị không chắc chắn để phân
hạng trang, và các thông điệp của chúng có kiểu
`double` mang giá trị là các phân số phân hạng tr
ang, trong khi đó giá trị các cạnh thuộc kiểu `voi
d` bởi vị các cạnh không lưu trữ bất cứ thông tin
nào. Chúng ta giả sử rằng đồ thị được khởi tạo đ
ể trong superstep thứ 0, giá trị của mỗi đỉnh là `1
/ NumVertices()` (1/ số lượng các
đỉnh). Trong từng superstep của 30 superstep
đầu tiên, mỗi đỉnh gửi tới mỗi cạnh đi ra từ chún
g giá trị phân hạng trang chia cho
số đỉnh đi ra từ nó.
class PageRankVertex
: public Vertex<double, void,
double> { public:
virtual void
Compute(MessageIterator* msgs) { if
(superstep() >= 1) {
double sum = 0;
12. for (; !msgs->Done(); msgs-
>Next()) sum += msgs-
>Value();
*MutableValue() =
0.15 / NumVertices() + 0.85 * sum;
}
if (superstep() < 30) {
const int64 n =
GetOutEdgeIterator().size();
SendMessageToAllNeighbors(GetValu
e() / n);
} else {
VoteToHal
t();
}
}
};
Figure 4: PageRank implemented in Pregel.
Bắt đầu từ superstep 1, mỗi đỉnh tính tổng các
giá trị trên các thông điệp lại thành `sum` và gán
giá trị không chắc chắn đó cho việc phân hạng
trang là `0.15 / NumVertices() + 0.85 * sum`. Sau
khi tới superstep 30, không có thêm thông điệp
nào được gửi đi và mỗi cạnh tự đề xuất ngắt,
Trong thực tế, một thuật toán phân hạng trang
sẽ chạy cho tới khi đạt đến điểm hội tụ và các
aggregators sẽ được sử dụng để xác định điều
kiện hội tụ.
5.2 Shortest Paths
Bài toán các tuyến đường ngắn nhất là một
trong những bài toán được biến đến nhiều nhất
trong lý thuyết đồ thị và xuất hiện trong nhiều
ứng dụng với nhiều biến thể. Bài toán tuyến
đường ngắn nhất với một đỉnh nguồn yêu cầu
tìm một đường ngắn nhất giữa một đỉnh nguồn
với các đỉnh khác trong đồ thị. Bài toán đường đi
s-t ngắn nhất yêu cầu tìm một đường đi đơn
ngắt nhất giữa hai đỉnh s và t cho trước, nó có
ứng dụng thực tế là chỉ đường và thu hút lượng
lớn sự quan tâm. Nó cũng là vấn đề có lời giải
tương đối đơn giản trong các đồ thị đặc trưng
như mạng lưới các tuyến đường với một phần
nhỏ của các đỉnh. Với việc khảo sát của
Lumsdaine et al lên tới 80000 đỉnh và trong 32
triệu đỉnh trong một ví dụ. Biến thể thứ ba, tất
cả các cặp đường ngắn nhất là không thực tế đối
với đồ thị lớn bởi vì nó yêu cầu độ phức tạp
O(|V|^2) về bộ nhớ.
Để đơn giản và rõ ràng, chúng ta tập trung vào
biến thể bài toán một nguồn vì nó phù hợp với
việc xử lý đồ thị lớn của Pregel, nhưng những dữ
liệu mở rộng khác thú vị hơn vấn đề đường đi
ngắn nhất s-t. Một cài đặt được thể hiện ở Hình
5.
Trong giải thuật này, chúng ta giả sử rằng giá
trị liên quan đến các đỉnh được thiệt lập ban đầu
là INF (một giá trị lớn hơn bất kỳ một khoảng
cách khả thi nào trong đồ thị từ đỉnh nguồn).
Trong một superstep, đầu tiền mỗi đỉnh sẽ nhận
thông điệp từ các đỉnh xung quanh, cập nhật lại
khoảng cách có thể là ngắn nhất từ đỉnh nguồn.
Nếu như khoảng cách ngắn nhất trong cập nhật
nhỏ hơn giá trị hiện tại của đỉnh, thì đỉnh sẽ cập
nhật lại giá trị của nó và gửi những cập nhật đến
các đỉnh lân cận, bao gồm trọng số của từng
cạnh đi ra cộng với khoảng cách ngắn nhất vừa
tìm được. Trong superstep đầu tiên, chỉ có đỉnh
nguồn sẽ cập nhật giá trị của nó (từ INF thành 0)
và gửi cập nhật tới các
đỉnh lân cận của nó.
13. class ShortestPathVertex
: public Vertex<int, int, int> {
void
Compute(MessageIterator*
msgs) {
int mindist = IsSource(vertex_id()) ? 0 :
INF; for (; !msgs->Done(); msgs-
>Next())
mindist = min(mindist, msgs-
>Value()); if (mindist < GetValue())
{
*MutableValue() = mindist;
OutEdgeIterator iter =
GetOutEdgeIterator(); for (;
!iter.Done(); iter.Next())
SendMessageTo(iter.Target(),
mindist + iter.GetValue());
}
VoteToHalt();
}
};
Figure 5: Single-source shortest paths.
class MinIntCombiner : public
Combiner<int> { virtual void
Combine(MessageIterator* msgs) {
int mindist = INF;
for (; !msgs->Done(); msgs-
>Next()) mindist = min(mindist,
msgs->Value());
Output("combined_source", mindist);
}
};
Figure 6: Combiner that takes minimum of
message values.
Những đỉnh lân cận lần lượt sẽ cập nhật lại giá
trị của chúng và gửi các thông điệp, kết quả là
một làn sóng của những cập nhật xuyên suốt đồ
thị. Thuật toán kết thúc khi không còn cập nhật,
sau đó giá trị của từng đỉnh biểu thị khoảng cách
nhỏ nhất từ đỉnh nguồn đến đỉnh đó. (Gía trị INF
thể hiện là đỉnh đó không thể đi tới được ). Việc
kết thúc sẽ chắc chắn xảy ra nếu tât cả chỉ số của
tất cả các cạnh đều không âm.
Các thông điệp trong thuật toán này bao gồm
các khoảng cách có thể là ngắn nhất. Vì đỉnh
nhận sẽ chỉ quan tâm đến cái nhỏ nhất, thuật
toán này có thể tối ưu bằng cách sử dụng bộ kết
hợp. Bộ kết hợp được thể hiện trong hình 6 làm
giảm lượng lớn dữ liệu truyền đi giữa 2 máy thợ,
cũng như là lượng dữ liệu trong buffer trước khi
xử lý trong superstep tiếp theo. Trong khi các
câu lệnh trong hình 5 chỉ tính toán các khoảng
cách, thay đổi nó để tính toán cây đường đi
ngắn nhất một cách đơn giản.
Thuật toán này có thể thực hiện nhiều phép so
sánh hơn các thuật toán như Dijkstra hay
Bellman-Ford, nhưng nó có khả năng xử lý vấn
đề đường đi ngắn nhất ở một quy mô mà không
thể thực thi với bất kỳ cài đặt trên một máy đơn
nào. Có những thuật toán song song cao cấp
hơn, ví dụ như Thorup hay thuật toán delta và
đã được sử dụng như cài đặt cơ bản cho các
mục đích chạy song song. Những thuật toán cao
cấp như thế có thể được cài đặt trong pregel
framework. Tuy nhiên, tính đơn giản trong cài
đặt ở hình 5 với hiệu năng ở mức có thể chấp
nhận phù hợp đối với những người mà không
thể làm các tinh chỉnh lớn hay tự cài đặt.
5.3 Ghép nối
Đầu vào của một thuật toán ghép nỗi bao gồm
2 bộ đỉnh độc lập cùng với các cạnh và đầu ra là
tập con của các cạnh mà không có điểm cuối
chung. Sự kết hợp tối đa là khi không thể có
thêm cạnh nào mà không có chung điểm ra.
14. Một thuật toán tối đa hóa ghép nối ngẫu nhiên
và tối đa hóa ghép nối theo chỉ số được cài đặt.
Chúng tôi sẽ miêu tả thuật toán tối đa hóa ghép
nối theo chỉ số.
Thuật toán này cài đặt với Pregel thì giá trị của
đỉnh là một tập hợp của 2 giá trị: một cờ chỉ định
tập mà định thuộc vào (Trái hoặc Phải) và tên
của đỉnh ghép nối với nó khi mà được tìm thấy.
Gía trị của cạnh có kiểu void (các cạnh không
chưa thông tin), và thông điệp là dạng boolean.
Thuật toán thực hiện các chu trình gồm 4 giai
đoạn, với chỉ mục của từng giai đoạn là chỉ mục
superstep mod 4, sử dụng bắt tay 3 bước.
Trong giai đoạn 0 của chu trình, mỗi đỉnh bên
trái chưa ghép nối gửi một thông điệp tới mỗi
đỉnh lân cận của nó, yêu cầu ghép nối và đề xuất
ngắt vô điều kiện. Nếu nó không gửi các thông
điệp (bởi vì nó đã được kết nối hoặc nó không có
cạnh đi ra) hoặc nếu tất cả các đỉnh nhận thông
điệp đều đã ghép nối, nó sẽ không được khởi
động lại. Ngược lại, nó sẽ nhận một thông điệp
phản hồi trong 2 superstep và khởi động lại.
Trong giai đoạn 1 của chu trình, mỗi đỉnh bên
phải chưa được ghép nối sẽ ngẫu nhiên chọn
một thông điệp mà nó nhận được, gửi một
thông điệp phản hổi cho phép ghép nối và gửi
tới các đỉnh còn lại thông điệp từ chối yêu cầu.
Cuối cùng đề xuất ngắt.
Trong giai đoạn 2 của chu trình, mỗi đỉnh bên
trái chưa được ghép nối chọn một trong các
thông điệp chấp nhận và gửi thông điệp chấp
nhận kết nối. Các đỉnh bên trái đã được ghép nối
sẽ không hoạt động trong giai đoạn này vì chúng
sẽ không gửi thông điệp ở giai đoạn 0.
Cuối cung, trong giai đoạn 3, mỗi đỉnh bên
phải chưa ghép nối nhận nhiều nhất 1 thông
điệp chấp nhận kết nối. Nó sẽ ghi lại đỉnh để
ghép nối và đề xuất ngắt.
5.4 Bán phân cụm
Pregel đã sử dụng một số phiên bản khác nhau
của phân cum. Một phiên bản, bán phân cụm,
phát sinh trong các đồ thị xã hội.
Các đỉnh trong một đồ thị xã hội thường tượng
trưng cho con người và các cạnh tượng trưng
cho các mối quan hệ giữa họ. Các cạnh có thể
dựa trên những hành động rõ ràng hoặc có thể
dựa trên cách ứng xử của con người. Các cạnh
có thể có các chỉ sô để biểu diễn độ thường
xuyên và gắn bó của mối quan hệ.
Một bán phân cum là một đồ thị xã hội thuộc
một nhóm người mà thường xuyên tương tác
với nhau và ít tương tác với những người khác.
Điều làm nó khác biệt so với các loại phân cụm
khác là một đỉnh có thể thuộc vào nhiều hơn
một bán cụm.
Phần này sẽ miêu tả lại một thuật toán bán
phân cụm tham lam song song. Đầu vào là một
chỉ số, một đồ thị vô hướng và đầu ra là nhiều
nhất Cmax bán phân cụm, mỗi cái chưa nhiều
nhất Vmax đỉnh, trong đó Cmax và Vmax là các tham
số đầu vào do người dùng nhập.
Một bán phân cụm c được phân một điểm số ,
trong đó Ic là tổng điểm số của tất cả các cạnh
bên trong, Bc là tổng các điểm số của tất cả các
cạnh biên, Vc là số đỉnh trong một bán phân cụm
và fB là hệ số cạnh biên, là một tham số đầu vào
của người dùng, thường nằm giữa 0 và 1. Chỉ số
được chuẩn hóa tức là chia cho số cạnh trong
một nhóm có kích thước Vc để các cụm lớn
không nhận
các điểm số lớn một cách bất thường.
15. Mỗi đỉnh V giữ một danh sách chứa nhiều nhất
Cmax các bán phân cụm, được sắp xếp theo điểm
số. Trong superstep 0 V đưa mình vào danh sách
đó như một bán phân cụm có kích thước 1 và
điểm số 1, và thông báo cho các đỉnh lân cận.
Trong chuỗi con các superstep:
Đỉnh V lặp đi lặp lại trên bán cụm c1,...,ck gửi
tới nó trong các superstep trước. Nếu một
bán phân cụm c chưa chứa V , và Vc < Mmax
thì V sẽ được thêm vào c để hình thành c0
.
Các bán phân cụm c1 ,…, ck; c0
1,…, c0
k được
sắp xếp theo điểm số và cái có chỉ số lớn
nhật được gửi đến các đỉnh lân cận của V.
Đỉnh V cập nhật danh sách của mình về các
bán phân cụm với những bán phân cụm từ
c1,…, ck, c0
1,…, c0
k mà có chứa V.
Thuật toán ngắt khi các bán phân cụm ngừng
thay đổi hoặc khi số lượng superstep đạt đến
ngưỡng mà người dùng chỉ định. Tại thời điểm
đó danh sách các bán phân cụm tốt nhất cho
từng đỉnh có thể được At that point the list of
best semi-cluster candidates for each vertex may
be tổng hợp thành một danh sách toàn cục các
bán phân cụm tốt nhất.
6. Thí nghiệm
Nhiều thí nghiệm được thực hiện trên cùng
một cài đặt của thuật toán đường đi ngắn nhất
từ 1 điểm nguồn trên một nhóm 300 PC nhiều
nhân thông dụng. Theo thống kê thời gian chạy
của cây nhị phân và đồ thị lognormal ngẫu nhiên
sử dụng nhiều kích thước đồ thị với trọng số của
tất cả các cạnh ngầm định là 1.
Thời gian để khởi tạo cụm, sinh đồ thị để kiểm
tra trong bộ nhớ, và kiểm tra kết quả không
được tính vào trong các đánh giá. Vì tất cả các
thí nghiệm có thể chạy trong một thời gian
tương đối ngắn, khả năng gặp lỗi khá thấp và các
điểm mốc bị vô hiệu hóa.
Như một số chỉ các Pregel đánh giá hiệu năng
máy thợ, Hình 7 cho thấy thời gian chạy thuật
toán đường đi ngắn nhất với cây nhị phân 1 triệu
đỉnh khi số lượng máy thợ Pregel có gía trị từ 50
đến 800. Số máy thợ tăng lên 16 lần thì tốc độ
tăng lên 10 lần, thời gian từ 174 giây giảm xuống
con 17,3 giây.
Để cho thấy khả năng mở rộng của Pregel với
kích thước đồ thị, hình số 8 thể hiện thời gian
chạy thuật toán đường đi ngắn nhất cho cây nhị
phân có kích thước đa dạng từ 1 tỉ đến 50 tỉ
đỉnh, bây giờ sử dụng một số xác định
Figure 7: SSSP - 1 billion vertex binary tree: vary-
ing number of worker tasks scheduled on 300
multi-core machines
Figure 8: SSSP|binary trees: varying graph sizes
on 800 worker tasks scheduled on 300 multicore
ma-chines
là 800 máy thợ lập lịch trên 300 máy nhiều nhân.
Ở đây thời gian tăng từ 17,3 đến 702 giây cho
thấy với những đồ thị với các cạnh đi ra thấp
thời gian chạy tăng tuyến tính theo kích thước
đồ thị.
Mặc dù thí nghiệm trước cho thấy chỉ số của
Pregel để đánh giá các máy thợ và kích thước đồ
17. Đây cũng là một thuật toán nân cao giúp nâng
cao hiệu năng. Vì vậy, kết quả của thí nghiệm
trong phần này không phải là hiệu năng lớn nhất
của thuật toán đường đi ngắn nhất viết bằng
Pregel. Thay vào đó, các kết quả không được sử
dụng để cho thấy sự thỏa đáng của hiệu năng có
thể có được mà không tôn công sức code. Trên
thực tế, kết quả với 1 tỷ đỉnh và cạnh so với kết
quả thuật toán đường deltaIn có được từ
Parallel BGL là đáng chú ý đối với một nhóm 112
bộ vi xử lý trên một đồ thị 256 triệu đỉnh và 1 tỉ
cạnh và quy mô của Pregel lớn hơn kích thước
đó.
7. Những công trình liên quan
Pregel là một framework cho lập trình phân
tán, Tập trung vào việc cung cấp cho người dùng
một API tự nhiên để lập trình thuật toán đồ thị
khi quản lý chi tiết sự rõ ràng của hệ phân tán,
bao gồm gửi thông điệp và chống chịu lỗi. Nó
tương tự MapReduce về tư tưởng, nhưng với
một API đồ thị tự nhiên và nhiều hỗ trợ hiệu quả
cho tính lặp của tính toán trên đồ thị. Đồ thị
cũng tập trung vào việc tạo sự khác biệt giữa nó
và những framework khác mà giấu chi tiết về
phân tán như Sawzall, Pig Latin và Dryad. Pregel
cũng khác biệt vì nó tập trung cài đặt mô hình
trạng thái mà những tiến trình được tính toán,
truyền tải và thay đổi trạng thái cục bộ dài hạn
hơn là một mô hình dòng data mà bất kỳ tiến
trình nào cũng chỉ tính toán chỉ trên data đầu
vào và tạo ra data đầu ra bởi những tiến trình
khác.
Pregel được lấy cảm hứng từ mô hình Bulk
Synchronous Parallel, mô hình mà cung cấp mô
hình đồng bộ superstep, tính toán và truyền
thông của nó. Đã có nhiều thư viện BSP phổ
thông được được cài đặt, ví dụ như thư viện BSP
Oxford Oxford BSP Library, Green BSP, BSPlib và
thư viện BSP của trường đại học Paderborn.
Chúng đa dạng về tập giao tiếp ban đầu được
cung cấp và cách chúng xử lý các vấn đề về phân
tán như độ tin cậy, cân bằng tải và đồng bộ hóa.
Khả năng mở rộng và chịu lỗi của các cài đặt BSP
chưa được đánh giá ở mức cao hơn vài chục
máy và không máy nào cung một API đồ thị nhất
định.
Thư viện gần nhất vơi Pregel là Parallel Boost
Graph Library và CGMgraph. Parallel BGL chỉ rõ
một số khái niệm mấu chốt chung về định nghĩa
đồ thị phân tán, cung cấp cài đặt dựa trên MPI,
và cài đặt một số thuật toán dựa trên chúng. Nó
có giữ sự đồng bộ với BGL để tạo điều kiện cho
thuật toán dùng cổng. Nó thêm bảng các thuộc
tính để giữ liên kết dữ liệu với các đỉnh và các
cạnh trong đồ thị, sử dụng các ghost cell để giữ
giá trị liên quan đến các phần tử ở xa. Điều này
có thể dẫn đến các vấn đề về quy mô nếu cần
gọi đến quá nhiều phần tử ở xa. Pregel sử dụng
thông điệp ngầm để lấy thông tiên từ xa và
không sao chép lại giá trị đó vào cục bộ. Điểm
khác biệt lớn nhất là Pregel có khả năng chịu lỗi
phòng trừ lỗi xảy ra trong khi tính toán, cho
phép nó trong một nhóm môi trường lớn mà
thường xuyên gặp lỗi, dù là lỗi phần cứng hay ưu
tiên một công việc nào đó.
CGMgraph có tư tưởng tương tụ, cung cấp
một số thuật toán đồ thị song song sử dụng mô
hình dựa trên MPI Coarse Grained Mul-
ticomputer (CGM). Nó nằm bên dưới cơ chế
phân tán, và tập trùng vào cung cấp các cài đặt
của các thuật toán hơn là cơ sở hạ tầng cần để
sử dụng chúng.
18. Ngược lại phong cách lập trình tổng quát của
Parallel BGL và Pregel, CGMgraph sử dụng phong
cách lập trình theo hướng đối tương cho một số
chi phí về hiệu năng.
Ngoài Pregel và Parallel, đã có một số hệ thống
có các thí nghiệm với các đồ thị ở mức 1 tỉ đỉnh.
Đồ thị lớn nhất được sử dụng là từ thống kê của
một cài đặt tự viết của thuật toán đường đi ngắn
nhất s-t chử không phải một framework phổ
thông. Yoo et al thống kê trên một cài đặt tìm
kiếm theo chiều rộng BlueGene/L trên 32,768 bộ
vi xử lý PowerPC với mạng torus hiệu năng cao,
cho thấy hiệu năng đạt tới 1,5 giây mỗi đồ thị
phân tán ngẫu nhien Poisson với 3,2 tỉ đỉnh và 32
tỉ cạnh. Bader và Madduri báo cáo về một cài đặt
Cray MTA-2 của một vấn đề tương tự trên một
hệ thống 10 nút, đa luồng tốc độ cao, kết quả
đạt được 0,43 giay cho một R-MAT đồ thị ngẫu
nhiên kích thước bất kỳ với 134 triệu đỉnh và 805
triệu cạnh. Lumsdaine et al so sánh kết cuarcuar
Parallel BGL trên một cụm Opteron x86-64 của
200 bộ vi xử lý với cài đặt BlueGene/L, kết quả
đạt được 0,43 giây cho một đồ thị ngẫu nhiên
Erdo˝s-Renyi với 4 tỉ đỉnh và 20 tỉ cạnh. Chúng
cps hiệu năng tốt hơn ghost cells và theo thực
nghiệm thì hiệu năng bắt đầu giảm nếu có từ 32
bộ vi xử lý trở lên.
Những kết quả cho bài toán đường đi ngắn
nhất từ một nguồn trên một đồ thị ngẫu nhiên
với 256 triệu đỉnh và số cạnh đi ra không đồng
bộ 4, sử dụng thuật tón delta, được thống kề cho
Cray MTA-2 và cho Parallel BGL trên Opterons.
Cái thứ 2 tương tự với kết quả của 400 máy thợ
của Pregel cho một cây nhị phân với 1 tỉ nút và
cạnh. Chưa có thống kê về kết quả cho SSSP trên
kích thước 1 tỉ đỉnh và 127,1 tỉ cạnh đồ thị log-
normal.
8. Kết luận và cải tiến trong tương
lai.
Đóng góp của bài báo này là một mô hình phù
hợp với cách tính toán trong đồ thị lớn và một
miêu tả cách cài đặt về chất lượng sản phẩm,
khả năng mở rộng, khả năng chịu lỗi.
Dựa vào các đầu vào của người dùng, chúng
tôi nghĩ chúng tôi đã thành công trong việc tạo
ra một mô hình hữu ích và có thể sử dụng được.
Rất nhiều các ứng dụng Pregel đã được triển
khai và sẽ có nhiều ứng dụng hơn nữa đang
được thiết kế, cài đặt và tinh chỉnh. Người dùng
phản hồi cho chúng tôi rằng một khi họ chuyển
qua chế độ lập trình “nghĩ mình như một đỉnh”,
API sẽ trực quan, linh hoạt và đơn giản hơn khi
sử dụng. Điều này không ngạc nhiên bởi vì chúng
tôi đã làm việc với “các người chấp nhận” –
người mà ảnh hưởng đến API từ những bước
đầu. Ví dụ, các aggregators đã được thêm vào
để xóa đi các giới hạn người dùng tìm được
trong các mô hình Pregel trước. Các khía cạnh sử
dụng của Pregel đã được thúc đẩy bởi kinh
nghiệm người dùng bao gồm một tập các trang
trạng thái với thông tin chi tiết về quá trình của
chương trình Pregel, một unittesting framework,
một chế độ máy đơn – cái mà đã giúp tăng tốc
tạo mẫu và sửa lỗi.
Hiệu năng, tính khả mở và khả năng chịu lỗi
của Pregel đạt yêu cầu đối với các đồ thị với
hàng tỉ đỉnh. Chúng tôi đang nghiên cứu kỹ thuật
để mở rộng các đồ thị lớn hơn, như là giảm bớt
tính đồng bộ của mô hình để tránh chi phí các
máy thợ nhanh phải đợi thường xuyên tại điểm
biên liên superstep.
Hiện tại toàn bộ trạng thái tính toán đang
được lưu trữ trên RAM. Chúng tôi đã thiết kế để
dữ liệu có thể lưu trong ổ đĩa và chúng tối sẽ
tiếp tục theo hướng này để có thể tính toán trên
các đồ thị lớn khi dữ liệu lên đến hàng terabytes
và bộ nhớ chính sẽ không thể chứa nổi.