Olá pessoal,
Estamos com um novo site e todo o conteúdo foi levado para lá.
Em breve este blog será desativado.
Visite: https://yadax.com.br
Bonacin Consultoria e Treinamentos
Olá pessoal,
Estamos com um novo site e todo o conteúdo foi levado para lá.
Em breve este blog será desativado.
Visite: https://yadax.com.br
Olá pessoal, tudo bem?
Tem alguns termos que a gente sempre escuta quando estamos falando de arquitetura do Cassandra, principalmente quando o assunto é particionar dados. Vou tentar explicar um pouquinho de alguns deles que influenciam neste particionamento.
Um cenário bastante comum é o que temos os dados distribuídos e replicados em DCs distintos, onde nem sempre a carga é exatamente igual em cada node.
Talvez você já deve ter ouvido falar que cada node é responsável por um determinado número de tokens e que de alguma forma isso influencia nesta distribuição.
A primeira pergunta que me surge é: vocês sabem exatamente onde estão e como seus dados são distribuídos em um cluster Cassandra?
Primeiramente, vamos falar dos tokens/vnodes e um pouco do período anterior a eles.
Nas primeiras versões do Cassandra (até a 1.2), você precisava calcular e indicar quais os tokens cada node possuía. Embora existam serviços na internet que ajudam nisso, era muito esforço manual.
Nas versões mais recentes, cada node pode ser responsável por mais de um token e todo o trabalho é feito automaticamente. Foi aí que surgiram os tais vnodes (virtual nodes – como se cada node no novo modelo tivesse vários nodes do formato antigo), quebrando esse paradigma de um token por node.
Quando um novo node é adicionado no cluster, durante o bootstrap, ele recebe uma quantidade de tokens (num_tokens) e em seguida recebe dos outros membros todo dado que ele será o novo responsável.
A próxima pergunta é: como a localização de cada dado está associado a estes tokens?
Tudo está baseado no nosso partition key, no ring e no algoritmo de particionamento (Partitioner).
Começando pelos Partitioners, ele é definido na criação do Cluster e não pode ser alterado. Entenda-os como uma forma de assegurar a distribuição determinística dos dados de entrada.
Até a mesma versão 1.2, o default era o RandomPartitioner, que já assegurava uma distribuição uniforme.
A partir da 1.2, surgiu com uma melhora significativa de performance, o Murmur3Partitioner, que usa a função MurmurHash para atribuir valores entre -2^63 to +2^63-1 para os dados da partition key. Se você não sabe o que é uma função Hash, vale a pena dar uma googlada.
De forma simplificada, o input para o partitioner é sua partition key, ele transforma este valor em um hash, e com este valor vai ser possível descobrir quem é o responsável por este dado, baseando-se nos tokens de cada node.
Para seguir, precisamos agora entender o conceito de ring, que é como cada token está associado a um determinado node.
Será mais fácil colocando a mão na massa. Criei um cluster com 4 nodes, divididos em 2 DCs. Para cada node, atribuí apenas 4 tokens para facilitar nossa análise.
É possível então verificar quais são os tokes que marcam o final do intervalo (range) e qual o node associado, e a isto damos o nome de ring.
Agora vamos para a criação da nossa keyspace e da nossa tabela.
CREATE KEYSPACE bonacs WITH replication = {'class':'NetworkTopologyStrategy', 'US-EAST-1A': 1, 'US-EAST-1B': 1};
CREATE TABLE users (
username int,
first_name text,
last_name text,
inicio_email text,
dominio_email text,
PRIMARY KEY (username)
);
Após a criação, vamos confirmar que ainda não há SSTable.
Talvez a forma mais direta de descobrir onde para onde o dado será enviado é através do comando nodetools getendpoints, informando a keyspace, a tabela e a partition key.
Veja:
Com isso, ele diz que o node 172.31.42.39 e o 172.31.18.33 vão recebê-lo. Vamos inserir, fazer um flush e conferir?
Vamos usar uma alternativa agora para descobrir para onde o dado deve ir. Primeiro precisamos verificar qual o token associado ao 6, usando a funcão token no cqlsh.
O valor retornado foi o +2705480034054113608. E onde ele se encaixa no nosso ring? Lembrando que o token associado no node marca a margem superior do range.
Na figura abaixo podemos ver que ele se encaixa no 172.31.18.33 e no 172.31.47.250.
E como ficaria o getendpoints?
Vamos confirmar com um novo insert e flush.
Por último, gostaria de chamar a atenção para o número de tokens por node. Uma baixa quantidade pode ocasionar um desbalanceamento na distribuição porque os tokens são gerados aleatoriamente e nem sempre os ranges não são do mesmo tamanho.
Veja como ficou nosso cluster após um insert uniformemente distribuído e repare que nosso ring não estava distribuído tão uniforme:
Então pense assim: ranges maiores recebem mais dados. Da mesma forma, espera-se que quanto mais tokens um node tenha, mais dados ele receba.
Era isso, gostou? Até a próxima.
Olá pessoal. Vamos falar de um tema importante hoje, um salva-vidas (ou emprego, pelo menos). 🙂
Cassandra é um dos banco de dados mais tolerantes a problemas de infraestrutura, não possui ponto único de falha. Se bem configurado, você pode perder um Datacenter inteiro e ele continua operando normalmente. O dado pode ser replicado para múltiplos nodes, em múltiplos DCs. Porém, esta alta disponibilidade (verdadeira, diga-se de passagem) às vezes nos induz a pensar que o backup é dispensável.
De fato, para a maioria dos problemas cotidianos (falha de discos/servers/rede) ele é sim redundante, mas para os casos abaixo vamos precisar.
Então, hoje vamos falar um pouco de como fazer backup e restore no Cassandra. Em termos de backup, o Cassandra não é tão avançado quanto um banco de dados relacionais. Ser um banco de dados distribuído traz mais desafios.
Nativamente o Cassandra nos permite fazer snapshots e é dele que vamos falar. Basicamente é um hardlink de todas as SSTables para o próprio diretório onde estão os dados. É uma característica dos hardlinks, como apontam para o mesmo inode, estarão no mesmo disco/volume.
Realizei uma pequena carga de dados, utilizando o cassandra-stress e tenho cerca de 20 MB de dados em cada node.
Vamos lá. Esta é a minha estrutura atual, tenho uma keyspace bonacs e uma tabela users:
├── bonacs
│ └── users-1d779980f30a11e8b44c6735184b4d84
│ ├── aa-5-bti-CompressionInfo.db
│ ├── aa-5-bti-Data.db
...
│ ├── aa-5-bti-TOC.txt
│ └── backups
Vou criar um snapshot em um dos nodes. Porém, lembre-se que para ter maior consistência (eventual), é necessário tirar snapshot simultaneamente em todos os nodes, via crontab ou um ssh em paralelo, por exemplo.
[cassandra@ip-172-31-19-113 bonacs]$ nodetool snapshot bonacs
Requested creating snapshot(s) for [bonacs] with snapshot name [1543419630027] and options {skipFlush=false}
Snapshot directory: 1543419630027
Antes de realizar o snapshot propriamente dito, o Cassandra faz um flush das MemTables para disco e então vemos que uma nova pasta foi criada, chamada snapshot.
└── users-1d779980f30a11e8b44c6735184b4d84
├── aa-5-bti-CompressionInfo.db
├── aa-5-bti-Data.db
...
├── aa-6-bti-TOC.txt
├── backups
└── snapshots
└── 1543419630027
├── aa-5-bti-CompressionInfo.db
├── aa-5-bti-Data.db
...
├── aa-6-bti-TOC.txt
├── manifest.json
└── schema.cql
Você pode confirmar que se tratam de um hardlink, apontando para o mesmo inode:
Vou criar os snapshots nos meus quatro nodes “simultaneamente” com 4 janelas do meu terminal.
Bom, esta é a parte fácil. Agora vamos ver como podemos restaurar nosso backup. Para isso vamos simular nosso desastre, com um truncate.
Vamos confirmar em todos os nodes:
Um importante detalhe é que o Cassandra só vai permitir voltar o backup se o schema existir (Keyspaces e tabelas), portanto você deve ter também o DDL que recria seu schema. Para nossa sorte, automaticamente ele guarda o DDL de criação das tabelas junto com os snapshots, mas nunca é demais você também ter o seu.
Agora que não temos mais nada na nossa tabela, vamos copiar nosso snapshot para seu caminho original. Vou colocar o caminho completo para maior clareza. E lembre-se de fazer o mesmo em todos os nodes.
[cassandra@ip-172-31-17-26 ~]$ cp /u00/cassandra/data/bonacs/users-1d779980f30a11e8b44c6735184b4d84/snapshots/1543437632011/aa-* /u00/cassandra/data/bonacs/users-1d779980f30a11e8b44c6735184b4d84
Feito isso, precisamos executar o comando abaixo também em todos os nodes.
$ nodetool refresh bonacs users
Após isso, nossos dados estarão lá novamente.
Para finalizar, podemos listar e eliminar nossos snapshots via nodetool. Faremos isso em todos os nodes. É possível eliminar um a um, informando o nome ou todos de uma vez.
Era isso, um passo a passo de como realizar um backup e um restore de forma simples no Cassandra. Espero que tenha ajudado.
Até a próxima. Dúvidas? Comente aí.
Abraço.
Olá Pessoal,
Vou escrever mais alguns artigos sobre Cassandra e preciso usar algumas simulações de carga. Por isso, vou começar com este artigo de como realizar um teste usando o cassandra-stress tool.
É uma ferramenta que já vem junto com as instalações Cassandra e é bastante útil no momento de calcular a capacidade do seu cluster. Ela é bastante customizável, o que faz que com seja possível reproduzir uma boa variedade de workloads e, com isso, tentar prever o impacto do GC (entre outras coisas) em seu ambiente bem como um tuning fino de sua JVM.
Vou deixar aqui registrado nosso cenário inicial, com as keyspaces abaixo. Caso queira reproduzi-lo, usamos o mesmo do artigo Deploy Cassandra AWS com Ansible.
O cassandra-stress vem com várias opções default, o que simplifica bastante nosso trabalho inicial. Assim, para um primeiro teste a gente pode tentar algo como:
E como resultado:
Um ponto interessante sobre a conexão é que ele usa o Cassandra Java Driver, que inicialmente bate no node que informamos, mas isto serve apenas para que a lista de nodes seja obtida. Uma vez obtida, as conexões são direcionadas para todos os nodes.
Podemos perceber a criação de uma keyspace chamada “keyspace1”, onde o cassandra-stress irá fazer suas operações.
Vamos descrever a keyspace:
cqlsh> describe keyspace1;
CREATE KEYSPACE keyspace1 WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'} AND durable_writes = true;
Vemos que o cenário não é exatamente o que precisamos, já que normalmente temos um cluster distribuído e podemos utilizar o NetworkTopology além de aumentar o fator de replicação. A pergunta é: Como podemos customizar o cassandra-stress? Na documentação você pode encontrar vários detalhes.
A opção que mais me agrada, é uma você pode customizar o teste para que seja semelhante a sua aplicação. Você define a keyspace, as tabelas, as queries, a proporção entre escrita e leitura e várias outras coisas.
Vou mudar um pouquinho nosso cenário inicial, agora usando GossipingPropertyFileSnitch simulando então dois DCs, um para cada AZ (A e B).
Com isso, vamos criar uma keyspace que tenha um fator de replicação 2 para cada DC. Porém, tudo será definido em um arquivo YAML
#
# Keyspace name and create CQL
#
keyspace: bonacs
keyspace_definition: |
CREATE KEYSPACE bonacs WITH replication = {'class':'NetworkTopologyStrategy', 'US-EAST-1A': 2, 'US-EAST-1B': 2};
#
# Table name and create CQL
#
table: users
table_definition: |
CREATE TABLE users (
username int,
first_name text,
last_name text,
inicio_email text,
dominio_email text,
PRIMARY KEY (username)
)
#
# Meta information for generating data
#
columnspec:
- name: username
size: fixed(10)
population: uniform(1..10M)
#
- name: first_name
size: uniform(10..20)
population: uniform(1..300)
#
- name: last_name
size: uniform(10..20)
population: uniform(1..2000)
#
- name: inicio_email
size: uniform(10..20)
population: uniform(1..10M)
#
- name: dominio_email
size: uniform(10..20)
population: uniform(1..10M)
#
# Specs for insert queries
#
insert:
partitions: fixed(1) # 1 partition per batch
batchtype: UNLOGGED # use unlogged batches
select: fixed(1)/1 # no chance of skipping a row when generating inserts
#
# Read queries to run against the schema
#
queries:
myuser:
cql: select * from users where username = ?
fields: samerow
As opções que temos agora: definir keyspaces e tabelas, como serão distribuídos/populados as colunas, quais as queries que teremos na aplicação. Feito isso, vamos colocar nosso teste para funcionar. Crie um arquivo stress.yml e execute o teste da seguinte forma:
cassandra-stress user profile=./stress.yml duration=60s 'ops(insert=1,myuser=3)' -node ip-172-31-31-193
O teste vai ficar rodando um tempo e você pode aproveitar para acompanhar com alguma de suas ferramentas de monitoração se o JMX estiver habilitado, como o OpsCenter ou um VisualVM. O VisualVM permite algumas informações básicas e tem essa cara.
Permitindo que seja analisado com detalhes CPU/Atividade do Garbage Collector e o tamanho da HEAP, por exemplo.
Bom, era isso. Você pode olhar a documentação para maiores detalhes de como distruir os dados em um range que faça mais sentido no seu cenário. Campos maiores, mais distribuídos, uniformemente ou normalmente (Sino) distribuídos.
Até a próxima. Dúvidas? Comente aí.
Olá pessoal,
Vou tirar as teias de aranha do blog e escrever sobre deploy semi-automatizado com Terraform e Ansible de um Cassandra na AWS.
Para deploy da infra, vou usar Terraform que é uma excelente ferramenta para isso. Não é o foco aqui, mas se desejarem mais detalhes, só dizer.
Para a instalação do Cassandra usarei o Ansible que também traz uma ótima forma de automatizar nosso trabalho de instalação de pacotes, ajustes no SO, criação de arquivos/diretórios, …
No cenário que vou testar, vou ignorar um pouco o lado AWS e focar no Cassandra.
Então vamos lá, para se usar o Terraform, vamos precisar de um ACCESS_KEY e SECRET_KEY com permissões para tal. Porém, sempre vale o alerta de segurança: Nunca os exponha (em blogs, github, …), pois com apenas esses dois segredinhos algum mal intensionado pode subir várias máquinas na sua conta ou destruir o que você já tem. Acredite, isso acontece nas melhores famílias e fica caro essa brincadeira!
Você vai precisar do terraform instalado na sua máquina.
$ terraform --version Terraform v0.11.10
Para não complicar muito, vou utilizar minha VPC default (e duas subnets públicas), mas também poderíamos com o Terraform subir toda um infra de rede. Em um cenário real, também seria uma boa prática utilizar o Cassandra em subnets privadas e um JumpHost para conseguir acessá-lo.
Para não ficarmos duplicando código, o Terraform nos permite usar módulos, que são análagos a uma função/método em uma linguagem de programação.
Centralizamos o código no módulo e só passamos os parâmetros que desejamos. O código completo está no github e vou pular detalhes.
Desta forma, deixamos flexível a escolha da AMI (imagem), do tipo (size) da instância, a KeyPair (chave SSH), SecurityGroups, a subnet, se devemos ou não associar um IP público e o nome da instância.
Por outro lado, fixamos algumas propriedades do root device.
Aplicando o terraform:
São dois conjuntos de spot instances, um para cada AZ:
Com isso já temos nossas 6 instances em duas AZs. Importante: para meu Ansible, vou utilizar os IPs públicos, pois ele está instalado no meu PC; para o Cassandra, serão utilizados os IPs privados, já que eles vão se conversar internamente, sem passar pela internet.
Avançando para o Ansible. Com o arquivo de hosts configurado, basta aplicar o playbook. Lembrando que você precisa conseguir fazer SSH direto para seus hosts.
Com o Cassandra instalado, precisamos startá-lo em todos os nodes. Precisamos iniciar por um seed e fazer sequencial node por node esperando concluir o bootstrap.
Como sou preguiçoso, vou fazer um outro playbook que faça isso por mim. Para cada start, haverá uma pausa de 1 min para que seja concluído o bootstrap.
Após alguns minutos, temos todos os nodes UPs. Perceba que cada AZ corresponde a um Rack, tudo isto tratado automaticamente pelo Ec2Snitch.
Após tudo pronto, basta destruir a brincadeira e desativar sua ACCESS_KEY se não for mais utilizar.
Os ajustes que você precisará fazer caso queira tentar (me chame caso tenha mais problemas) serão:
– Caso tenha problemas com o JDK (atualmente o 191 está disponível para download), precisa trocar a URL para uma correta.
– O arquivo de hosts do Ansible (com os IPs públicos se for a partir do seu PC ou IPs privados se for outra instance AWS)
– Última linha do cassandra.yaml, nos IPs dos seeds (IPs privados)
– Ajustar os parâmetros de acordo com sua conta AWS.
– Incluir um arquivo dse.repo na pasta de templates seguindo as instruções (como vai user/senha, não vou subir no git) –
https://docs.datastax.com/en/dse/5.1/dse-admin/datastax_enterprise/install/installRHELdse.html [datastax] name = DataStax Repo for DataStax Enterprise baseurl=https://DSA_profile_name:downloads_key@rpm.datastax.com/enterprise enabled=1 gpgcheck=0
Era isso, queria mostrar e compartilhar uma forma prática e rápida de ser fazer o deploy. Prometi no último DBA BR que iria compartilhar, aí está com alguns meses de atraso. 🙂
Github:
https://github.com/abonacin
Abraços
Olá Pessoal,
Vou falar mais um pouquinho sobre scala. A ideia aqui não é explorar o conceito de um condicional em si, estou supondo que tenha alguma experiência com alguma outra linguagem e expondo como funciona aqui.
Como em outras linguagens de programação, o scala também oferece uma estrutura condicional, que pode até ser bem parecido com o que você está acostumado.
scala> val tres = 3 tres: Int = 3 scala> val dois = 2 dois: Int = 2 scala> if (tres > dois) { | println("Três é maior que dois") | } Três é maior que dois scala> if (dois > tres) { | println("Dois é maior que três") | } else if (dois == tres) { | println("Dois é igual a três") | } else { | println("Dois é menor que três") | } Dois é menor que três
Além desta forma comum, temos o que é chamado de “ternancy operator”, que talvez você tenha visto em outras linguagens, como o Java. Se a condição for TRUE, retorna a, senão b.
variavel = (a < b) ? a : b;
No scala, a operação é um pouco mais simples e direta. É possível testar a condição com um IF explícito dentro da atribuição da variável.
scala> val maior = if (dois > tres) dois else tres maior: Int = 3
A sutileza que encontramos no scala, é que o statement IF/ELSE retorna um valor e por isso não precisamos do “ternancy operator”.
Por este motivo podemos utilizar esta expressão direto como retorno de uma função.
scala> def maior(a: Int, b: Int) = if (a > b) a else b maior: (a: Int, b: Int)Int scala> maior(4, 6) res28: Int = 6 scala> maior (6, 4) res29: Int = 6
Era só esta pincelada rápida.
Até a próxima.
Olá pessoal, vou continuar a saga com o Redshift.
Quando criamos um cluster Redshift, estes são os users default: rdsdb (interno da aws) e o que você escolheu durante a criação.
O database default (excluindo alguns internos do Redshift) é o que você escolheu durante a criação.
Conforme for necessário, podemos criar outros users e groups. Vamos criar alguns para ilustrar, começando por dois grupos: users e dbas.
Agora um user dentro do grupo users.
Podemos criar um user sem grupo e ao mesmo tempo já atribuir privilégios. Perceba que ao conceder o privilégio CREATEUSER o user fica como Super User, assim como o Master user do Cluster.
Podemos criar um novo schema para começarmos criar nossos objetos.
Também podemos conceder privilégios para groups.
Alterar a sequencia de schemas que users buscam por objetos, via alter user.
Naturalmente, podemos adicionar users a grupos.
Podemos criar outros DBs, com o limite de até 60 por cluster.
Enfim, podemos fazer bastante coisa! 🙂
Até a próxima.
Olá pessoal, como estão?
Vou escrever sobre como se conectar no Redshift que está numa subnet privada, usando o client SQLWorkbench. Tinha utilizado esta ferramenta em um dos treinamentos AWS que fiz e depois vi em algum post, então vou utilizá-la. 🙂
Você pode encontrá-la aqui: https://www.sql-workbench.eu. Você também vai precisar fazer o download do driver JDBC do Redshift (aqui).
Como a subnet é privada, não temos acesso direto a ela a partir de nosso PC. Precisamos fazer nosso Tunnel passar pelo bastion-host. Já falamos de algo parecido em outro artigo (AWS – Acessando serviços Web em Subnet Privadas), mas hoje vou falar de como fazer isso no Windows. A idéia é: vamos estabelecer um Tunnel e qualquer requisição a nossa própria máquina (localhost) vai passar por ele. Vai ficar mais claro com o exemplo, vamos lá.
Precisamos do ENDPOINT do Redshift, algo como bonacs-cluster.xxxxx.us-east-1.redshift.amazonaws.com:5439. Você pode encontrá-lo na console:
Com esse endpoint, vamos ao putty. Estou assumindo que você consegue se conectar ao bastion-host normalmente (se tiver dificuldades, comente que tento ajudar).
Procure a opção (1) Tunnel (Connection, SSH), preencha a (2) Sourte port com o valor de sua preferência (será a porta que o localhost estará escutando), o (3) Destination com o endpoint do Redshift e clique no botão (4) Add. Feito isso, acima irá aparecer a (5) config do seu Tunnel.
Agora precisamos voltar a opção Session, preencher com o IP do bastion-host e acessá-lo normalmente.
Uma vez que o acessamos, vamos para o SQLWorkbench.
O primeiro passo aqui é adicionar o driver do Redhift. Clique em baixo no botão Manage Drivers.
Escolha o Amazon Redshift a esquerda e clique no ícone a direita para fazer o import do JAR.
Agora é só testar e ver que sua conexão está funcionando. A URL que deve usar é algo parecido com: jdbc:redshift://localhost:5432/bonacsdb, lembrando que deve utilizar a porta que escolheu no putty e o nome do banco que utilizou na criação do cluster Redshift. Importante: Deixe marcado a opção Autocommit.
Com isso, podemos acessar nosso cluster a partir daí.
Até a proxima.
Olá Pessoal, estou voltando a publicar alguns rascunhos que tinha aqui de scala.
Você já deve ter cruzado em sua vida com funções/métodos que possuem parâmetros “default”. Eles também existem no Scala.
scala> def soma(n: Int = 1, m: Int = 2) = n + m soma: (n: Int, m: Int)Int
Usando os dois valores defaults.
scala> soma() res2: Int = 3
Agora só o segundo será o default.
scala> soma(2) res3: Int = 4
Sem usar default.
scala> soma(2, 3) res4: Int = 5
O Scala também apresenta um tipo de parâmetro/operação implícito. Algo como as conversões implícitas que vemos frequentemente.
A beleza aqui é poder construir seu próprio conversor ou passar parâmetros de forma implícita, com a instrução “implicit”. Veja este outro exemplo.
scala> def quadradoImplicito (implicit num: Int) = num * num quadradoImplicito: (implicit num: Int)Int
É possível usar normalmente, como estamos acostumados.
scala> quadradoImplicito(3) res0: Int = 9
Até agora funcionou exatemente como esperado. O que muda?
Vamos tentar chamar a função sem passar parâmetro.
scala> quadradoImplicito <console>:26: error: could not find implicit value for parameter num: Int quadradoImplicito ^
E por fim a mágica: vamos declarar um variável implícita do tipo que a função recebe. A função usará este valor como default.
scala> implicit val m = 5 m: Int = 5 scala> quadradoImplicito res2: Int = 25
Vejamos, por fim, como construir nosso próprio conversor implícito. Vamos imaginar um cenário em que passamos para nosso método “soma”, criado acima, duas listas:
scala> val myList1 = List(1, 2, 3) myList1: List[Int] = List(1, 2, 3) scala> val myList2 = List(4, 5) myList2: List[Int] = List(4, 5) scala> soma(myList1, myList2) <console>:30: error: type mismatch; found : List[Int] required: Int soma(myList1, myList2) ^ <console>:30: error: type mismatch; found : List[Int] required: Int soma(myList1, myList2) ^
Obviamente, o método não sabe o que fazer. Para este caso, criaremos um método implícito que converterá a List em Int.
scala> implicit def list2Int(lista: List[Int]): Int = lista.sum warning: there was one feature warning; re-run with -feature for details list2Int: (lista: List[Int])Int
Agora a sacada: desta forma, sempre que invocarmos um método que espera um Int e recebe uma List[Int], ele fará automagicamente a conversão transformando a lista em um inteiro (soma de seus elementos).
scala> soma(myList1, myList2) res1: Int = 15
O que achou? Interessante, não?
Até a proxima.
Olá pessoal,
Passamos um pouco pela arquitetura do Redshift em artigos recentes, e vimos que o Leader Node (LN) faz a ponte com os Clients. Ele pode distribuir queries para que sejam executadas nos Compute Nodes (CN) ou executar em si próprio.
Ele envia os SQLs para os CN sempre que fazem referência a tabelas que criamos (user tables) ou tables/views de sistema (com prefixo STL ou STV) e executa exclusivamente no LN aquelas que referenciam apenas as tabelas do catálogo (com prefixo PG) ou não referenciam tabelas.
Por conta desta estranha distribuição, algumas funções SQL rodam apenas nos LN (CURRENT_SCHEMA, CURRENT_SCHEMAS, HAS_DATABASE_PRIVILEGE, HAS_SCHEMA_PRIVILEGE e HAS_TABLE_PRIVILEGE) e não nos CN. O mesmo acontece no contrário, há funções SQL que só rodam quando executadas no CN (LISTAGG, MEDIAN, PERCENTILE_CONT, PERCENTILE_DISC e APPROXIMATE PERCENTILE_DISC).
Vamos ver alguns exemplos.
Uma query que não faz referência a tabelas executa no LN, portanto pode utilizar CURRENT_SCHEMA;
Uma query que faz referência ao catalogo (PG*), também executa no LN e pode chamar o CURRENT_SCHEMA;
Uma query que envolve dados de usuários, executa no CN e não pode utilizar o CURRENT_SCHEMA;
Erro: [Amazon] (500310) Invalid operation: Specified types or functions (one per INFO message) not supported on Redshift tables.
Uma query que faz referência a uma user table, pode usar MEDIAN.
Uma query que faz referência ao catalogo, não pode usar MEDIAN.
Erro: [Amazon] (500310) Invalid operation: One or more of the used functions must be applied on at least one user created tables.
Acho que já conseguimos ter uma ideia de como funciona, não?
Até a próxima.