Recebemos dados de GPS em tempo real a uma taxa de cerca de 5000 pr. minuto (de 4 servidores TCP). Cada servidor usa uma conexão única para inserir os dados e armazena em buffer os dados entre as inserções. A cada 15 minutos, aproximadamente, um serviço busca esses dados e os processa em viagens. Depois que as viagens são geradas, os dados reais do GPS geralmente não são tão importantes, apenas se o usuário quiser ver a rota em um mapa.
O problema é que parece que o banco de dados está lutando para acompanhar a taxa de dados inseridos. Às vezes, quando a carga aumenta, o tempo de inserção aumenta repentinamente drasticamente (> 30 segundos), o que, por sua vez, permite que mais dados sejam armazenados em buffer, o que resulta em pastilhas maiores e maior duração da pastilha.
Espero receber alguns comentários sobre o design atual e algumas das idéias que temos para melhorar o desempenho, além de respostas para algumas de nossas perguntas - e outras dicas que as pessoas possam ter!
Design atual
Atualmente, os dados são separados em tabelas que representam uma semana e os dados anteriores a um ano são arquivados em um banco de dados secundário. A coisa toda é unida em uma exibição editável, usada para inserções e leituras.
Design da mesa
- ID (PK, identificador exclusivo)
- DeviceId (FK, int)
- PersonId (FK, int)
- ID do veículo (FK, int)
- TokenId (FK, int)
- UtcTime (PK, datetime2 (3))
- Latitude (flutuante)
- Longitude (flutuante)
- Velocidade (smallint)
- Título (smallint)
- Satélites (tinyint)
- IOData (varbinário (100))
- IgnitionState (tinyint)
- UserInput (tinyint)
- CreateTimeUtc (datetime2 (3))
Índices
- DeviceId_CreateTimeUtc_Desc
- DeviceId_UtcTime_Desc (agrupado)
- PersonId_UtcTime_Desc
- TokenId_UtcTime_Desc
- VehicleId_UtcTime_Desc
Atualmente, toda semana ocupa cerca de 10 GB, incluindo índices, e atualmente existem cerca de 300 GB de dados no banco de dados principal.
As tabelas de dados no banco de dados principal têm seu próprio grupo de arquivos com 1 arquivo, mas estão no mesmo disco que todas as outras tabelas no banco de dados principal. O banco de dados secundário está em um disco diferente, mas na mesma máquina.
Acho que também estamos executando um trabalho de reconstrução do índice semanalmente, quando uma nova partição de tabela (semana) é usada. Nenhum encolhimento é realizado.
A máquina é um HP de 8 núcleos com 12 GB de memória e o disco que contém o banco de dados principal está executando o RAID 10.
Ideias
- Limite a quantidade de dados armazenados no banco de dados primário para, por exemplo, no máximo 1 mês. No mínimo, isso tornaria o banco de dados mais gerenciável para backup / restauração, mas poderíamos esperar uma melhoria no desempenho fazendo isso?
- Crie 2 arquivos no grupo de arquivos para dados atuais e distribua-os em 2 partições físicas diferentes
- Crie bancos de dados mestre-escravo com dados atuais, para que inserções e leituras sejam executadas em diferentes bancos de dados
- Colocar arquivos para dados atuais em discos SSD (o espelhamento faria alguma diferença de desempenho com os discos SSD?)
Entre em contato se precisar de mais informações. Há terrivelmente muitos fatores que influenciam o desempenho e, provavelmente, muitas maneiras de ajustá-lo.
fonte
Respostas:
5000 inserções por minuto são cerca de 83 inserções por segundo. Com 5 índices, são 400 linhas físicas inseridas por segundo. Se a carga de trabalho estivesse na memória, isso não seria um problema, mesmo para o menor dos servidores. Mesmo se essa fosse uma inserção linha por linha, da maneira mais ineficiente possível. 83 consultas triviais por segundo simplesmente não são interessantes do ponto de vista da CPU.
Provavelmente, você está ligado ao disco. Você pode verificar isso consultando as estatísticas de espera ou
STATISTICS IO
.Suas consultas provavelmente tocam muitas páginas diferentes, para que o buffer pool não tenha espaço para todas elas. Isso causa leituras freqüentes de páginas e provavelmente gravações aleatórias em disco também.
Imagine uma tabela na qual você apenas insere fisicamente no final por causa de uma chave cada vez maior. O conjunto de trabalho seria uma página: a última. Isso geraria E / S sequencial, assim como o processo preguiçoso do gravador ou do ponto de verificação grava o "final" da tabela no disco.
Imagine uma tabela com inserções colocadas aleatoriamente (exemplo clássico: uma chave guid). Aqui, todas as páginas são o conjunto de trabalho porque uma página aleatória será tocada para cada inserção. IOs são aleatórios. Este é o pior caso quando se trata de conjunto de trabalho.
Você está no meio. Seus índices são da estrutura
(SomeValue, SequentialDateTime)
. O primeiro componente randomiza parcialmente a sequencialidade fornecida pelo segundo. Eu acho que existem alguns valores possíveis para "SomeValue
" para que você tenha muitos pontos de inserção aleatoriamente inseridos em seus índices.Você diz que os dados são divididos em tabelas de 10 GB por semana. Esse é um bom ponto de partida, porque o conjunto de trabalho agora é limitado por 10 GB (desconsiderando qualquer leitura que você possa fazer). Com 12 GB de memória do servidor, porém, é improvável que todas as páginas relevantes possam permanecer na memória.
Se você pudesse reduzir o tamanho das "partições" semanais ou aumentar um pouco a memória do servidor, provavelmente está bem.
Eu esperava que as inserções no início da semana fossem mais rápidas que no final. Você pode testar essa teoria em um servidor de desenvolvimento executando uma referência com um determinado tamanho de dados e reduzindo gradualmente a memória do servidor até ver o tanque de desempenho.
Agora, mesmo que todas as leituras e gravações caibam na memória, você ainda poderá ter E / S liberando aleatoriamente páginas sujas. A única maneira de se livrar disso é escrever em posições co-localizadas nos seus índices. Se você puder converter seus índices para usar (mais) chaves seqüenciais que ajudariam muito.
Como solução rápida, eu adicionaria uma camada de buffer entre os clientes e a tabela principal. Talvez acumule 15 minutos de gravações em uma tabela intermediária e limpe-a periodicamente. Isso elimina os picos de carga e usa um plano mais eficiente para gravar na grande mesa.
fonte