Você está na página 1de 29

Universidade do Minho

Mestrado Integrado em Engenharia Informática

Unidade Curricular

Administração de

Bases de Dados

Ano Letivo de 2019/2020

Aluno Número
Rui Boticas A22724
Carlos Monteiro PG41068
Alexandru Domente PG41063
Índice
1. Descrição do Problema ..................................................................................................................... 2
2. Introdução........................................................................................................................................ 3
3. Plataforma de Benchmarking ........................................................................................................... 4
4. Fase Inicial ....................................................................................................................................... 5
5. Análise do Benchmark ...................................................................................................................... 6
6. Otimização dos parâmetros PostgreSQL ........................................................................................... 7
7. Análise de desempenho queries analíticas ...................................................................................... 17
8. Benchmark em Sistemas Distribuídos ............................................................................................. 26
9. Anexos ........................................................................................................................................... 28

1
1. Descrição do Problema

O trabalho prático consiste na configuração, otimização e avaliação do benchmark TPC-C, que simula um
sistema de bases de dados de uma cadeia de lojas, suportando a operação diária de gestão de vendas e
stocks. Este processo vai ser realizado em PostgreSQL 9.6 num ambiente Cloud (Google Cloud).

Os objetivos principais do Benchmarking são:

• Análise das interrogações analíticas;


• Otimizar o desempenho das interrogações analíticas;
• Otimizar o desempenho da carga transacional;
• Manusear as variáveis de PostgreSQL;
• Criação de Backup.

Área de Aplicação: Administração de Base de Dados

Palavras-Chave: Benchmark, Java, PostgreSQL, Cloud

2
2. Introdução

Neste relatório serão apresentadas as experiências obtidas trabalhando com o TPC-C.

Neste sentido pretende-se testar várias configurações, analisar os resultados obtidos e alcançar uma
configuração que seja considerada eficiente para um determinado número de clientes.

Desta forma, procedeu-se a uma descrição de todo o processo, incluindo os testes efetuados até se
alcançar a configuração ideal, como também a otimização que poderia ser feita.

3
3. Plataforma de Benchmarking

Inicialmente estabelecemos uma necessidade de utilização de 4 GB RAM para o nosso Benchmark.

Das configurações disponíveis na Google Cloud, a escolhida seria a única opção que nos permitiria
equilibrar o saldo gasto em função da performance.

Características

ü CPU 4 Cores
ü Memória 3.6 GB RAM
ü Disco SSD
ü Time zone Europe

Política de disponibilidade

Relativamente a esta política escolhemos não ativar o modo “Preempção” de forma a garantir a
disponibilidade da máquina na totalidade do tempo, já que a outra opção é que a máquina pode ser
desligada a qualquer altura; em contrapartida assumimos um gasto superior.

Política de execução de tarefas

Dado que as execuções de algumas tarefas eram demoradas, resolvemos este problema com a utilização
da aplicação “SCREEN” que permite deixar as tarefas em modo background.

4
4. Fase Inicial

Na primeira fase do nosso trabalho fez-se uma análise do benchmark que está presente no repositório
do github, para a configuração das instâncias virtuais com o objetivo de descobrir o número ideal de
warehouses, visto que os outros parâmetros são escaláveis horizontalmente, de acordo com a imagem
seguinte.

Figura 1: Escalabilidade dos parâmetros do TPC-C


(Retirado do TPC Benchmark™ Standard Specification)

5
5. Análise do Benchmark

O nosso primeiro objetivo era encontrar uma configuração padrão para todo o projeto.

Este padrão deveria preencher a base de dados com um tamanho similar à quantidade de memória RAM.
Dado que construímos uma máquina com 3.6 GB RAM.

Na primeira fase fizermos evoluir o número de warehouses de 2 para 10 obtendo, assim, um tamanho
da base de dados de 1135 MB, concluindo que, por um warehouse, precisaríamos de 113,5 MB e, assim
sendo, para perfazer 3.6 GB seriam necessários 27 warehouses.

Figura 2: Modelo lógico do benchmark

6
6. Otimização dos parâmetros PostgreSQL

O objetivo desta fase passa por alterar alguns parâmetros do sistema, recorrendo às variáveis de
configuração do PostgreSQL para tentar aumentar a performance da execução do benchmark TPC-C.

A principal métrica de comparação usada nos vários testes realizados foi o throughput que traduz o
número de encomendas por minuto C (tpmC). Esta métrica também é denomina por “Business
Throughput”. Cada uma destas transações está sujeita aos atrasos temporais subjacentes.

Os parâmetros influenciadores do desempenho da base de dados são mais de trinta, embora os mais
preponderantes não sejam muito mais de dez. Estes afetam mais significativamente a performance do
SGBD e permitem “afinar” a forma como as respostas são dados. De entre os parâmetros mais
potenciadores de ajuste no sistema encontram-se os seguintes:

• shared buffers;
• effective cache size;
• work mem;
• maintenance work mem;
• default statistics target;
• random page cost;
• CPU tuple cost;
• CPU index tuple cost;
• CPU operator cost;
• memory allocation;
• CPU allocation.

Para os testes de “afinação” foram selecionados quatro parâmetros: work_mem, shared_buffers,


effetive_chache_size e maintenance_work_mem. No decurso dos testes foram registados os valores do
throughput, de tempo de resposta medido em segundos e taxa de queries canceladas, face à variação
destes quatro parâmetros.

CENÁRIO DOS TESTES


Tempo da simulação: 2minutos

Número de clientes usados: 270

Warehouses: 27

Breve descrição dos parâmetros selecionados

• Configuração work_mem

7
O work_mem especifica a quantidade de memória RAM que pode ser usada para operações internas
antes de serem gravadas para ficheiros temporários em disco.

O valor predefinido na configuração do PostgreSQL é de 4 MB.

Para qualquer valor mais alto testado, o grau de dispersão do gráfico correspondente ao tempo de
resposta aumentava consideravelmente. Regressamos ao valor por omissão inicial. Como existem
algumas queries complexas no teste do Benchmark decidimos testar como iria variar o tempo de
execução das mesmas.

O valor por omissão do parâmetro max_connections é de 100. O benchmark não utiliza mais do que 14
ligações em simultâneo, daí o valor ser reduzido para max_connections 15.

• Configuração shared_buffers

O parâmetro de configuração shared_buffers determina a quantidade de memória RAM dedicada ao


PostgreSQL, usada para armazenar dados enquanto executa as queries. Inicialmente, poderia prever-se
que quanto maior fosse a quantidade de memória dedicada, melhor seriam os resultados de
desempenho. É uma conclusão precipitada, pois o PostgreSQL utiliza esta memória para efetuar
operações e não para cache de disco. A documentação do PostgreSQL especifica que para um valor
razoável para o shared_buffers com tamanho de 1GB de RAM ou superior, seja usado ¼ do tamanho
disponível. No presente caso de teste, estavam disponíveis 3.6 GB de RAM, logo o valor aconselhado era
de 900 MB, apesar de valores acima de 40% do tamanho serem, provavelmente, menos eficazes, pois o
PostgreSQL conta também com a cache do sistema operativo.

• Configuração effective_cache_size

O effective_cache_size é definido como uma estimativa da quantidade de memória disponível para a


cache do disco. Este parâmetro é utilizado pelo PostgreSQL Query Planner para perceber que planos
pode utilizar, tendo em conta o espaço disponível em memória.

A documentação do PostgreSQL afirma que definir 50% da memória total do dispositivo será uma
configuração conservadora, e que 75% será uma configuração arrojada, mas compreensível e até, de
certa forma, tolerável.

Então, para a configuração deste benchmark utilizaram-se os seguintes valores: 2048MB e 4096MB.

Para a primeira experiência foram utilizados 2GB de RAM e concluiu-se que 50% da memória total
apresentava grande dispersão, como se pode observar na figura abaixo.

Assim sendo, com o aumento do effective_cache_size para 4GB de RAM obtivemos melhor desempenho.
Logo, regressamos à configuração original do benchmark, e sendo atribuídos 4GB de RAM.

8
• Configuração maintenance_work_mem

O parâmetro controla a quantidade de memória que é usada para operações relacionadas com outras
atividades distintas das queries, mas que, ao consumirem recursos do sistema, acabam por afetar
indiretamente o desempenho da base de dados. Este parâmetro está intimamente ligado a operações
de limpeza do sistema (parâmetro VACCUM), criação de índices, uso da instrução ALTER TABLE, adição
de chaves estrangeiras e outros. Por omissão, o seu valor é 64MB. Este parâmetro deve ser controlado
juntamente com o autovacuum_work_mem, uma vez que se o autovacuum executar com o número
máximo de “workers (autovacuum_max_workers)” e a memória para cada ”worker” não estiver definida,
corre-se o risco de alocar toda a memória a esta tarefa, reduzindo, assim, a performance. Com isto, a
memória para manutenção não deverá ser muito alta.

As tarefas que utilizam este tipo de memória apenas executam uma vez por sessão e, já que o servidor
não deverá ter muitas destas tarefas em execução simultânea, é aconselhado reservar para este
parâmetro um valor significativamente mais alto que o parâmetro work_mem.

O aumento da memória não só vai aumentar a performance das tarefas de limpeza, como também vai
melhor as operações de restauro dos dumps da base de dados.

Testes

1º Teste

CONFIGURAÇÕES
work_mem shared_buffers effective_cache_size maintenance_work_mem
4 MB 128 MB 4 GB 64 MB

RESPOSTA DO SISTEMA
throughput(tx/s) response_time(s) abort_rate
23.5854905148 0.00865712616822 0.0256118383608

9
Figure 1: Gráfico de desempenho da execução dos testes de carga

Figure 2: Registo do uso de memória quando da execução dos testes de carga

Figure 3: Taxa de utilização do disco aquando dos testes de carga

2º Teste

CONFIGURAÇÕES
work_mem shared_buffers effective_cache_size maintenance_work_mem
100 MB 128 MB 4 GB 64 MB

RESPOSTA DO SISTEMA
throughput(tx/s) response_time(s) abort_rate

10
24.0428535836 0.00764363845711 0.0219594594595

Com o aumento da quantidade de memória a ser usada, nota-se uma diminuição das escritas em disco.

3º Teste

work_mem shared_buffers effective_cache_size maintenance_work_mem


2000 MB 128 MB 4 GB 64 MB

RESPOSTA DO SISTEMA
throughput(tx/s) response_time(s) abort_rate
23.3609964353 0.00680759951749 0.0154394299287

11
Aumentando ainda mais a quantidade de memória a ser usada, nota-se mais vincadamente a
diminuição das escritas em disco.

4º Teste

work_mem shared_buffers effective_cache_size maintenance_work_mem


2000 MB 900 MB 4 GB 64 MB

RESPOSTA DO SISTEMA
throughput(tx/s) response_time(s) abort_rate

12
22.611812583 0.00511620977354 0.00297088532383

5º Teste

work_mem shared_buffers effective_cache_size maintenance_work_mem


4 MB 900 MB 4 GB 64 MB

RESPOSTA DO SISTEMA
throughput(tx/s) response_time(s) abort_rate
24.2885626246 0.0110912743972 0.00114678899083

6º Teste
13
work_mem shared_buffers effective_cache_size maintenance_work_mem
4 MB 16 MB 4 GB 64 MB

RESPOSTA DO SISTEMA
throughput(tx/s) response_time(s) abort_rate
23.7676422111 0.00913344988345 0.00174520069808

7º Teste

work_mem shared_buffers effective_cache_size maintenance_work_mem


4 MB 16 MB 2 GB 64 MB

RESPOSTA DO SISTEMA
throughput(tx/s) response_time(s) abort_rate
23.1604837057 0.00849085545723 0.000589622641509

14
8º Teste

maintenance_work_mem/
work_mem shared_buffers effective_cache_size
autovacuum_work_mem = -1
4 MB 16 MB 4 GB 1024 MB

RESPOSTA DO SISTEMA
throughput(tx/s) response_time(s) abort_rate
23.4043418715 0.00804345307068 0.00115740740741

9º Teste

work_mem shared_buffers effective_cache_size maintenance_work_mem

15
4 MB 128 MB 4 GB 1024 MB

RESPOSTA DO SISTEMA
throughput(tx/s) response_time(s) abort_rate
24.2206926871 0.00752524106636 0.000566893424036

Agora é possível comparar os resultados entre a configuração inicialmente usada, a predefinida no


PostgreSQL e a que conseguimos obter por alteração de alguns critérios. Conclui-se que as evoluções que
têm vindo a ocorrer com a alteração de certos parâmetros, têm feito evoluir positivamente o
desempenho do benchmark.

Apesar dos parâmetros terem voltado ao valor original, constatamos que o throughput aumentou de
23,5 para 24,2 e o tempo de resposta médio diminuiu, muito por culpa dos dados já existentes na cache.

16
7. Análise de desempenho queries analíticas

A secção seguinte retrata a análise às interrogações analíticas descritas nos anexos do enunciado, bem
como possíveis otimizações. Note-se que, possivelmente, algumas otimizações estarão aqui de forma
representativa e não como implementação.

Para visualização de planos de execução usou-se a ferramenta já existente no PostgreSQL “explain”.

Query A1.

Explain da Query A1 com o plano por omissão

Tivemos um tempo de execução de 29ms (0.9 planeamento) e um custo de 8624.

17
Explain da Query A1

ß1º Teste (Remoção de Hash Join)

Tivemos um tempo de execução de 28ms (1.4 planeamento) e um custo de 8912

2º Teste (Remoção do HashJoin)

Seguidamente removemos o Merge Join, resultando na alteração do plano para uma combinação de
Nested Loop e materialização.

18
Removemos o Gather Merge, resultando na sua substituição pelo Gather, com um aumento no custo.
Tentamos remover o IndexScan, resultando na sua substituição pelo BitMap Scan, que é mais lento e
custoso.

O melhor plano é o 1º, criado pelo PostgreSQL.

19
Query A2

1º Teste (Sem restrições)

Tivemos um tempo de 916 ms (0.3 planeamento) e um custo de 48986.

A árvore começa por um Sort, seguido de um Group Aggregate, um Sort e um Hash Join.

Aqui separa-se em 2 ramos, um com um Sequencial Scan, outro com um Hash e Sequencial Scan.

20
2º Teste (Sem Hash Join)

Tivemos um tempo de 851ms (0.3 planeamento) e um custo de 50297.

O Hash Join foi substituído pelo Merge Join, que é mais rápido, sem a necessidade de construir a Hash
Table.

Além disso, os SequencialScans foram substituídos por IndexScans (exceto o último que é obrigatório),
sendo estes mais rápidos, mas mais custosos.

A substituição deve-se ao facto do Merge Join usar tabelas ordenadas.

3º Teste (Sem IndexScan)

Tivemos um tempo de 935ms (0.3 planeamento) e um custo de 67238.


21
Os Index Scans foram substituídos pela junção do Sort com o SequencialScan, sendo estes, juntos, mais
lentos e de maior custo.

A inserção do Sort deve-se ao facto do Merge Join usar tabelas ordenadas, que o Sequencial Scan não
faz.

4º Teste (Sem Merge Join)

Tivemos um tempo de 890ms (0.3 planeamento) e um custo de 65822.

O Merge Join foi substituído pela junção de Gather e Nested Loop, obrigando a substituição do primeiro
Index Scan pelo Parallel Seq Scan.

Se o tempo de execução for mais relevante que o custo, o segundo plano é o melhor, senão é o primeiro.

Em conclusão o melhor plano é executado sem hashJoin.

22
Query A3

1º Teste (Sem restrições)

Tivemos um tempo de 139ms (6.3 planeamento) e um custo de 6763.

2º Teste (Sem Nested Loop)

Tivemos um tempo de 231ms (6.6 planeamento) e um custo de 29167.

Os Nested Loops foram substituídos por Hash Joins, o que implicou o acréscimo do plano Hash em vários
ramos e a substituição de Index Scans por Seq Scans, pois os SeqScan “custam” menos. Com os Hash Join
não há a necessidade de ordenar tabelas.

23
2º Teste (Sem Hash Join)

Tivemos um tempo de 431ms (6.0 planeamento) e um custo de 9147.

Houve a substituição do Group Aggregate por partes pelo Group Aggregate normal.

O primeiro Hash Join foi substituído pela combinação do Merge Join e o Sort, pois o Merge Join precisa
de tabelas ordenadas.

Os restantes Hash Joins foram substituídos por Nested Loops.

Nested Loop é melhor que o Merge quando o número de linhas a processar é pequeno.

3º Teste (Sem Index Scan)

Tivemos um tempo de 168ms (7.1 planeamento) e um custo de 11891.

Os Indexs Scans são substituídos pela junção de Bitmap Heap Scan e Bitmap Index Scan, que são mais
lentos e com maior custo.

O melhor plano é o primeiro, criado pelo PostgreSQL.

24
Query A4

1º Teste (Sem restrições)

Tivemos um tempo de 720ms (0.6 planeamento) e um custo de 159589.

2º Teste (Sem Hash Join)

Tivemos um tempo de 977ms (0.5 planeamento) e um custo de 171309.

A remoção do Hash Join implicou a alteração da árvore desde do Parallel Hash Join até ao nível mais
baixo.

Substitui-se o Parallel Hash Join pelo Nested Loop e os Hash Joins pela combinação de Merge Join e Sort,
mantendo os Seq Scans.

Conclusão: a melhor é a solução inicial.

25
8. Benchmark em Sistemas Distribuídos

Nesta última fase do trabalho pretende-se montar uma infraestrutura que esteja preparada para garantir
alta disponibilidade e redundância dos dados, em caso de falha, e ainda garantir um aumento da escala
relativamente à configuração ideal de referência obtida na primeira fase.

Como ponto de partida foi utilizada uma parte de infraestrutura da unidade curricular "Infraestrutura de
Centros de Dados".

A estrutura usada é constituída por duas camadas. A primeira camada contém um cluster que é
composto por duas máquinas (cl1 e cl2) e uma segunda camada denominada por storage com dois
DRBDs. O objetivo principal destes elementos é a execução dos serviços lógicos.

Assim sendo, o serviço lógico é constituído por IP, PostgreSQL e o Filesystem que se encontra nos drbds
e que é partilhado pelas máquinas do cluster. Elas dividem entre si as atividades de processamento e
executam o trabalho simultaneamente.

Quando um serviço falha numa máquina, é iniciado na outra; desta forma conseguirmos garantir alta
disponibilidade para o servidor de base de dados.

No que diz respeito à camada de Storage, ela é constituída por duas máquinas: drbd1 e drbd2, que
servem para escrever e ler os dados do benchmark, sendo percecionadas pela camada superior (Cluster)
como um disco único. Esta característica apresenta grandes vantagens, uma vez que permite o normal
funcionamento caso um dos discos seja corrompido ou, até mesmo, em caso de falhas físicas.

Esquema estrutural

Plataforma:

• DRBD com 2 discos de 20 GB


• 47 warehouses
• Tamanho da base de dados; 8,23 GB;

26
RESPOSTA DO SISTEMA
throughput(tx/s)
32.1354622354

27
9. Anexos

Script de carregamento da BD

#!/bin/bash

#------------------------------------------------------
sql_path="etc/sql/postgresql"
#------------------------------------------------------
error=false

if ! test -d "$sql_path" ; then


echo "O caminho especificado para os ficheiros SQL não existe"
error=true
else
db="tpcc"
user="abd"

declare -a sql_files

sql_files[1]="createtable.sql"
sql_files[2]="createindex.sql"
sql_files[3]="sequence.sql"
sql_files[4]="delivery01"
sql_files[5]="neworder01"
sql_files[6]="orderstatus01"
sql_files[7]="payment01"
sql_files[8]="stocklevel01"
# sql_files[9]="dropindex.sql"

for file in "${sql_files[@]}" ; do


sql_file="$sql_path/$file"
if ! test -f "$sql_file"; then
echo "$sql_file not exist"
error=true
fi
done

if ! $error ; then
dropdb -U abd tpcc >& /dev/null
createdb -U abd tpcc >& /dev/null
for file in "${sql_files[@]}" ; do

if psql -d $db -U $user -f "$sql_path/$file" >& /dev/null ; then


echo "OK ..... $file"
else
echo "FAIL ... $file"
error=true
fi
done
fi

fi
echo $error
if ! $error ; then
echo "[--- Data Structure created with success ---------------------]"
echo "[--- Loading data ...]"
./load.sh
else

echo "[Data Structure created with errors. Process has stopped]"


fi

28

Você também pode gostar