Uma Proposta de Difusão Confiável Hierárquica em Sistemas Distribuídos Assíncronos
4. O Algoritmo de Difusão Confiável Proposto
Seja i um processo que executa o algoritmo de difusão confiável e d = log2na dimensão
do d-VCube com 2dprocessos. O Algoritmo 1 apresenta o pseudo-código da solução de
difusão confiável proposta.
A função clusteri(j) = s calcula o identificador s do cluster do processo
i que contém o processo j, 1 ≤ s ≤ d. Por exemplo, considerando o 3-VCube da Figura 1, cluster0(1) = 1, cluster0(2) = cluster0(3) = 2 e cluster0(4) =
cluster0(5) = cluster0(6) = cluster0(7) = 3. Três tipos de mensagens são utiliza-
dos: hT REE, mi para identificar a mensagem de aplicação m que está sendo propagada na árvore; hDELV, mi para as mensagens enviadas aos processos considerados falhos,
(a) Sem falhas (b) p4é suspeito
Figura 2. Difusão confiável no processo 0 (p0)
evitando que falsas suspeitas impliquem em não recebimento por processos corretos; e hACK, mi para confirmar o recebimento de m pelo destinatário que recebe TREE. Cada mensagem m contém ainda dois parâmetros: (1) o identificador da origem, isto é, o pro- cesso que iniciou a difusão, obtido com a função source(m); e (2) o timestamp, um contador sequencial local que identifica de forma única cada mensagem gerada em um processo, obtido pela função ts(m). Um processo obtém as informações sobre o estado dos demais processos pelo algoritmo VCube.
As variáveis locais mantidas pelos processos são:
• correcti: conjunto dos processos considerados corretos pelo processo i;
• lasti[n]: a última mensagem recebida de cada processo fonte;
• ack_seti: o conjunto de ACKs pendentes no processo i. Para cada mensagem
hT REE, mi (re)-transmitida por i de um processo j para um processo k, um elemento hj, k, mi é adicionado a este conjunto. O símbolo ⊥ representa um elemento nulo. O asterisco é usado como curinga. Por exemplo, um elemento hj, ∗, mi, por exemplo, representa todos os ACKs pendentes para uma mensagem m recebida pelo processo j e retransmitida para qualquer outro processo.
• pendingi: lista de mensagens m recebidas pelo processo i de um processo fonte
source(m)que ainda não podem ser entregues à aplicação por estarem fora de ordem, isto é, ts(m) > ts(lasti(source(m)) + 1.
Um processo i inicia a difusão invocando o método BROADCAST(m). A linha 7
garante que um novo broadcast só é iniciado após o término do anterior, isto é, quando não há acks pendentes para a mensagem lasti[i]. Nas linhas 9 - 10 a nova mensagem m
é entregue localmente (propriedade de entrega confiável) e em seguida enviada a todos os vizinhos no VCube através da função BROADCAST_TREE. Esta função utiliza BRO- ADCAST_CLUSTERpara enviar mensagens TREE para cada primeiro processo sem-falha
em cada cluster s = 1.. log2n, e mensagens DELV para os processos considerados fa-
lhos (suspeitos). Para cada mensagem TREE enviada, um ack é incluído na lista de acks pendentes. A Figura 2 ilustra exemplos para um VCube de 3 dimensões. A Figura 2(a) mostra uma execução sem falhas considerando o processo 0 (p0) como fonte. Após fazer
a entrega local, p0envia uma cópia da mensagem para p1, p2e p4, que são os vizinhos dele
em cada cluster. Embora p5 também pertença ao mesmo cluster de p4, p0 não envia uma
cópia da mensagem para p5, pois não há aresta no VCube conectando os dois processos.
Quando um processo i recebe uma mensagem hT REE, mi de um processo j (linha 39) ele invoca HANDLE_MESSAGE. Nela é verificado se a mensagem é nova com-
parando os timestamps da última mensagem armazenada em lasti[j]e da mensagem rece-
lasti[j]é atualizado e a mensagem é entregue à aplicação. Em seguida, o processo i ve-
rifica se o processo origem da mensagem está falho. Se a origem ainda é considerada correta, m é retransmitida para os vizinhos em cada cluster interno ao cluster de i que também fazem parte do grupo com os destinatários da mensagem. Isso é feito durante a execução da função BROADCAST_CLUSTER com parâmetro h = clusteri(j)− 1. A
Figura 2(a) ilustra a propagação feita por p4 para p5. Se i é uma folha da árvore (clus-
ters s = 1) ou se não existe vizinho correto pertencente aos destinatários, nenhum ack pendente é adicionado ao conjunto ack_seti e CHECKACKS envia uma mensagem ACK
para j. Por outro lado, se um processo i recebe uma mensagem nova hT REE, mi, mas verifica que source(m) foi detectado como falho, o processo de broadcast é reiniciado considerando a árvore com raiz em i.
Quando uma mensagem hACK, mi é recebida, o conjunto ack_seti é atualizado
e, se não existem mais acks pendentes para a mensagem m, CHECKACKS envia um ACK
para o processo k do qual i recebeu a mensagem TREE anteriormente. No entanto, se k = i, a mensagem ACK alcançou o processo fonte ou o processo que retransmitiu a mensagem após a falha do processo fonte. Nesse caso, a mensagem de ACK não precisa mais ser propagada.
A detecção de um processo falho j é tratada após a notificação do evento Algoritmo 1 Difusão confiável no processo i
1:lasti[n]← {⊥, ..., ⊥}
2:ack_seti← ∅
3:correcti← {0, ..., n − 1}
4:pendingi← ∅
5:procedureBROADCAST(message m)
6: if source(m) = i then
7: wait until ack_seti∩ {h⊥, ∗, lasti[i]i} = ∅
8: lasti[i]← m
9: DELIVER(m)
10: BROADCAST_TREE(⊥,m, log2n)
11: procedureBROADCAST_TREE(process j, message m, inte-
ger h)
12: for all s ∈ [1, h] do
13: BROADCAST_CLUSTER(j,m, s)
14: procedureBROADCAST_CLUSTER(process j, message m, integer s)
15: sent← false
16: for all k ∈ ci,sdo
17: if sent = false then
18: if hj, k, mi ∈ ack_setiand k ∈ correctithen
19: sent← true
20: else if k ∈ correctithen
21: SEND(hT REE, mi) to pk
22: ack_seti← ack_seti∪ {hj, k, mi}
23: sent← true
24: else if hj, k, mi /∈ ack_setithen
25: SEND(hDELV, mi) to pk
26: procedureCHECK_ACKS(process j, message m)
27: if j 6= ⊥ and ack_seti∩ {hj, ∗, mi} = ∅ then
28: if j ∈ correctithen
29: SEND(hACK, mi) to pj
30: procedureHANDLE_MESSAGE(message m)
31: pendingi← pendingi∪ {m}
32: while ∃l ∈ pendingi : (source(l) = source(m)∧ ts(l) = ts(lasti[source(m)]) + 1)
33: or (lasti[source(m)] =⊥ ∧ ts(l) = 0) do
34: lasti[source(m)]← l
35: pendingi← pendingi\{l}
36: DELIVER(l)
37: if source(m) /∈ correctithen
38: BROADCAST(m)
39: upon receive hT REE, mi from pj
40: HANDLE_MESSAGE(m)
41: BROADCAST_TREE(m,clusteri(j)− 1)
42: CHECK_ACKS(j,m)
43: upon receive hDELV, mi from pj
44: HANDLE_MESSAGE(m)
45: upon receive hACK, mi from pj
46: for all k = x : hx, j, mi ∈ ack_setido
47: ack_seti← ack_seti\{hk, j, mi}
48: CHECK_ACKS(k,m)
49: upon notifying crash(process j)
50: correcti← correctir {j}
51: for all p = x, m = y : hx, j, yi ∈ ack_seti∩ {h∗, j, ∗i} do
52: BROADCAST_CLUSTER(p,m, clusteri(j))
53: ack_seti← ack_seti\{hp, j, mi}
54: CHECK_ACKS(p,m)
55: if lasti[j]6= ⊥ then
56: BROADCAST(lasti[j])
57: upon notifying up(process j)
CRASH(j). Três ações são realizadas: (1) atualização da lista de processos corretos; (2)
remoção dos acks pendentes que contém o processo j como destino ou aqueles em que a mensagem m foi originada em j; (3) reenvio das mensagens anteriormente transmitidas ao processo j para o novo vizinho correto k no mesmo cluster de j, se existir um. Esta retransmissão desencadeia uma propagação na nova estrutura da árvore. No exemplo da Figura 2(b), após a notificação de falha de p4, p0retransmite a mensagem para o processo
p5, visto que c0,3 = (4, 5, 6, 7), p5 é o próximo processo sem falha no cluster s = 3. A
propagação continua pelos demais processos corretos do cluster, isto é, p6 e p7. Se p4 é
considerado falho antes do início da difusão, uma mensagem DELV é enviada a ele para garantir o recebimento por p4em caso de falsa suspeita.
5. Conclusão
Este trabalho apresentou uma proposta de solução distribuída para a difusão confiável (broadcast) em sistemas distribuídos sujeitos a falhas de crash em ambientes assíncronos. Árvores com raiz em cada processo são construídas e mantidas dinamicamente sobre uma topologia de hipercubo virtual denominada VCube. Em caso de falhas, os processos são reorganizados de forma a manter as propriedades logarítmicas do hipercubo. Falsas suspeitas são contornadas pelo envio de mensagens adicionais aos processos considerados falhos, porém mantendo-se as principais propriedades do hipercubo.
Como trabalhos futuros, o algoritmo será especificado formalmente, incluindo provas de correção, e testes de desempenho serão realizados por simulação comparando-o com outras soluções.
Referências
Bonomi, S., Del Pozzo, A. e Baldoni, R. (2013). Intrusion-tolerant reliable broadcast. Technical report, Sapienza Università di Roma,.
Chandra, T. D., Hadzilacos, V. e Toueg, S. (1996). The weakest failure detector for solving consensus. Journal of the ACM, 43(4):685–722.
Duarte, Jr., E. P., Bona, L. C. E. e Ruoso, V. K. (2014). VCube: A provably scalable dis- tributed diagnosis algorithm. In: 5th Work. on Latest Advances in Scalable Algorithms for Large-Scale Systems, ScalA’14, pp. 17–22, Piscataway, USA. IEEE Press.
Hadzilacos, V. e Toueg, S. (1993). Fault-tolerant broadcasts and related problems. In: Distributed systems, pp. 97–145. ACM Press, New York, NY, USA, 2 ed.
Liebeherr, J. e Beam, T. (1999). HyperCast: A protocol for maintaining multicast group members in a logical hypercube topology. In: Rizzo, L. e Fdida, S., editores, Networ- ked Group Communication, v. 1736 de LNCS, pp. 72–89. Springer Berlin Heidelberg. Rodrigues, L. A., Duarte Jr., E. P. e Arantes, L. (2014). Árvores geradoras mínimas
distribuídas e autonômicas. In: XXXII Simpósio Brasileiro de Redes de Computadores e Sistemas Distribuídos, SBRC’14.
Ruoso, V. K. (2013). Uma estratégia de testes logarítmica para o algoritmo Hi-ADSD. Dissertação de Mestrado, Universidade Federal do Paraná.
Schneider, F. B., Gries, D. e Schlichting, R. D. (1984). Fault-tolerant broadcasts. Sci. Comput. Program., 4(1):1–15.
Wu, J. (1996). Optimal broadcasting in hypercubes with link faults using limited global information. J. Syst. Archit., 42(5):367–380.