- Kết thúc chu kỳ kéo, cho dù việc kéo thành cơng hay khơng thành cơng thì 1 ln trở về trạng thái PUSH.
- Ta có sơ ñồ chuyển ñổi trạng thái của các nút:
CHƯƠNG 3 – GIẢI PHÁP CẢI TIẾN GIAO THỨC KÉO ðẨY XEN KẼ
3.1. Ý tưởng chung
Như chúng ta ñều biết, trong giao thức kéo ñẩy xen kẽ, tại mỗi chu kỳ đẩy, các máy tính ln lựa chọn đẩy tới một hàng xóm ngẫu nhiên mảnh dữ liệu có số tuần tự lớn nhất mà nó nhận được. ðiều này là hợp lý trong phạm vi phân phối dữ liệu nhưng ñối với việc áp dụng trong truyền thơng đa phương tiện thì vẫn cịn nhiều hạn chế. ðiều hạn chế ñầu tiên là do các hàng xóm được lựa chọn ngẫu nhiên khơng theo một phương pháp chung nào nên ñể tất cả các máy tính trong mạng đều nhận được dữ liệu một cách ñầy ñủ sẽ mất rất nhiều thời gian. Mặt khác, các mảnh dữ liệu ñược lựa chọn chuyển tiếp ln là những mảnh dữ liệu có số tuần tự lớn nhất dẫn tới việc phát sinh các lỗ hổng gói tin. ðối với các ứng dụng truyền thơng đa phương tiện thời gian thực yêu cầu ñộ trễ rất khắt khe thì việc phát sinh nhiều lỗ hổng gói tin sẽ dẫn tới độ trễ truyền thơng tăng, chất lượng dịch vụ khơng đảm bảo.
Chính vì vậy, trong phạm vi luận văn này, hướng nghiên cứu chính của chúng tơi là làm cách nào khắc phục tốt nhất các hạn chế kể trên của giao thức kéo ñẩy xen kẽ nhằm có thể áp dụng được giao thức kéo ñẩy xen kẽ, vốn ñược áp dụng ñầu tiên trong lĩnh vực phân phối dữ liệu ngang hàng, trong các ứng dụng truyền thơng đa phương tiện thời gian thực.
ðể khắc phục ñược những hạn chế của giao thức, chúng tơi đã cài ñặt bổ sung tại mỗi máy tính trong mạng sử dụng giao thức một thuộc tính mới lưu vết trao đổi dữ liệu giữa máy tính đó với các máy hàng xóm của nó. Chúng tơi tạm gọi thuộc tính này là Push_maxID với ý nghĩa là một giá trị lưu trữ số tuần tự lớn nhất của gói tin đã được trao đổi giữa máy tính hiện tại và các máy hàng xóm của nó (trong cả hai chu kỳ kéo và đẩy). Thuộc tính này được tích lũy theo q trình truyền nhận dữ liệu của máy tính và là cơ sở cho máy tính khi đưa ra quyết định lựa chọn gói dữ liệu cũng như hàng xóm để kéo dữ liệu về hay ñẩy dữ liệu tới.
Q trình đưa ra quyết ñịnh là một ñiểm quan trọng trong cài ñặt thuật tốn. Quyết định kéo đẩy dữ liệu hồn tồn bị phụ thuộc vào việc lựa chọn hàng xóm trước hay lựa chọn gói tin để chuyển tiếp trước. Chính vì vậy, chúng tơi đã hiện thực hóa đề xuất cải tiến của mình trong hai thuật toán, phụ thuộc vào quyết định lựa chọn hàng xóm trước hay lựa chọn gói tin trước. Trong đó: Thuật tốn 1 được xây dựng trên cơ sở lựa chọn gói tin kéo đẩy trước sau đó mới lựa chọn hàng xóm dựa trên gói tin được chọn và thuộc tính Push_maxID. Cịn thuật tốn 2 được xây dựng trên việc lựa chọn
hàng xóm trước; sau ñó mới lựa chọn gói tin dựa trên hàng xóm đã ñược chọn và thuộc tính Push_maxID. Chi tiết cài đặt các thuật tốn sẽ được trình bày ở dưới:
3.2. Thuật tốn cải tiến thứ nhất
Hình 19. Hoạt động của thuật toán 1 trong chu kỳ đẩy
Input: /**push_maxID: Mảng chứa giá trị chunkID lớn nhất của hàng xóm thứ i mà node hiện tại biết
được dựa trên các hoạt động kéo đẩy giữa node hiện tại với node hàng xóm đó
max_push_attempts: Số lần đẩy tối đa được phép max_pull_attempts: Số lần kéo tối đa được phép */
if (status == PULL) then
while (pull_attempt < max_pull_attempts) AND (download_bandwidth_available) do /**Chọn mảnh dữ liệu ci cịn thiếu có giá trị chunkID nhỏ nhất*/
/**Chọn hàng xóm có khả năng chứa chunkID ci tìm thấy ở trên. Trường hợp không thấy sẽ trả về hàng xóm ngẫu nhiên để tận dụng chu kỳ */
Node selectedNode = null; foreach (Node nei in contact_list)
if (push_maxID[nei.GetID()]>ci.GetID()) {
selectedNode = nei;
break; /* exit from the foreach cycle */ }
if (selectedNode == null)
selectedNode = getRNDNeighbor()
Send PULL message; Wait for reply;
if (reply == ACCEPT PULL) then
if (download_bandwidth_available) then {
Send READY message; startPullingPiece;
//Ghi nhận đã chuyển ci tới cho hàng xóm selectedNode if (push_maxID[selectedNode.GetID()]<ci.GetID()) {
push_maxID[selectedNode.GetID()] = ci.GetID(); }
break; /* exit from the while cycle */ }
else
Send BUSY message; end end pull_attempt++; end status = PUSH; pull_attempt = 0; end
if (status == PUSH) then
while (push_attempt < max_push_attempts) AND (upload_bandwidth_available) do
/**Chọn mảnh dữ liệu ci có giá trị chunkID lớn nhất trong danh sách các chunk đang sở hữu*/
/**Chọn hàng xóm có khả năng chưa sở hữu chunkID ci tìm thấy ở trên. Trường hợp khơng thấy sẽ trả về hàng xóm ngẫu nhiên để tận dụng chu kỳ */
Node selectedNode = null; foreach (Node nei in contact_list)
if (push_maxID[nei.GetID()]<ci.GetID()) {
selectedNode = nei;
break; /* exit from the foreach cycle */ }
if (selectedNode == null)
selectedNode = getRNDNeighbor()
Send PUSH message; Wait for reply;
if (reply == ACCEPT PUSH) then
if (upload_bandwidth_available) then {
Send READY message; startPushingPiece;
//Ghi nhận đã chuyển ci tới cho hàng xóm selectedNode if (push_maxID[selectedNode.GetID()]<ci.GetID()) {
push_maxID[selectedNode.GetID()] = ci.GetID(); }
break; /* exit from the while cycle */ }else
Send BUSY message; end end push_attempt++; end status = PULL; push_attempt = 0; end
Nếu như trong giao thức kéo đẩy xen kẽ, máy tính trong một chu kỳ kéo hoặc đẩy của mình đưa ra quyết định chỉ dựa trên danh sách các mảnh dữ liệu hiện đang sở hữu tại máy tính đó, sau đó nó lựa chọn một hàng xóm để kéo hoặc đẩy dữ liệu một cách ngẫu nhiên; thì trong các thuật tốn sửa đổi chúng tơi đề xuất tại mỗi máy tính sẽ
bổ sung lưu trữ một mảng chứa số tuần tự lớn nhất của các mảnh dữ liệu mà máy tính hàng xóm sở hữu đối với máy tính hiện tại. Sở dĩ chúng tơi dùng từ “đối với máy tính hiện tại” bởi lẽ số liệu của mảng dữ liệu này ñược xây dựng chỉ dựa trên việc thống kê sau các hoạt ñộng kéo hoặc ñẩy giữa máy tính hiện tại và máy tính hàng xóm. Do đó số tuần tự mảnh dữ liệu lớn nhất máy tính P lưu trữ cho máy tính N chưa chắc đã là số tuần tự mảnh dữ liệu lớn nhất mà máy tính N đang thực sự sở hữu.
Cùng với việc bổ sung mảng push_maxID đó, chúng tơi cũng đồng thời cải tiến cách thức ñưa ra quyết ñịnh của máy tính trong mạng.
Cụ thể, trong thuật tốn 1, trong chu kỳ kéo, máy tính vẫn giữ nguyên việc lựa chọn mảnh dữ liệu cịn thiếu có số tuần tự nhỏ nhất. Nhưng khi lựa chọn hàng xóm, thay vì chọn một cách ngẫu nhiên như thuật tốn kéo đẩy xen kẽ gốc đề xuất, nó sẽ kiểm tra một vịng mảng push_maxID đang lưu trữ tại chính nó để tìm ra hàng xóm có khả năng chứa mảnh dữ liệu nó đang cần tìm kiếm là lớn nhất.
/**Chọn mảnh dữ liệu ci cịn thiếu có giá trị chunkID nhỏ nhất*/
/**Chọn hàng xóm có khả năng chứa chunkID ci tìm thấy ở trên. Trường hợp khơng thấy sẽ trả về hàng xóm ngẫu nhiên để tận dụng chu kỳ */
Node selectedNode = null; foreach (Node nei in contact_list)
if (push_maxID[nei.GetID()]>ci.GetID()) {
selectedNode = nei;
break; /* exit from the foreach cycle */ }
if (selectedNode == null)
selectedNode = getRNDNeighbor()
Tương tự, trong chu kỳ đẩy, máy tính cũng dựa trên mảng push_maxID đang lưu trữ tại chính nó để tìm ra hàng xóm có khả năng chưa có mảnh dữ liệu nó đang muốn đẩy đi là lớn nhất thay vì lựa chọn hàng xóm một cách ngẫu nhiên như giải thuật của giao thức kéo ñẩy xen kẽ nguyên bản:
/**Chọn mảnh dữ liệu ci có giá trị chunkID lớn nhất trong danh sách các chunk đang sở
hữu*/
/**Chọn hàng xóm có khả năng chưa sở hữu chunkID ci tìm thấy ở trên trường hợp để đẩy chunk ci sang. Trường hợp không thấy sẽ trả về hàng xóm ngẫu nhiên để tận dụng chu kỳ */
Node selectedNode = null; foreach (Node nei in contact_list)
if (push_maxID[nei.GetID()]<ci.GetID()) {
selectedNode = nei;
break; /* exit from the foreach cycle */ }
if (selectedNode == null)
selectedNode = getRNDNeighbor()
3.3. Minh họa cho các cải tiến thứ nhất
ðể minh họa cho các cải tiến trong thuật toán thứ nhất, chúng ta sẽ xem xét lại chính mạng ngang hàng bất đối xứng trong ví dụ minh họa giao thức kéo ñẩy xen kẽ đã mơ tả ở chương 2.
Hình 20. Minh họa cải tiến giao thức kéo đẩy xen kẽ
Khi đó chúng ta cũng xem xét một thời ñiểm t bất kỳ với trạng thái sở hữu dữ liệu tại các node giống hệt với minh họa giao thức kéo ñẩy xen kẽ trong chương 2 Máy tính Danh sách hàng xóm Dữ liệu sở hữu Push_maxID Dữ liệu sẽ ñẩy Các hàng xóm sẽ đẩy Dữ liệu sẽ kéo Các hàng xóm sẽ kéo S 1; 2; 3 1|2|3|4 3; 2; 1 4 1 - - 1 3; 4; 6 1|3 3; 3; 1 3 6 2 3
2 1; 4; 5 1|2 1; 0; 2 2 1 3 1 3 1; 6; 7 1|2 2; 1; 1 2 6 3 1 4 2; 5; 7 2 2; 2; 1 2 7 1 2 5 2; 4; 7 1|2 2; 2; 0 2 7 3 2 6 1; 3; 7 1 1; 1; 1 1 - 2 1 7 3; 5; 6 1 1; 1; 1 1 - 2 3
Hình 21. Trạng thái sở hữu dữ liệu của các máy tính tại thời điểm t
Chúng ta có thể nhận thấy ngay sự khác biệt trong lưu trữ trạng thái sở hữu của thuật toán cải tiến so với thuật tốn kéo đẩy xen kẽ gốc. Tại thời điểm t, mỗi máy tính sẽ lưu trữ thêm thơng tin về số định danh lớn nhất trong số các mảnh dữ liệu ñã giao tiếp (qua phương thức kéo hoặc ñẩy) với các máy tính hàng xóm trong mảng Push_maxID. Trong đó giá trị 0 sẽ thể hiện máy tính hiện tại chưa hề giao tiếp với máy tính hàng xóm tương ứng.
Như vậy, nhìn giá trị dữ liệu của mảng Push-maxID ta sẽ biết được tính tới chu kỳ hiện tại, các máy tính đã giao tiếp với nhau như thế nào. Chẳng hạn mảng Push_maxID ở nguồn S cho thấy mảnh dữ liệu lớn nhất mà S ñã đẩy cho máy tính số 1 là 3; máy tính số 2 là 2 và máy tính số 3 là 1. Khi ñó với danh sách chunk S ñang sở hữu là {1|2|3|4} thì nó sẽ đẩy tiếp mảnh dữ liệu số 4 cho bất kỳ một máy tính hàng xóm nào đều cũng thành cơng (thành cơng ở đây được hiểu là mảnh dữ liệu đó hiện đang chưa có tại các máy tính đích) do số thứ tự 4 ln lớn hơn các dữ liệu tương ứng trong mảng Push_maxID tại S. Giả sử S chọn 1 ñể ñẩy mảnh dữ liệu thứ 4 đi. Khi đó mảng Push_maxID tại S sẽ thay ñổi thành {4; 2; 1}.
Tương tự, tại máy tính số 1, với giá trị của mảng Push_maxID là {3; 3; 1} và mảnh dữ liệu ñang cần ñẩy là 3; sự lựa chọn cho lần ñẩy kế tiếp của 1 luôn là hàng xóm thứ 3 (tương ứng với máy tính số 6). Với yêu cầu mảnh dữ liệu còn thiếu là 2 thì máy số 1 sẽ có thể hy vọng kéo được mảnh dữ liệu đó từ các hàng xóm số 1 và 2 của nó do giá trị 2 hiện đang nhỏ hơn giá trị Push_maxID mà nó lưu trữ về hai hàng xóm số 1 và số 2.
Cứ như vậy, trong một chu kỳ các máy tính sẽ tính tốn và đưa ra quyết ñịnh chọn mảnh dữ liệu và hàng xóm để kéo ñẩy tương ứng không chỉ dựa trên trạng thái sở hữu mảnh tin của bản thân máy tính hiện tại mà cịn dựa trên các thơng tin nó thu thập về các máy tính hàng xóm từ các chu kỳ trước đó để thay vì lựa chọn một hàng xóm ngẫu nhiên, nó sẽ lựa chọn có chọn lọc hàng xóm với xác suất thành cơng cao hơn.
Máy tính
Danh sách hàng
xóm Dữ liệu sở hữu Push_maxID Dữ liệu sẽ ñẩy Trạng thái ñẩy S 1; 2; 3 1|2|3|4 3; 2; 1 4 Success 1 3; 4; 6 1|2|3|4 3; 3; 1 4 Success 2 1; 4; 5 1|2 1; 0; 2 2 Success 3 1; 6; 7 1|2 2; 1; 1 2 Success 4 2; 5; 7 2 2; 2; 1 2 Success 5 2; 4; 7 1|2 2; 2; 0 2 Success 6 1; 3; 7 1|2|3 1; 1; 1 3 - 7 3; 5; 6 1|2 1; 1; 1 2 -
Hình 22. Trạng thái sở hữu dữ liệu và kết quả thao tác PUSH tại thời điểm t+1 của thuật tốn 1
Máy tính
Danh sách hàng xom
Dữ liệu sở hữu Push_maxID Dữ liệu ñể kéo Trạng thái kéo
S 1; 2; 3 1|2|3|4 3; 2; 1 - - 1 3; 4; 6 1|2|3 3; 3; 1 4 Success 2 1; 4; 5 1|2|3 1; 0; 2 4 Success 3 1; 6; 7 1|2|3 2; 1; 1 4 Success 4 2; 5; 7 1|2 2; 2; 1 3 Success 5 2; 4; 7 1|3|2 2; 2; 0 4 Failed 6 1; 3; 7 1|2 1; 1; 1 3 Success 7 3; 5; 6 1|2 1; 1; 1 3 Success
Hình 23. Trạng thái sở hữu dữ liệu và kết quả thao tác PULL tại thời điểm t+1 của thuật toán 1
3.4. Thuật toán cải tiến thứ hai
Hình 25. Hoạt động của thuật toán 2 trong chu kỳ đẩy
Input: /**push_maxID: Mảng chứa giá trị chunkID lớn nhất của hàng xóm thứ i mà node hiện tại biết
được dựa trên các hoạt động kéo đẩy giữa node hiện tại với node hàng xóm đó
max_push_attempts: Số lần đẩy tối đa được phép max_pull_attempts: Số lần kéo tối đa được phép */
if (status == PULL) then
while (pull_attempt < max_pull_attempts) AND (download_bandwidth_available) do /**Chọn mảnh dữ liệu ci còn thiếu có giá trị chunkID nhỏ nhất*/
/**Chọn hàng xóm có khả năng chứa chunkID ci tìm thấy ở trên. Trường hợp khơng thấy sẽ trả về hàng xóm ngẫu nhiên để tận dụng chu kỳ */
Node selectedNode = null; foreach (Node nei in contact_list)
if (push_maxID[nei.GetID()]>ci.GetID()) {
selectedNode = nei;
break; /* exit from the foreach cycle */ }
if (selectedNode == null)
selectedNode = getRNDNeighbor(); Send PULL message;
Wait for reply;
if (reply == ACCEPT PULL) then if (download_bandwidth_available) then {
Send READY message; startPullingPiece;
//Ghi nhận đã chuyển ci tới cho hàng xóm selectedNode if (push_maxID[selectedNode.GetID()]<ci.GetID()) {
push_maxID[selectedNode.GetID()] = ci.GetID(); }
break; /* exit from the while cycle */ }
else
Send BUSY message; end end pull_attempt++; end status = PUSH; pull_attempt = 0; end
if (status == PUSH) then
while (push_attempt < max_push_attempts) AND (upload_bandwidth_available) do /**Chọn hàng xóm ngẫu nhiên */
Node selectedNode = getRNDNeighbor();
/**Chọn mảnh dữ liệu ci có giá trị chunkID nhỏ nhất mà node hàng xóm selectedNode chưa sở hữu trong số các chunk mà node có. Trường hợp selectedNode đã có tất cả các chunk mà node hiện tại có thì sẽ bỏ trống chu kỳ */
Chunk selectedChunk = null;
foreach (Chunk ci in ChunkListOwned)
if (push_maxID[selectedNode.GetID()]<ci.GetID()) {
selectedChunk = ci;
break; /* exit from the foreach cycle */ }
if (selectedChunk != null) {
Send PUSH message; Wait for reply;
if (reply == ACCEPT PUSH) then
if (upload_bandwidth_available) then {
Send READY message; startPushingPiece;
//Ghi nhận đã chuyển ci tới cho hàng xóm selectedNode if (push_maxID[selectedNode.GetID()]<ci.GetID()) {
push_maxID[selectedNode.GetID()] = ci.GetID(); }
break; /* exit from the while cycle */ }else
Send BUSY message; end end push_attempt++; } end status = PULL; push_attempt = 0; end
Thuật tốn 2 có cài đặt một số sửa ñổi nhỏ của thuật toán 1 ñược ñề xuất ở trên. Thay vì lựa chọn các máy tính hàng xóm sau khi ñã lựa chọn mảnh dữ liệu ñể kéo về hoặc đẩy đi; máy tính sẽ lựa chọn ngẫu nhiên một hàng xóm trước, sau đó trên cơ sở hàng xóm được chọn đó sẽ chọn trong số các mảnh dữ liệu nó sở hữu, một mảnh dữ liệu có số tuần tự nhỏ nhất mà hàng xóm đó có thể chưa có để đẩy đi. Lý do chính của việc cài ñặt này là nhằm giúp giảm ñộ trễ truyền thơng so với thuật tốn kéo đẩy xen kẽ nguyên bản và thuật toán 1. Khi mà cả hai thuật tốn kéo đẩy xen kẽ ngun bản và thuật tốn 1 ln lựa chọn các mảnh dữ liệu có số tuần tự lớn nhất trong các mảnh dữ liệu nó đang có.
/**Chọn hàng xóm ngẫu nhiên */
Node selectedNode = getRNDNeighbor();
/**Chọn mảnh dữ liệu ci có giá trị chunkID nhỏ nhất mà node hàng xóm selectedNode chưa