1. MySQL
5.7
Mul,-‐Source
Replica,on
Wagner
Bianchi
–
Oracle
ACE
Director
Oracle
Open
World
2015
Edição
#
11
–
Ano
2015
2. Agenda
• MySQL
5.7
–
novidades
para
a
replicação;
• Apresentação
da
replicação
no
MySQL:
• Replicação
MulD-‐Source:
– Principais
caracterísDcas;
– ReplicaDon
Channels;
– Variáveis
de
Ambiente
– Deployment;
– Principais
Comandos;
– PERFORMANCE_SCHEMA
replicaDon_*;
– Considerações
finais.
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
3. MySQL
5.7
–
novidades
p/
replicação
• O
que
há
de
mais
relevante
na
nova
versão
com
relação
à
replicação
de
dados:
– MulD-‐source
ReplicaDon
baseada
em
ReplicaDon
Channels
(5.7.6);
– Filtros
de
replicação
via
comando
CHANGE REPLICATION FILTER (5.7.3);
– RBR/RBL
se
tornou
o
formato
padrão
do
log
binário
(5.7.7);
– Finalmente
slave_net_Dmeout
tem
seu
padrão
igual
a
60
secs;
– P_S
passa
a
exibir
informações
sobre
a
replicação
(5.7.2);
– Introdução
do
Replica(on
Mode:
• Transações
Anônimas
(file,
offset)
e
Transações
Globais;
• Convívio
dos
dois
protocolos
de
replicação
em
uma
mesma
topologia;
• Possibilita
o
rollout
da
replicação
baseada
em
nome
e
posição
do
log
binário
para
GTID
online;
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
4. MySQL
5.7
–
CHANGELOG
• Para
mais
informações,
acesse
os
CHANGELOG:
– hhp://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-‐5-‐7-‐2.html
– hhp://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-‐5-‐7-‐3.html
– hhp://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-‐5-‐7-‐4.html
– hhp://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-‐5-‐7-‐5.html
– hhp://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-‐5-‐7-‐6.html
– hhp://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-‐5-‐7-‐7.html
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
6. Replicação
MySQL
(big
picture)
• Conceito
de
servidores
MASTER
e
SLAVE;
• Escritas
no
MASTER,
leituras
no
SLAVE;
• Tanto
MASTER
quanto
SLAVE
são
instâncias
de
MySQL;
• Relação:
1
Master
-‐>
N
Slaves
/
1
Slave
-‐>
1
Master
*
• Cada
instância
parDcipante
da
topologia:
server_id
único;
• Obrigatoriamente,
logs
binários
habilitados
no
MASTER;
• Um
usuário
deve
ser
criado
no
MASTER
para
o
SLAVE;
• O
SLAVE
copia
o
log
binário
para
o
relay
log
e
aplica
atualizações.
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
*
Relação
existente
até
o
advento
da
replicação
mul(-‐source
7. Replicação
MySQL
(caracterís.cas)
• A
replicação
no
MySQL
pode
ser:
– Assíncrona,
baseada
no
nome
do
log
binário
e
a
posição
do
mesmo;
– Assíncrona,
baseado
em
Transações
Globais
(GTID);
– Semi-‐síncrona,
através
de
plugins
e
via
ack
de
uma
dos
SLAVEs;
– Síncrona,
através
do
MySQL
Cluster;
– Virtualmente
síncrona,
através
do
Galera
Cluster
(WSRep
API);
• A
replicação
MulD-‐Source
uDliza
o
modelo
assíncrono:
– baseada
no
nome
do
log
binário
e
a
posição
do
mesmo;
– baseado
em
Transações
Globais
(GTID);
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
8. Replicação
MySQL
(implementação)
Configurações
my.cnf
• No
servidor
SLAVE:
CHANGE
MASTER
TO
(Slaves)
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
[mysqld]
#: todos os servers
server_id=1
gtid_mode=on
log_bin=mysql01-bin
log_slave_updates=true
binlog_format=ROW # default 5.7.6
enforce_gtid_consistency=true
#
report_host=oowmysql01.wb.com
report_port=3306
mysql slave> CHANGE MASTER TO
MASTER_HOST=‘192.168.0.100’,
MASTER_BIND=‘eth0’,
MASTER_PORT=3306,
MASTER_USER=‘wb_rpl’;
MASTER_PASSWORD=‘ooWlad15’,
MASTER_HEARTBEAT_PERIOD=5,
MASTER_AUTO_POSITION=1;
mysql slave> START SLAVE;
mysql slave> SHOW STATUS LIKE ‘Slave_%’;
9. Log
binário
/
Relay
log
• Log
binário
(MASTER):
– Log
para
registro
de
atualizações;
– ADvado
com
a
variável
log-‐bin=/local/meulog-‐bin;
– Possui
os
formatos
SBR
(SQL)
e
RBR
(eventos),
RBR
o
padrão
5.7.7
++;
• binlog_format=ROW|STATEMENT|MIXED
– A
variável
expire_logs_days
remove
logs
mais
velhos
que
X
dias.
• Relay
log
(SLAVE):
– Log
para
armazenamento
das
atualizações
copiadas
do
MASTER;
– Acompanha
o
formato
de
log
binário,
sendo
uma
cópia
deste
úlDmo;
– É
lido
pela
Slave
SQL
Thread
para
atualizar
o
SLAVE;
– relay_log_purge
habilita
a
remoção
de
logs
não
mais
uDlizados.
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
10. Replicação
MySQL
(implementação)
• A
configuração
da
replicação
é
realizada
através
do
comando
CHANGE
MASTER
TO
(comando
básico):
– MASTER_HOST:
IP/DNS
do
MASTER;
– MASTER_BIND:
a
interface
uDlizada
pela
replicação;
– MASTER_USER:
usuário
que
criamos
no
MASTER
para
os
SLAVEs;
– MASTER_PASSWORD:
senha
do
usuário
acima
citado;
– MASTER_PORT:
porta
onde
roda
o
listener
do
MySQL;
-- baseada no nome do log binário e a posição do mesmo
– MASTER_LOG_POS:
posição
do
log
binário
para
início
da
leitura;
– MASTER_LOG_FILE:
nome
do
arquivo
de
log
binário
no
MASTER;
-- replicação GTID (Global Transaction Identifiers)
– MASTER_AUTO_POSITION:
“Mr. Master, where are we? - Slave.”
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
11. Replicação
MySQL
(implementação)
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
Servidor MASTER
IP: 192.168.0.100
Usuário: wb_rpl:ooWlad15
Servidor SLAVE01
IP: 192.168.0.101
Usuário: wb_rpl:ooWlad15
Servidor SLAVE02
IP: 192.168.0.102
Usuário: wb_rpl:ooWlad15
Master’s
Binlog
Dump
Thread
Slave’s
I/O
Thread
Binary
Log
-‐
Os
SLAVEs
se
conectam
ao
MASTER
-‐
Os
SLAVEs
copiam
o
log
binário,
relay-‐log
-‐
A
Slave
SQL
Thread
executa
as
atualizações
Slave
SQL
Thread
Slave
SQL
Thread
Relay
Log
Relay
Log
12. Replicação
MySQL
(implementação)
• São
criadas
três
threads
após
o
comando
START
SLAVE:
– Binlog
Dump
Thread
(MASTER):
responsável
por
ler
do
log
binário
local
todos
os
eventos
que
estão
para
ser
enviados
para
o
SLAVE
quando
este
se
conectar
– Slave
I/O
Thread:
essa
thread
conversa
direto
com
aquela
existente
no
MASTER,
solicitando
os
eventos
de
atualização
e
os
copia
para
o
relay
log
local,
este
que
é
uma
cópia
do
log
binário
do
MASTER.
– Slave
SQL
Thread:
executa
as
atualizações
depositadas
no
relay
log
para
manter
o
SLAVE
atualizado
em
relação
ao
MASTER.
Desde
o
MySQL
5.6,
pode
contar
com
até
1024
sub-‐threads
para
execução
dos
trabalhos
(slave_parallel_workers).
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
13. Replicação
MySQL
(monitoramento)
• Comandos
para
monitoramento
da
replicação:
– SHOW SLAVE STATUS:
exibe
todas
as
informações
de
replicação;
– SHOW SLAVE HOSTS:
exibe
os
hosts
conectados
ao
MASTER;
– SHOW PROCESSLIST:
exibe
conexões
e
threads
da
replicação;
– SHOW MASTER STATUS:
exibe
o
arquivo
de
log
binário
sendo
uDlizado
atualmente
pelo
MASTER,
assim
como
a
posição
atual;
• Variáveis
de
status:
– SHOW STATUS LIKE ‘Slave_running’;
• Exibe
se
um
SLAVE
está
replicando
ou
não
através
de
valores
ON | OFF.
• Considera
o
funcionamento
da
duas
threads
disponíveis
no
SLAVE.
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
15. Principais
caracterís,cas
• Resolve
o
problema:
1
SLAVE
-‐>
N
MASTER
/
N
SLAVE
-‐>
N
MASTER;
• Cria
estruturas
em
disco
para
acomodar
SLAVEs
por
canal;
• Replicação
baseada
em
Transações
Anônimas
e/ou
GTID;
• Possibilita
centralizar
dados
de
vários
servidores;
• Possibilidade
de
criação
de
até
256
canais
de
replicação
por
MySQL;
• Pode
ser
uDlizado
com
replicação
clássica
ou
GTID;
• Não
possui
nenhum
controle
de
conflito
em
dados
auto_increment;
• Crash-‐safe
Replica(on
é
mandatório
para
SLAVEs.
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
16. Variáveis
de
Ambiente
• Configuração
de
repositórios
(my.cnf)
– master_info_repository=TABLE
– relay_log_info_repository=TABLE
• Dinamicamente:
– SET GLOBAL master_info_repository=TABLE;
– SET GLOBAL relay_log_info_repository=TABLE;
• Iniciando
o
mysqld
--master_info_repository=TABLE --relay_log_info_repository=TABLE
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
17. Replica,on
Channels
• CHANGE MASTER TO ... FOR CHANNEL ‘channel_name’;
– Declaração
adicionada
ao
comando
CHANGE MASTER TO;
– Possibilita
dar
um
nome
aos
canais,
parar
e
iniciá-‐los;
– Cada
canal
tem
sua
própria
estrutura
de
relay-‐logs;
• Criados
em
disco
hostname-relay-channel_name.xxxxxx
– Não
segue
uma
conversão
de
nomeação,
contudo,
nomes
reservados:
• group_replication_applier
• group_replication_recovery;
– Canal
Padrão
para
manter
retro
compaDbilidade
(“”);
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
18. Replica,on
Channels
Configuração
my.cnf
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
[mysqld]
#: all servers
server_id=1
gtid_mode=on
binlog_format=ROW # default 5.7.6
log_bin=mysql01-bin
log_slave_updates=true
enforce_gtid_consistency=true
master_info_repository=TABLE
relay_log_info_repository=TABLE
relay_log_recovery=1
#: ai conflicts
auto_increment_increment=3
auto_increment_offset=1
#: host infos on replication
report_host=oowmysql01.wb.com
report_port=3306
CHANGE
MASTER
TO
(Slaves)
mysql oowmysql03> CHANGE MASTER TO
MASTER_HOST=‘192.168.0.100’,
MASTER_BIND=‘eth0’,
MASTER_PORT=3306,
MASTER_USER=‘wb_rpl’;
MASTER_PASSWORD=‘ooWlad15’,
MASTER_HEARTBEAT_PERIOD=5,
MASTER_AUTO_POSITION=1
FOR CHANNEL ‘oowmysql01’; # the channel name!
mysql oowmysql03> START SLAVE FOR CHANEL ‘OOWMYSQL01’;
20. Deployment
• Com
base
na
definição
de
topologia
anterior:
– MASTER01
• CHANGE MASTER TO MASTER_HOST=‘192.168.0.101’... FOR CHANNEL ‘oowmysql01-2’;
• CHANGE MASTER TO MASTER_HOST=‘192.168.0.102’... FOR CHANNEL ‘oowmysql01-3’;
– MASTER02
• CHANGE MASTER TO MASTER_HOST=‘192.168.0.100’... FOR CHANNEL ‘oowmysql02-1’;
• CHANGE MASTER TO MASTER_HOST=‘192.168.0.102’... FOR CHANNEL ‘oowmysql02-3’;
– SLAVE01
• CHANGE MASTER TO MASTER_HOST=‘192.168.0.100’... FOR CHANNEL ‘oowmysql03-1’;
• CHANGE MASTER TO MASTER_HOST=‘192.168.0.101’... FOR CHANNEL ‘oowmysql03-2’;
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
21. Deployment
• Com
as
configurações
criadas:
– START SLAVE iniciará
a
a
replicação
de
todos
os
canais;
– START SLAVE FOR CHANNEL ‘oowmysql1-2’
inicia
a
replicação
do
MASTER01
com
o
MASTER02,
quando
oowmysql01
é
SLAVE
do
oowmysql02;
– SHOW SLAVE STATUS exibirá
o
status
de
todos
os
canais;
– SHOW SLAVE STATUS FOR CHANNEL ‘oowmysql1-2’ exibe
as
informações
de
status
deste
canal
específico;
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
22. Principais
Comandos
• Todos
os
comandos
Dveram
adição
FOR
CHANNEL
‘channel_name’
– SHOW SLAE STATUS FOR CHANNEL ‘channel_name’;
– START SLAVE [IO_THREAD|SQL_THREAD] FOR CHANNEL ‘channel_name’;
– STOP SLAVE [IO_THREAD|SQL_THREAD] FOR CHANNEL ‘channel_name’;
– SHOW RELAY LOGS FOR CHANNEL ‘channel_name’;
– SHOW RELAYLOG EVENTS FOR CHANNEL ‘channel_name’;
– RESET SLAVE [ALL] FOR CHANNEL ‘channel_name’;
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
23. PERFORMANCE_SCHEMA
• A
parDr
do
MySQL
5.7.2,
tabelas
replicaDon_*
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
mysql oowmysql01> show tables from performance_schema like 'replication%';
+---------------------------------------------+
| Tables_in_performance_schema (replication%) |
+---------------------------------------------+
| replication_applier_configuration |
| replication_applier_status |
| replication_applier_status_by_coordinator |
| replication_applier_status_by_worker |
| replication_connection_configuration |
| replication_connection_status |
| replication_group_member_stats |
| replication_group_members |
+---------------------------------------------+
8 rows in set (0.00 sec)
24. PERFORMANCE_SCHEMA
• Monitorar
o
estado
dos
canais:
• Monitorar
o
conjunto
de
transações
já
recebidas:
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
mysql oowmysql01> SELECT CHANNEL_NAME, SOURCE_UUID, SERVICE_STATE
> FROM performance_schema.replication_connection_status;
+--------------+--------------------------------------+---------------+
| CHANNEL_NAME | SOURCE_UUID | SERVICE_STATE |
+--------------+--------------------------------------+---------------+
| oowmysql01-2 | 7353cfa9-0d77-11e5-a369-0800274fb806 | ON |
| oowmysql01-3 | d9a28f1e-0d77-11e5-a375-0800274fb806 | ON |
+--------------+--------------------------------------+---------------+
2 rows in set (0.00 sec)
mysql oowmysql01> SELECT CHANNEL_NAME, SERVICE_STATE, RECEIVED_TRANSACTION_SET
> FROM performance_schema.replication_connection_statusG
*************************** 1. row ***************************
CHANNEL_NAME: oowmysql01-2
SERVICE_STATE: ON
RECEIVED_TRANSACTION_SET: 7353cfa9-0d77-11e5-a369-0800274fb806:1-2
*************************** 2. row ***************************
CHANNEL_NAME: oowmysql01-3
SERVICE_STATE: ON
RECEIVED_TRANSACTION_SET: 7353cfa9-0d77-11e5-a369-0800274fb806:1-2
2 rows in set (0.00 sec)
25. PERFORMANCE_SCHEMA
• Configurando
SLAVE
com
múlDplas
SQL_THREADS;
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
#: configurando o multi-threaded slave
mysql oowmysql01> STOP SLAVE; # para todas as threads de todos os canais
Query OK, 0 rows affected (0.00 sec)
mysql oowmysql01> SET GLOBAL slave_parallel_workers=16; # qtd e threads para execução do relay log
Query OK, 0 rows affected (0.00 sec)
mysql oowmysql01> SET GLOBAL slave_parallel_type=LOGICAL_CLOCK # threads trabalhando independente de schema
Query OK, 0 rows affected (0.00 sec)
#: verificação de configuração e iniciando os canais de replicação novamente
mysql oowmysql01> SELECT @@slave_parallel_workers, @@slave_parallel_type;
+--------------------------+-----------------------+
| @@slave_parallel_workers | @@slave_parallel_type |
+--------------------------+-----------------------+
| 16 | LOGICAL_CLOCK |
+--------------------------+-----------------------+
1 row in set (0.00 sec)
mysql oowmysql01> START SLAVE; # inicia as threads de todos os canais
Query OK, 0 rows affected (0.00 sec)
26. PERFORMANCE_SCHEMA
• Verificando
Coordinators
(1
para
cada
canal):
• Após
um
load
em
qualquer
servidor
da
topologia:
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
mysql oowmysql01> select * from performance_schema.replication_applier_status_by_coordinator;
+--------------+-----------+---------------+-------------------+--------------------+----------------------+
| CHANNEL_NAME | THREAD_ID | SERVICE_STATE | LAST_ERROR_NUMBER | LAST_ERROR_MESSAGE | LAST_ERROR_TIMESTAMP |
+--------------+-----------+---------------+-------------------+--------------------+----------------------+
| oowmysql01-2 | 9301 | ON | 0 | | 0000-00-00 00:00:00 |
| oowmysql01-3 | 9319 | ON | 0 | | 0000-00-00 00:00:00 |
+--------------+-----------+---------------+-------------------+--------------------+----------------------+
2 rows in set (0.02 sec)
mysql oowmysql01> SELECT CHANNEL_NAME, WORKER_ID, THREAD_ID, SERVICE_STATE, LAST_SEEN_TRANSACTION
> FROM performance_schema.replication_applier_status_by_worker WHERE LAST_SEEN_TRANSACTION <> '';
+--------------+-----------+-----------+---------------+---------------------------------------------+
| CHANNEL_NAME | WORKER_ID | THREAD_ID | SERVICE_STATE | LAST_SEEN_TRANSACTION |
+--------------+-----------+-----------+---------------+---------------------------------------------+
| oowmysql01-2 | 1 | 9302 | ON | 7353cfa9-0d77-11e5-a369-0800274fb806:246601 |
| oowmysql01-2 | 2 | 9303 | ON | 7353cfa9-0d77-11e5-a369-0800274fb806:246586 |
[…snip…]
| oowmysql01-2 | 15 | 9316 | ON | 7353cfa9-0d77-11e5-a369-0800274fb806:246599 |
| oowmysql01-2 | 16 | 9317 | ON | 7353cfa9-0d77-11e5-a369-0800274fb806:246600 |
+--------------+-----------+-----------+---------------+---------------------------------------------+
19 rows in set (0.00 sec)
27. Filtros
de
Replicação
• Até
a
versão
5.7.2
--replicate-do-db
--replicate-ignore-db
--replicate-do-table
--replicate-ignore-table
--replicate-wild-do-table
--replicate-wild-ignore-table
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
28. Filtros
de
Replicação
• A
parDr
do
MySQL
5.7.3
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
mysql oowmysql01> STOP SLAVE;
Query OK, 0 rows affected (0.16 sec)
mysql oowmysql01> CHANGE REPLICATION FILTER REPLICATE_IGNORE_DB=(oowdb);
Query OK, 0 rows affected (0.00 sec)
mysql oowmysql01> START SLAVE;
Query OK, 0 rows affected (0.15 sec)
mysql oowmysql03> create table t04(i int);
Query OK, 0 rows affected (0.05 sec)
mysql oowmysql01> show create table t04;
ERROR 1146 (42S02): Table 'oowdb.t04' doesn't exist
29. Filtros
de
Replicação
• Outros
exemplos
de
sintaxe
do
comando:
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
#: necessário parar os canais antes de alterar os filtros
mysql wbsrv01> STOP SLAVE;
#: possível comandos e declarações
mysql wbsrv01> CHANGE REPLICATION FILTER REPLICATION_DO_DB=(oowdb,mysql), REPLICATION_IGNORE_DB(test);
#
mysql wbsrv01> CHANGE REPLICATION FILTER REPLICATE_WILD_IGNORE_TABLE=(‘oowdb.hist_%’,’test.tb_%’);
#
mysql wbsrv01> CHANGE REPLICATION FILTER REWRITE_DB((dbA,dbB), (dbC,dbD));
#
#: para limpar as regras criadas
mysql wbsrv01> CHANGE REPLICATION FILTER REPLICATE_DO_DB=(), REPLICATE_IGNORE_DB();
30. Considerações
finais
• A
replicação
MulD-‐Source
mudou
o
jogo:
– Tornou
o
modelo
de
replicação
mais
flexível;
– Deu
agilidade
na
linha
de
raciocínio
de
novas
arquiteturas;
– Agregou
valor
no
tocante
a
termos
so•ware
mais
escaláveis;
– Aumentou
a
disponibilidade
da
informação;
– Abriu
caminho
para
o
surgimento
do
MySQL
Group
Replica,on!!
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
mysql oowmysql01> SELECT CHANNEL_NAME, GROUP_NAME FROM performance_schema.replication_connection_statusG
*************************** 1. row ***************************
CHANNEL_NAME: oowmysql01-2
GROUP_NAME:
*************************** 2. row ***************************
CHANNEL_NAME: oowmysql01-3
GROUP_NAME:
2 rows in set (0.00 sec)
31. Ques,ons?
Wagner
Bianchi,
Oracle
ACE
Director
–
me@wagnerbianchi.com
Wagner
Bianchi
é
Oracle
ACE
Director,
com
cerDficações:
• MySQL
CerDfied
Database
Cluster
Administrator
• MySQL
CerDfied
Database
Administrator
• MySQL
CerDfied
Developer
Formando
em
Gerenciamento
de
Bancos
de
Dados,
com
Pós-‐Graduação
em
Administração
de
Empresas
pela
FGV
e
MBA
em
Gerenciamento
de
Bancos
de
Dados
Oracle.
Blog:
wagnerbianchi.com
E-‐mail:
me@wagnerbianchi.com