Assim como o open source, os padrões abertos são criados, evoluídos e lançados por um comunidade de pessoas ou empresas que buscam não depender de licenças pagas e/ou padrões engessados.
Dentre tantos padrões maravilhosos como:
Eis que surge o CloudEvents, para suprir a falta de um padrão para a definicação de eventos na nuvem.
Se você trabalha com eventos, arquitetura orientada à eventos ou é uma empresa orientada à dados, você precisa conhecer este padrão. Ou melhor, você deve adotar CloudEvents!
Durante quase dois anos eu fui voluntário no grupo de trabalho responsável pela definição deste padrão e pela construção das SDKs. Atuei especialmente na especificação Avro e nas SDKs JavaScript e Java.
O Padrão CloudEvents
Este padrão define o atributos comuns a qualquer evento, os Atributos de Contexto. Eles podem ser requeridos ou opcionais. E na versão atual, a 1.0
, são exatamente quatro atributos requeridos:
- id: idenficiador único do evento
- source: fonte do evento, ou seja, qual aplicação o produziu
- specversion: versão da especificação utilizada,
1.0
por exemplo. - type: tipo do evento
Existem muitos outros atributos opcionais, mas o data
em especial é aquele que carrega o payload do evento. Nele encontra-se a carga útil do fato gerado nas aplicações.
E foram definidos dois modos para codificar um evento:
- Estruturado
- Binário
No modo Estruturado o evento é representado inteiramente no corpo do formato de dados utilizado, ou seja, seus atributos e carga útil seguem na estrutura.
E no Binário, os atributos são cabeçalhos e a carga útil segue sozinha no corpo do formato de dados.
Exemplos de Eventos
Tome como exemplo o fato gerado por uma transação financeira que alterou o saldo na conta de um cliente. Ela, depois de confirmada, torna-se um fato e irá compor o balanço financeiro, ou melhor, o extrato.
Definição do Evento
- tipo: Débito Executado ou Crédito Executado
- identificador da transação
- valor da transação
- sistema origem
- código da transação
- número da conta
- data-hora da transação
- descrição da transação
Na definição do evento estão todos os atributos necessários para que o fato seja interpretado por qualquer interessado. E alguns deles fazem parte da carga útil do evento, outros não.
A transação também foi especializada em débito ou crédito, assim os interessados não deverão aplicar lógicas adicionais sobre o atributo “valor da transação” para determinar isso.
Bem, veja como este evento fica quando modelado com CloudEvents.
type
: Débito Realizado ou Crédito Realizadoid
: identificador da transaçãosource
: sistema origemsubject
: código a transaçãotime
: data-hora da transação
O restante das características fazem parte da carga útil:
data
- valor da transação
- número da conta
- descrição da transação
Sempre haverão fortes tendências a colocar todas as características na carga útil do evento, mas sempre tenha em mente que o CloudEvents foi criado com o objetivo de resolver parte disso. Algo que acontece quando se inicia o uso de nova especificação, mas que deve ser resolvida logo no inicio.
No modo estruturado e formato JSON, o evento Débito Executado fica assim:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"type":"ml.kafka.tef.debito.v1",
"id":"a4c15cfb-dc65-4215-9281-aa5fd50201ab",
"source":"https://kafka.ml/tef",
"subject":"890344",
"time":"2020-09-18T05:31:00Z",
"specversion":"1.0",
"datacontenttype": "application/json",
"data":{
"valor": -45.89,
"conta": "234559",
"descricao": "Pagamento de Impostos"
}
}
Existem dois atributos adicionais:
specversion
: define a versão da especificação utilizadadatacontenttype
: tipo do conteúdo emdata
, porque ele poderia ser de qualquer tipo e não exatamente JSON, como o restante do evento.
Então o evento poderá ser emitido através de diversos vínculos de transporte, como:
CloudEvents com Apache Kafka®
Apache Kafka® foi criado para streaming de eventos, nada mais natural que empregar CloudEvents.
Como o formato de dados Avro é um dos mais utilizados, ele será objeto dos exemplos. E o vínculo de transporte, naturalmente, será a especificação CloudEvents para Apache Kafka®.
Também será utilizado o modo binário, o que simplifica muito a operação.
E mesmo no modo estruturado os atributos do evento e o payload data
podem, por definição, serem de tipos diferentes. Ou seja, pode-se utilizar Avro para os atributos CloudEvents e JSON como formato para data
.
O esquema Avro para a transação de débido ou crédito:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"name":"DebitoExecutado",
"namespace":"com.kafkabr.e5o",
"type":"record",
"version":"1",
"fields":[
{
"name":"valor",
"type":"double"
},
{
"name":"conta",
"type":"string"
},
{
"name":"descricao",
"type":"string"
}
]
}
Através de uma aplicação, feita em Java por exemplo, pode-se produzir este evento como um ProducerRecord.
Primeiro definindo os Dados do Eventos como valor do registro:
1
2
3
4
5
DebitoExecutado debito = DebitoExecutado.newBuilder()
.setValor(-45.89)
.setConta("234559")
.setDescricao("Pagamento de Impostos")
.build();
E por segundo os Atributos CloudEvents como cabeçalhos do registro:
Na SDK oficial, o formato Avro ainda não foi implemetado.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
ProducerRecord<String, DebitoExecutado> registro =
new ProducerRecord<>("transacoes", debito.getConta(), debito);
registro.headers().add("ce_type",
"ml.kafka.tef.debito.v1".getBytes());
registro.headers().add("ce_id",
"a4c15cfb-dc65-4215-9281-aa5fd50201ab".getBytes());
registro.headers().add("ce_source",
"https://kafka.ml/tef".getBytes());
registro.headers().add("ce_subject",
"890344".getBytes());
registro.headers().add("ce_time",
"2020-09-18T05:31:00Z".getBytes());
registro.headers().add("ce_specversion",
"1.0".getBytes());
registro.headers().add("content-type",
"application/avro".getBytes());
E por fim, só resta produzir o evento no Apache Kafka®:
1
2
3
4
5
6
7
try(KafkaProducer<String, DebitoExecutado> producer =
new KafkaProducer<>(configs)){
// ####
// Produzir evento
producer.send(registro);
}
Deste momento em diante seu ecossistema de serviços baseado em eventos já está em conformidade com um padrão aberto. E está preparado para as evoluções ou novas ferramentas que surgirão, ou seja, é uma grande contribuição para o seu presente e futuro.
Código Fonte
Como de costume, o código-fonte completo encontra-se no GitHub do Kafka BR:
Obrigado e até o próximo artigo!
Photo by Sam Schooler on Unsplash