Vídeo da palestra NoSQL: onde, como e por quê? Cassandra e MongoDB.
Information technology and tangential subjects
Vídeo da palestra NoSQL: onde, como e por quê? Cassandra e MongoDB.
Segue material da apresentação que fiz no dia 10/11 no Seminário de Gerenciamento de Dados em Software Livre no SERPRO.
Visão geral sobre bancos de dados NoSQL e detalhes técnicos dos modelos de dados e arquiteturas das implementações Apache Cassandra e MongoDB.
SELECT nome, uf FROM municipios
WHERE busca @@ plainto_tsquery(simples('agua lindoia'));
curso=# SELECT nome, uf FROM municipios
curso-# WHERE busca @@ plainto_tsquery(simples('agua lindoia'))
nome | uf
------------------+----
Águas de Lindóia | SP
(1 registro)
INSERT INTO municipios (codigo, nome, uf) VALUES (100, 'Águas de Lindóia do Sul', 'RS');
curso=# SELECT nome, uf, busca FROM municipios WHERE codigo = 100; nome | uf | busca -------------------------+----+------- Águas de Lindóia do Sul | RS | (1 registro)
CREATE FUNCTION municipios_trigger() RETURNS trigger AS $$ begin new.busca := to_tsvector(simples(new.nome)); return new; end $$ LANGUAGE plpgsql;
CREATE TRIGGER municipios_tsupdate BEFORE INSERT OR UPDATE ON municipios FOR EACH ROW EXECUTE PROCEDURE municipios_trigger();
UPDATE municipios SET uf = uf WHERE codigo = 100;
curso=# SELECT nome, uf, busca FROM municipios WHERE codigo = 100; nome | uf | busca -------------------------+----+--------------------------- Águas de Lindóia do Sul | RS | 'agu':1 'lindo':3 'sul':5 (1 registro)
curso=# SELECT nome, uf FROM municipios
curso-# WHERE busca @@ plainto_tsquery(simples('agua lindoia'));
nome | uf
-------------------------+----
Águas de Lindóia do Sul | RS
Águas de Lindóia | SP
(2 registros)
UPDATE municipios SET nome = 'Águas Quentes do Sul' WHERE codigo = 100;
curso=# SELECT codigo, nome, uf FROM municipios
WHERE busca @@ plainto_tsquery(simples('agua quente'));
codigo | nome | uf
--------+----------------------+----
100 | Águas Quentes do Sul | RS
(1 registro)
Aplicações modernas provaram que bancos de dados do tipo NoSQL são inevitáveis para o sucesso e continuidade de empresas altamente dependentes da Internet. Vide exemplos como Google, Yahoo, Amazon, Twitter e Facebook.
Todavia, existem inúmeras soluções disponíveis e nenhum padrão sobre como manipular, trafegar ou consultar as informações contidas nos bancos NoSQL. Mesmo a classificação (ou melhor dizer, a taxonomia) dessa zoologia de novos bancos ainda está (perdoem-me o trocadilho!) nebulosa... Quem sabe futuramente tenhamos um ANSI-NoSQL...
O fato é que algumas dessas tecnologias provaram ser apenas estufas para o meio acadêmico, enquanto que outras chegaram a evoluir a ponto de serem aceitas por empresas que apostam no pioneirismo. Uma dessas tecnologias de sucesso foi o MongoDB.
Nesta apresentação são introduzidos conceitos como as Grandes Rupturas (IMS x RDBMS x NoSQL), o que é o MongoDB, o Modelo de Dados Orientado a Documentos, JSON e BSON, tipos de dados no MongoDB, operações (Insert, Update, Delete), Modificadores Atômicos, Linguagem de Consulta, Indexação, Agregação e Map/Reduce, Capped Collections, GridFS, Server-Side Scripting, Replicação (Master/Slave e Replica Sets), Arquitetura com Sharding, Auto-Sharding + Replicação e outras tecnologias e detalhes envolvidos no banco de dados MongoDB.



nome | uf
---------------------+----
Abadia de Goiás | GO
Abadia dos Dourados | MG
Abadiânia | GO
Abaeté | MG
Abaetetuba | PA
Abaiara | CE
Abaíra | BA
Abaré | BA
Abatiá | PR
Abdon Batista | SC
...
ALTER TABLE municipios ADD busca tsvector;
Table "public.municipios"
Column | Type | Modifiers
--------+-----------------------+-----------
nome | character varying(50) |
uf | character(2) |
busca | tsvector |
CREATE FUNCTION to_ascii(bytea, name) RETURNS text AS 'to_ascii_encname' LANGUAGE internal STRICT; CREATE FUNCTION simples(texto varchar) RETURNS varchar AS 'select lower(to_ascii(convert_to($1, ''latin1''), ''latin1''))' LANGUAGE sql IMMUTABLE STRICT;
brasil=# select simples('Pinhão com Açaí');
simples
----------------
pinhao com acai
(1 row)
brasil=# select to_tsvector(simples('Pinhão com Açaí'));
to_tsvector
-------------------
'aca':3 'pinha':1
(1 row)
UPDATE municipios SET busca = to_tsvector(simples(nome));
brasil=# select nome, uf from municipios
brasil=# where busca @@ plainto_tsquery(simples('sao mateus'));
nome | uf
------------------------+----
São Mateus | ES
São Mateus do Maranhão | MA
São Mateus do Sul | PR
(3 rows)
brasil=# explain select nome, uf from municipios
brasil=# where busca @@ plainto_tsquery(simples('sao mateus'));
QUERY PLAN
-------------------------------------------------------------
Seq Scan on municipios (cost=0.00..163.60 rows=6 width=16)
Filter: (busca @@ plainto_tsquery('sao mateus'::text))
(2 rows)
CREATE INDEX municipios_gidx ON municipios USING gin(busca);
brasil=# explain select nome, uf from municipios
brasil=# where busca @@ plainto_tsquery(simples('sao mateus'));
QUERY PLAN
------------------------------------------------------------------------------
Bitmap Heap Scan on municipios (cost=4.30..23.49 rows=6 width=16)
Recheck Cond: (busca @@ plainto_tsquery('sao mateus'::text))
-> Bitmap Index Scan on municipios_gidx (cost=0.00..4.30 rows=6 width=0)
Index Cond: (busca @@ plainto_tsquery('sao mateus'::text))
(4 rows)
Um termo recorrente quando se fala em computação em nuvem é a persistência dos dados em bancos do tipo NoSQL, ou seja, em uma forma não-relacional. Essa tecnologia não substitui os consolidados Sistemas Gerenciadores de Bancos de Dados Relacionais (SGBDRs), mas ao invés disso torna-se uma nova ferramenta disponível ao desenvolvedor.
Implantar uma aplicação na nuvem não significa que NoSQL será utilizada. Entretanto, as funcionalidades que essa tecnologia provê são altamente convergentes com as propostas da computação em nuvem: performance, escalabilidade horizontal, alta disponibilidade e flexibilidade.
Nesta apresentação são introduzidos conceitos como Computação em Nuvem, Persistência de Dados, Bancos de Dados Relacionais, o movimento NoSQL, o modelo de dados do Bigtable da Google, a arquitetura do Dynamo da Amazon e detalhes técnicos do Apache Cassandra.








































/opt/apache-cassandra-0.6.5/nodes
|
|-- node1
| |-- bin
| |-- conf
| |-- data
| |-- log
| `-- txs
|
|-- node2
| |-- bin
| |-- conf
| |-- data
| |-- log
| `-- txs
|
`-- node3
|-- bin
|-- conf
|-- data
|-- log
`-- txs
# ifconfig lo:2 127.0.0.2 up # ifconfig lo:3 127.0.0.3 up
$ ifconfig
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:30848 errors:0 dropped:0 overruns:0 frame:0
TX packets:30848 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:2946793 (2.9 MB) TX bytes:2946793 (2.9 MB)
lo:2 Link encap:Local Loopback
inet addr:127.0.0.2 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:16436 Metric:1
lo:3 Link encap:Local Loopback
inet addr:127.0.0.3 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:16436 Metric:1
/etc/hosts: 127.0.0.1 localhost node1 127.0.0.2 node2 127.0.0.3 node3
$ ping node2 PING node2 (127.0.0.2) 56(84) bytes of data. 64 bytes from node2 (127.0.0.2): icmp_seq=1 ttl=64 time=0.018 ms 64 bytes from node2 (127.0.0.2): icmp_seq=2 ttl=64 time=0.015 ms ^C --- node2 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 999ms rtt min/avg/max/mdev = 0.015/0.016/0.018/0.004 ms
$ cd /opt/apache-cassandra-0.6.5/ $ mkdir -p nodes/node1 $ cp -R bin/ conf/ nodes/node1/ $ cd nodes/node1
# Edit the next line to point to your logs directory log4j.appender.R.File=./log/system.log
<Keyspaces>
<Keyspace Name="Keyspace1">
...
<ReplicationFactor>2</ReplicationFactor>
...
</Keyspace>
<Keyspaces>
...
<CommitLogDirectory>./txs</CommitLogDirectory>
<DataFileDirectories>
<DataFileDirectory>./data</DataFileDirectory>
</DataFileDirectories>
...
<ListenAddress>node1</ListenAddress>
<StoragePort>7000</StoragePort>
...
<ThriftAddress></ThriftAddress>
<ThriftPort>9160</ThriftPort>
<ThriftFramedTransport>false</ThriftFramedTransport>
...
for jar in $cassandra_home/../../lib/*.jar; do
CLASSPATH=$CLASSPATH:$jar
done
$ cd /opt/apache-cassandra-0.6.5/nodes/ $ mkdir node2 node3 $ cp -R node1/* node2 $ cp -R node1/* node3
$ tree -L 2
.
|-- node1
| |-- bin
| `-- conf
|-- node2
| |-- bin
| `-- conf
`-- node3
|-- bin
`-- conf
<ListenAddress>node2</ListenAddress>
# Arguments to pass to the JVM
JVM_OPTS=" \
-ea \
-Xms1G \
-Xmx1G \
-XX:+UseParNewGC \
-XX:+UseConcMarkSweepGC \
-XX:+CMSParallelRemarkEnabled \
-XX:SurvivorRatio=8 \
-XX:MaxTenuringThreshold=1 \
-XX:+HeapDumpOnOutOfMemoryError \
-Dcom.sun.management.jmxremote.port=8082 \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.authenticate=false"
$ node1/bin/cassandra -f $ node2/bin/cassandra -f $ node3/bin/cassandra -f
$ netstat -lptn Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN - tcp6 0 0 127.0.0.3:9160 :::* LISTEN 8520/java tcp6 0 0 127.0.0.2:9160 :::* LISTEN 8424/java tcp6 0 0 127.0.0.1:9160 :::* LISTEN 8336/java tcp6 0 0 :::46954 :::* LISTEN 8424/java tcp6 0 0 :::53418 :::* LISTEN 8336/java tcp6 0 0 :::49035 :::* LISTEN 8520/java tcp6 0 0 :::80 :::* LISTEN - tcp6 0 0 :::42737 :::* LISTEN 8520/java tcp6 0 0 :::8081 :::* LISTEN 8336/java tcp6 0 0 :::8082 :::* LISTEN 8424/java tcp6 0 0 :::8083 :::* LISTEN 8520/java tcp6 0 0 :::60310 :::* LISTEN 8424/java tcp6 0 0 :::46167 :::* LISTEN 8336/java tcp6 0 0 ::1:631 :::* LISTEN - tcp6 0 0 127.0.0.3:7000 :::* LISTEN 8520/java tcp6 0 0 127.0.0.2:7000 :::* LISTEN 8424/java tcp6 0 0 127.0.0.1:7000 :::* LISTEN 8336/java
$ cd /opt/apache-cassandra-0.6.5/
$ ./bin/nodetool -h localhost -p 8081 ring
Address Status Load Range Ring
142865723918937898194528652808268231850
127.0.0.1 Up 3,1 KB 39461784941927371686416024510057184051 |<--|
127.0.0.3 Up 3,1 KB 54264004217607518447601711663387808864 | |
127.0.0.2 Up 2,68 KB 142865723918937898194528652808268231850 |-->|

$ ./bin/cassandra-cli --host node1 --port 9160 Connected to: "Test Cluster" on node1/9160 Welcome to cassandra CLI. cassandra> set Keyspace1.Standard1['rowkey']['column'] = 'value' Value inserted. cassandra> get Keyspace1.Standard1['rowkey']['column'] => (column=636f6c756d6e, value=value, timestamp=1285273581745000) cassandra> get Keyspace1.Standard1['rowkey'] => (column=636f6c756d6e, value=value, timestamp=1285273581745000) Returned 1 results. cassandra> del Keyspace1.Standard1['rowkey'] row removed.