Como implementamos o cache no banco de dados Tarantool

Bom dia

Quero compartilhar com você uma história sobre a implementação do cache no banco de dados Tarantool e meus recursos de trabalho.
Eu trabalho como desenvolvedor Java em uma empresa de telecomunicações. A principal tarefa: a implementação da lógica de negócios da plataforma que a empresa comprou do fornecedor. Dos primeiros recursos, esse é um trabalho de sabão e a quase completa ausência de armazenamento em cache, exceto na memória da JVM. Tudo isso é bom até que o número de instâncias de aplicativos exceda duas dúzias ...

No decorrer do trabalho e no surgimento de um entendimento dos recursos da plataforma, foi feita uma tentativa de fazer cache. Naquela época, o MongoDB já havia sido lançado e, como resultado, não obtivemos resultados positivos especiais como no teste.

Em uma busca adicional por alternativas e conselhos do meu amigo mr_elzor , foi decidido tentar o banco de dados Tarantool.

Em um estudo superficial, apenas a dúvida apareceu na lua, uma vez que não havia escrito sobre ela com a palavra "completamente". Mas afastando todas as dúvidas, ele começou a instalar. Sobre redes fechadas e firewalls, acho que poucas pessoas estão interessadas, mas aconselho você a tentar contorná-las e colocar tudo de fontes públicas.

Servidores de teste com configuração: 8 Cpu, 16 GB de RAM, 100 Gb de disco rígido, Debian 9.4.

A instalação foi realizada de acordo com as instruções do site. E então eu tenho uma opção de exemplo. A idéia surgiu imediatamente de uma interface visual com a qual o suporte funcionaria convenientemente. Durante uma pesquisa rápida, encontrei e configurei o tarantool-admin . Trabalha no Docker e abrange tarefas de suporte 100%, pelo menos por enquanto.

Mas vamos falar sobre mais interessante.

O próximo pensamento foi configurar minha versão na configuração mestre - escravo no mesmo servidor, pois a documentação contém apenas exemplos com dois servidores diferentes.

Depois de passar algum tempo entendendo lua e descrevendo a configuração, inicio o assistente.

# systemctl start tarantool@master Job for tarantool@master.service failed because the control process exited with error code. See "systemctl status tarantool@master.service" and "journalctl -xe" for details. 

Imediatamente caí em um estupor e não entendo por que o erro ocorre, mas vejo que ele está no status "carregando".

 # systemctl status tarantool@master ● tarantool@master.service - Tarantool Database Server Loaded: loaded (/lib/systemd/system/tarantool@.service; enabled; vendor preset: enabled) Active: activating (start) since Tue 2019-02-19 17:03:24 MSK; 17s ago Docs: man:tarantool(1) Process: 20111 ExecStop=/usr/bin/tarantoolctl stop master (code=exited, status=0/SUCCESS) Main PID: 20120 (tarantool) Status: "loading" Tasks: 5 (limit: 4915) CGroup: /system.slice/system-tarantool.slice/tarantool@master.service └─20120 tarantool master.lua <loading> Feb 19 17:03:24 tarantuldb-tst4 systemd[1]: Starting Tarantool Database Server... Feb 19 17:03:24 tarantuldb-tst4 tarantoolctl[20120]: Starting instance master... Feb 19 17:03:24 tarantuldb-tst4 tarantoolctl[20120]: Run console at unix/:/var/run/tarantool/master.control Feb 19 17:03:24 tarantuldb-tst4 tarantoolctl[20120]: started 

Eu corro escravo:

 # systemctl start tarantool@slave2 Job for tarantool@slave2.service failed because the control process exited with error code. See "systemctl status tarantool@slave2.service" and "journalctl -xe" for details. 

E eu vejo o mesmo erro. Aqui, geralmente começo a me esforçar e não entendo o que está acontecendo, pois não há nada na documentação sobre isso ... Mas, ao verificar o status, vejo que ele não começou, apesar de dizer que o status está "em execução":

 # systemctl status tarantool@slave2 ● tarantool@slave2.service - Tarantool Database Server Loaded: loaded (/lib/systemd/system/tarantool@.service; enabled; vendor preset: enabled) Active: failed (Result: exit-code) since Tue 2019-02-19 17:04:52 MSK; 27s ago Docs: man:tarantool(1) Process: 20258 ExecStop=/usr/bin/tarantoolctl stop slave2 (code=exited, status=0/SUCCESS) Process: 20247 ExecStart=/usr/bin/tarantoolctl start slave2 (code=exited, status=1/FAILURE) Main PID: 20247 (code=exited, status=1/FAILURE) Status: "running" Feb 19 17:04:52 tarantuldb-tst4 systemd[1]: tarantool@slave2.service: Unit entered failed state. Feb 19 17:04:52 tarantuldb-tst4 systemd[1]: tarantool@slave2.service: Failed with result 'exit-code'. Feb 19 17:04:52 tarantuldb-tst4 systemd[1]: tarantool@slave2.service: Service hold-off time over, scheduling restart. Feb 19 17:04:52 tarantuldb-tst4 systemd[1]: Stopped Tarantool Database Server. Feb 19 17:04:52 tarantuldb-tst4 systemd[1]: tarantool@slave2.service: Start request repeated too quickly. Feb 19 17:04:52 tarantuldb-tst4 systemd[1]: Failed to start Tarantool Database Server. Feb 19 17:04:52 tarantuldb-tst4 systemd[1]: tarantool@slave2.service: Unit entered failed state. Feb 19 17:04:52 tarantuldb-tst4 systemd[1]: tarantool@slave2.service: Failed with result 'exit-code'. 

Mas, ao mesmo tempo, o mestre começou a trabalhar:

 # ps -ef | grep taran taranto+ 20158 1 0 17:04 ? 00:00:00 tarantool master.lua <running> root 20268 2921 0 17:06 pts/1 00:00:00 grep taran 

Reiniciar o escravo não ajuda. Eu me pergunto por que?

Eu paro o mestre. E execute as ações na ordem inversa.

Eu vejo que o escravo está tentando começar.

 # ps -ef | grep taran taranto+ 20399 1 0 17:09 ? 00:00:00 tarantool slave2.lua <loading> 

Inicio o assistente e vejo que ele não aumentou e geralmente mudou para o status de órfão, enquanto o escravo geralmente caiu.

 # ps -ef | grep taran taranto+ 20428 1 0 17:09 ? 00:00:00 tarantool master.lua <orphan> 

Torna-se ainda mais interessante.

Vejo nos logs do escravo que ele até viu o mestre e tentou sincronizar.

 2019-02-19 17:13:45.113 [20751] iproto/101/main D> binary: binding to 0.0.0.0:3302... 2019-02-19 17:13:45.113 [20751] iproto/101/main I> binary: bound to 0.0.0.0:3302 2019-02-19 17:13:45.113 [20751] iproto/101/main D> binary: listening on 0.0.0.0:3302... 2019-02-19 17:13:45.113 [20751] iproto D> cpipe_flush_cb: locking &endpoint->mutex 2019-02-19 17:13:45.113 [20751] iproto D> cpipe_flush_cb: unlocking &endpoint->mutex 2019-02-19 17:13:45.113 [20751] main D> cbus_endpoint_fetch: locking &endpoint->mutex 2019-02-19 17:13:45.113 [20751] main D> cbus_endpoint_fetch: unlocking &endpoint->mutex 2019-02-19 17:13:45.113 [20751] main/101/slave2 I> connecting to 1 replicas 2019-02-19 17:13:45.113 [20751] main/106/applier/replicator@tarantuldb-t D> => CONNECT 2019-02-19 17:13:45.114 [20751] main/106/applier/replicator@tarantuldb-t I> remote master 825af7c3-f8df-4db0-8559-a866b8310077 at 10.78.221.74:3301 running Tarantool 1.10.2 2019-02-19 17:13:45.114 [20751] main/106/applier/replicator@tarantuldb-t D> => CONNECTED 2019-02-19 17:13:45.114 [20751] main/101/slave2 I> connected to 1 replicas 2019-02-19 17:13:45.114 [20751] coio V> loading vylog 14 2019-02-19 17:13:45.114 [20751] coio V> done loading vylog 2019-02-19 17:13:45.114 [20751] main/101/slave2 I> recovery start 2019-02-19 17:13:45.114 [20751] main/101/slave2 I> recovering from `/var/lib/tarantool/cache_slave2/00000000000000000014.snap' 2019-02-19 17:13:45.114 [20751] main/101/slave2 D> memtx_tuple_new(47) = 0x7f99a4000080 2019-02-19 17:13:45.114 [20751] main/101/slave2 I> cluster uuid 4035b563-67f8-4e85-95cc-e03429f1fa4d 2019-02-19 17:13:45.114 [20751] main/101/slave2 D> memtx_tuple_new(11) = 0x7f99a4004080 2019-02-19 17:13:45.114 [20751] main/101/slave2 D> memtx_tuple_new(17) = 0x7f99a4008068 

E a tentativa foi bem sucedida:

 2019-02-19 17:13:45.118 [20751] main/101/slave2 D> memtx_tuple_new(40) = 0x7f99a40004c0 2019-02-19 17:13:45.118 [20751] main/101/slave2 I> assigned id 1 to replica 825af7c3-f8df-4db0-8559-a866b8310077 2019-02-19 17:13:45.118 [20751] main/101/slave2 D> memtx_tuple_new(40) = 0x7f99a4000500 2019-02-19 17:13:45.118 [20751] main/101/slave2 I> assigned id 2 to replica 403c0323-5a9b-480d-9e71-5ba22d4ccf1b 2019-02-19 17:13:45.118 [20751] main/101/slave2 I> recover from `/var/lib/tarantool/slave2/00000000000000000014.xlog' 2019-02-19 17:13:45.118 [20751] main/101/slave2 I> done `/var/lib/tarantool/slave2/00000000000000000014.xlog' 

Até começou:

 2019-02-19 17:13:45.119 [20751] main/101/slave2 D> systemd: sending message 'STATUS=running' 

Mas, por razões desconhecidas, ele perdeu a conexão e caiu:

 2019-02-19 17:13:45.129 [20751] main/101/slave2 D> SystemError at /build/tarantool-1.10.2.146/src/coio_task.c:416 2019-02-19 17:13:45.129 [20751] main/101/slave2 tarantoolctl:532 E> Start failed: /usr/local/share/lua/5.1/http/server.lua:1146: Can't create tcp_server: Input/output error 

Tentar iniciar o escravo novamente não ajuda.

Agora exclua os arquivos criados pelas instâncias. No meu caso, excluo tudo do diretório / var / lib / tarantool.

Eu começo o escravo primeiro, e só depois o mestre. E eis que ...

 # ps -ef | grep tara taranto+ 20922 1 0 17:20 ? 00:00:00 tarantool slave2.lua <running> taranto+ 20933 1 1 17:21 ? 00:00:00 tarantool master.lua <running> 

Não encontrei nenhuma explicação para esse comportamento, exceto como um "recurso deste software".
Essa situação aparecerá sempre que o servidor tiver sido completamente reiniciado.

Após uma análise mais aprofundada da arquitetura deste software, verifica-se que está planejado usar apenas uma vCPU para uma instância e muitos outros recursos permanecem livres.

Na ideologia de n vCPU, podemos criar o mestre e n-2 escravos para leitura.

Dado que no servidor de teste 8 vCPU, podemos aumentar o mestre e 6 instâncias para leitura.
Copio o arquivo para escravo, corrijo as portas e corro, ou seja, mais alguns escravos são adicionados.

Importante! Ao adicionar outra instância, você deve registrá-la no assistente.
Mas você deve primeiro iniciar um novo escravo e só depois reiniciar o mestre.

Exemplo


Eu já tinha uma configuração em execução com um assistente e dois escravos.

Eu decidi adicionar um terceiro escravo.

Registrei-o no mestre e reiniciei o mestre primeiro, e foi o que vi:

 # ps -ef | grep tara taranto+ 20922 1 0 Feb19 ? 00:00:29 tarantool slave2.lua <running> taranto+ 20965 1 0 Feb19 ? 00:00:29 tarantool slave3.lua <running> taranto+ 21519 1 0 09:16 ? 00:00:00 tarantool master.lua <orphan> 

I.e. nosso mestre se tornou um solitário e a replicação se desfez.

Iniciar um novo escravo não ajudará mais e resultará em um erro:

 # systemctl restart tarantool@slave4 Job for tarantool@slave4.service failed because the control process exited with error code. See "systemctl status tarantool@slave4.service" and "journalctl -xe" for details. 

E nos logs, vi uma pequena entrada informativa:

 2019-02-20 09:20:10.616 [21601] main/101/slave4 I> bootstrapping replica from 3c77eb9d-2fa1-4a27-885f-e72defa5cd96 at 10.78.221.74:3301 2019-02-20 09:20:10.617 [21601] main/106/applier/replicator@tarantuldb-t I> can't join/subscribe 2019-02-20 09:20:10.617 [21601] main/106/applier/replicator@tarantuldb-t xrow.c:896 E> ER_READONLY: Can't modify data because this instance is in read-only mode. 2019-02-20 09:20:10.617 [21601] main/106/applier/replicator@tarantuldb-t D> => STOPPED 2019-02-20 09:20:10.617 [21601] main/101/slave4 xrow.c:896 E> ER_READONLY: Can't modify data because this instance is in read-only mode. 2019-02-20 09:20:10.617 [21601] main/101/slave4 F> can't initialize storage: Can't modify data because this instance is in read-only mode. 

Paramos o mago e começamos um novo escravo. Também haverá um erro, como no primeiro início, mas veremos que ele está carregando o status.

 # ps -ef | grep tara taranto+ 20922 1 0 Feb19 ? 00:00:29 tarantool slave2.lua <running> taranto+ 20965 1 0 Feb19 ? 00:00:30 tarantool slave3.lua <running> taranto+ 21659 1 0 09:23 ? 00:00:00 tarantool slave4.lua <loading> 

Mas quando você inicia o master, o novo escravo trava e o master não acompanha o status de execução.

 # ps -ef | grep tara taranto+ 20922 1 0 Feb19 ? 00:00:29 tarantool slave2.lua <running> taranto+ 20965 1 0 Feb19 ? 00:00:30 tarantool slave3.lua <running> taranto+ 21670 1 0 09:23 ? 00:00:00 tarantool master.lua <orphan> 

Nesta situação, há apenas uma saída. Como escrevi anteriormente, excluo os arquivos criados por instâncias e executo os escravos primeiro e depois os domino.

 # ps -ef | grep tarantool taranto+ 21892 1 0 09:30 ? 00:00:00 tarantool slave4.lua <running> taranto+ 21907 1 0 09:30 ? 00:00:00 tarantool slave3.lua <running> taranto+ 21922 1 0 09:30 ? 00:00:00 tarantool slave2.lua <running> taranto+ 21931 1 0 09:30 ? 00:00:00 tarantool master.lua <running> 

Tudo começou com sucesso.

Foi assim que, por tentativa e erro, descobri como configurar e iniciar a replicação corretamente.

Como resultado, a seguinte configuração foi montada:

2 servidores.
2 mestre. Reserva quente.
12 escravos. Todos estão ativos.

Na lógica do tarantool, o http.server foi usado para não bloquear o adaptador adicional (lembre-se do fornecedor, plataforma e sabão) ou fixar a biblioteca a cada processo de negócios.

Para evitar uma discrepância entre os mestres, no balanceador (NetScaler, HAProxy ou qualquer outro favorito), definimos a regra de reserva, ou seja, operações de inserção, atualização e exclusão vão apenas para o primeiro mestre ativo.

Nesse momento, o segundo simplesmente replica os registros do primeiro. Os próprios escravos são conectados ao primeiro mestre especificado a partir da configuração, que é o que precisamos nesta situação.

Em lua, implementamos operações CRUD para valor-chave. No momento, isso é suficiente para resolver o problema.

Em vista dos recursos do trabalho com sabão, foi implementado um processo de negócios de proxy, no qual foi estabelecida a lógica de trabalhar com uma tarântula via http.

Se os dados principais estiverem presentes, eles serão retornados imediatamente. Caso contrário, uma solicitação é enviada ao sistema mestre e armazenada no banco de dados Tarantool.

Como resultado, um processo comercial nos testes processa até 4k solicitações. Nesse caso, o tempo de resposta da tarântula é de ~ 1ms. O tempo médio de resposta é de até 3 ms.

Aqui estão algumas informações dos testes:



Havia 50 processos de negócios que vão para 4 sistemas principais e armazenam dados em cache em sua memória. Duplicação de informações em pleno crescimento em cada instância. Dado que o java já adora memória ... a perspectiva não é a melhor.

Agora


50 processos de negócios solicitam informações através do cache. Agora, as informações de 4 instâncias do assistente são armazenadas em um local e não são armazenadas em cache na memória em cada instância. Foi possível reduzir significativamente a carga no sistema mestre, não há duplicatas de informações e o consumo de memória nas instâncias com lógica de negócios diminuiu.

Um exemplo do tamanho do armazenamento de informações na memória da tarântula:



No final do dia, esses números podem dobrar, mas não há "rebaixamento" no desempenho.

Na batalha, a versão atual cria solicitações de 2 a 2,5k por segundo de carga real. O tempo médio de resposta é semelhante a testes de até 3ms.

Se você olhar o htop em um dos servidores com tarantool, veremos que eles estão "esfriando":



Sumário


Apesar de todas as sutilezas e nuances do banco de dados Tarantool, você pode obter um ótimo desempenho.

Espero que este projeto se desenvolva e que esses momentos desconfortáveis ​​sejam resolvidos.

Source: https://habr.com/ru/post/pt441686/


All Articles