O Netflix recentemente apresentou o Hollow, uma biblioteca e um conjunto de ferramentas Java para processar datasets em memória que não são caracterizados como "big data." Como datasets podem conter metadata para e-commerce e motores de busca, ou no caso do Netflix, metadata sobre filmes e shows de TV. Soluções tradicionais para processar estes datasets requerem o uso de banco de dados ou serialização, mas normalmente sofrem de problemas de confiabilidade e latência. O guia de inicialização do Hollow resume os conceitos principais e a nomenclatura:
O Hollow gerencia datasets que são fornecidos por um simples producer, e disseminados somente com permissão de leitura para um ou vários consumers. Um dataset muda ao longo do tempo. A linha de tempo para um dataset em mudança pode ser dividida em discretos estados de dados, no qual cada um é um snapshot completo dos dados em um determinado ponto no tempo.
O producer e os consumer manipulam os datasets através de um state engine que transita entre os estados dos dados. Um producer usa um write state engine e um consumer usa um read state engine.
O Hollow substitui o framework anterior de dados em memória do Netflix, o Zeno. Os datasets agora são representados com uma codificação compacta, de tamanho fixo, fortemente tipada. Essa codificação minimiza o rastro dos datasets e os registros codificados são "agrupados dentro de pedaços reutilizáveis da memória que são armazenados na heap da JVM para evitar impactar o comportamento do GC em servidores muito ocupados."
Começando
Como ponto de partida, considere o seguinte POJO:
public class Movie { long id; String title; int releaseYear; public Movie(long id,String title,int releaseYear) { this.id = id; this.title = title; this.releaseYear = releaseYear; } }
Um simples dataset baseado no POJO acima pode ser populado como:
Listmovies = Arrays.asList( new Movie(1,"The Matrix",1999), new Movie(2,"Beasts of No Nation",2015), new Movie(3,"Goodfellas",1990), new Movie(4,"Inception",2010) ); O Hollow traduz a lista de filmes para o novo layout de codificação como mostrado a seguir:
Mais detalhes sobre essa codificação podem ser encontrados na seção Advanced Topics no website do Hollow.
O Producer
A primeira instância de um producer disponibiliza um estado dos dados inicial de um dataset (filmes neste exemplo) e consumers são notificados em onde encontrar esse conjunto de dados. Alterações subsequentes no conjunto de dados são sistematicamente publicados e comunicadas para os consumers.
Um producer usa um HollowWriteStateEngine como gerenciador para um dataset:
HollowWriteStateEngine writeEngine = new HollowWriteStateEngine();
Um HollowObjectMapper popula um HollowWriteStateEngine:
HollowObjectMapper objectMapper = new HollowObjectMapper(writeEngine); for(Movie movie : movies) { objectMapper.addObject(movie); }
O HollowObjectMapper é thread safe e também pode ser executado em paralelo.
O producer escreve o dataset (também conhecido como blob) em um determinado output stream:
OutputStream os = new BufferedOutputStream(new FileOutputStream(snapshotFile)); HollowBlobWriter writer = new HollowBlobWriter(writeEngine); writer.writeSnapshot(os);
Gerando uma API para Consumers
Uma API cliente gera o código Java necessário com base no modelo de dados e deve ser executado antes de escrever o código inicial do consumer:
HollowAPIGenerator codeGenerator = new HollowAPIGenerator( "MovieAPI", // um nome para a API "org.redlich.hollow.consumer.api.generated", // o path para os arquivos da API gerados stateEngine); // o state engine codeGenerator.generateFiles(apiCodeFolder);
O Consumer
Uma vez que o consumer é notificado de que um dataset foi publicado, o consumer usa um HollowWriteReadEngine para manipular o dataset:
HollowReadStateEngine readEngine = new HollowReadStateEngine();
Um HollowBlobReader consome um blob do producer dentro de um HollowReadStateEngine:
HollowBlobReader reader = new HollowBlobReader(readEngine); InputStream is = new BufferedInputStream(new FileInputStream(snapshotFile)); reader.readSnapshot(is);
Os dados dentro do dataset podem ser acessados através da API gerada:
MovieAPI movieAPI = consumer.getAPI(); for(MovieHollow movie : movieAPI.getAllMovieHollow()) { System.out.println(movie._getId() + ", " + movie._getTitle()._getValue() + ", " + movie._getReleaseYear()); }
O seguinte saída será exibida:
1, "The Matrix", 1999 2, "Beasts of No Nation", 2015 3, "Goodfellas", 1990 4,"Inception", 2010
Todo o projeto Hollow pode ser encontrado no GitHub.
A InfoQ recentemente apresentou uma entrevista detalhada com Drew Koszewnik, engenheiro de software senior na Netflix e contribuidor líder do Hollow, sobre os detalhes específicos da implementação do Hollow.