Friday, August 02, 2013

SQLHOSTS options / Opções do SQLHOSTS

This article is written in English and Portuguese (full post here!)
Este artigo está escrito em Inglês e Português (artigo completo aqui!)

English version:
Recently I've been asked to setup some connection redirection for Informix clusters. In most situations we'll want to use the connection manager, but in this post I'm not going that deep. I'll just review something that is also related to the use of connection manager, but that has a lot more uses and that I've found many customers are not aware. I'm referring to the INFORMIXSQLHOSTS file options field. You can find the full documentation here in the InfoCenter. I'll just make some remarks about several options that can be extremely useful, and many people never thought about using.

  • r option (0|1)
    Only used on the client side. If it's set to 1, the client will look for .netrc file in the user's home directory that allows you to specify a user and password to connect to the database server
  • s option (0,1,2,3|4|6)
    Controls server side security settings. Check the documentation for full details, but:
    • 0 disables checking /etc/hosts.equiv and ~user/.rhosts (or their equivalents defined in REMOTE_SERVER_CFG and REMOTE_USER_CFG parameters)
    • 1 activates the central trust file (/etc/hosts.equiv or it's replacement REMOTE_SERVER_CFG) and deactivates the individual user file (~user/.rhosts or it's replacement defined in REMOTE_USER_CFG parameter)
    • 2 opposite of 1
    • 3 activates both files
    • 4 for PAM enabled ports
    • 6 restricts the port for replication connections only (HDR, RSS and ER)
  • k option (0|1)
    Activates (1) the TCP functionality of keep alive. Note that the keep alive interval, timeout and retries must be setup at the OS level. This can be very important when there are firewalls between the clients and the servers. In some cases, if the functionality is not activated (which can be controlled at the OS level), the firewalls may break the connection and an idle client will receive an error when it attempts to send a query after a long period of inactivity
As you can see on the documentation there are many more. But for the purpose of this post, I'm particularly interested in the group related options. The concept of groups was created for Enterprise Replication many years ago but we can use them for other purposes. Let's first see how to create a group:

my_group group - - i=100,c=0
my_server_1 onsoctcp my_hostname_1 1526 k=1,g=my_group
my_server_2 onsoctcp my_hostname_2 1526 k=1,g=my_group

So, here I have a group called "my_group", defined because I've use "group" in the protocol field. I don't use the hostname and service name or port (so I replace them with a "-") and I use two options:
  • i=100
    This is just a group id.We can use any unique number for each group
  • c=0
    This controls the way the clients trying to access INFORMIXSERVER=my_group handle the several servers in the group. This option can be setup to "0" or "1":
    • 0 means that it will always try to connect to the first server, and if it's not available it will try the second one and so on
    • 1 means it will randomly choose one of the servers that belong to the group and start trying from there until it finds one server available
Now, how is this useful? I'll give you two usage scenarios. First one is a cluster with primary server, an HDR server and an RSS server. Both secondary nodes are in read-only mode, we don't plan to change the roles between the servers, and naturally the chances that the HDR is more up to date than the RSS is higher. In this case we may want to redirect read-only clients preferably to the HDR instance, but in case of failure or planned maintenance we want the clients to be shifted to the RSS server. The following INFORMIXSQLHOSTS will do the trick:

my_read_only_group group - - i=100,c=0
my_hdr_instance onsoctcp my_hdr_host 1526 k=1,g=my_read_only_group
my_rss_instance onsoctcp my_rss_host 1526 k=1,g=my_read_only_group

And then just use INFORMIXSERVER=my_read_only_group. Clients will attempt to connect to my_hdr_instance first, but it that fails they'll retry the connection against my_rss_instance.
And there you have it... The most simple client redirection you can find. This has advantages and disadvantages:
  •  You don't need another piece of software (connection manager). It's terribly simple to setup
  • It works for clients with very old versions that can't handle connection managers in REDIRECT mode (maybe in a future post about connection manager I'll explain this)
  • It will not work if you change your instances roles (like primary to secondary and vice-versa)
  • Although you could set "c=1" to randomly distribute the connections between the two servers, it would not allow more sophisticated redirection rules allowed by the connection manager
Let's now see the second scenario. For improved flexibility you want to implement connection manager. But you know that once you do it, it will be a single point of failure. If it's down, you won't be able to connect to your servers, even if there is nothing wrong with them. Naturally the solution would be to setup two connection managers on different machines. But then how would you configure your clients? Well, very similar to the example above. But this time, we would have two listeners (one in each machine where the connection manager is running) and we'd want the clients to see and try to connect through both of them. So, let's assume we create the cm_1 and cm_2 services on two different hosts using the connection manager. In each of them cm_* will be an SLA that will redirect for the secondary servers. So, our client side INFORMIXSQLHOSTS would be:

my_read_only_group - - i=100,c=1
cm_1 onsoctcp cm1_hostname 1526 g=my_read_only_group
cm_2 onsoctcp cm2_hostname 1526 g=my_read_only_group

Our clients would be setup with INFORMIXSERVER=my_read_only_group and they would try each connection manager randomly.  After reaching a connection manager service, they would be redirected to the appropriate secondary server. The configuration on the CM will not be covered in this post.

There is only one more piece of information that may be important. By default, Informix clients wait very long (60 seconds) for a connection attempt. When you're dealing with connection redirection you probably don't want to waste so much time.... Let's face it, if a server does not reply within 10s (I'm accommodating DNS problems and so on) it will never answer. We can establish two environment variables to configure this:
  • INFORMIXCONTIME
    The timeout the client will wait for a connection establishment (in seconds)
  • INFORMIXCONRETRY
    The number of attempts the client will do within the INFORMIXCONTIME period

Versão Portuguesa:
Foi-me pedido recentemente que configurasse um redirecionamento de ligações para um cluster Informix. Na maioria das situações queremos usar o connection manager, mas neste artigo não irei tão longe. Vou apenas rever algo que embora também esteja relacionado com o uso do connection manager, tem muitos mais casos de utilização, e apercebi-me que muitos clientes não têm conhecimento disto. Estou a referir-me ao campo de opções do ficheiro $INFORMIXSQLHOSTS. Pode encontrar a documentação completa sobre isto aqui no InfoCenter. Vou apenas referir algumas notas sobre algumas das opções que verifico serem desconhecidas de muitos clientes.
  • opção "r" (0|1)
    É apenas usada do lado do cliente. Se estiver com o valor 1, o cliente irá procurar num ficheiro chamado .netrc, na $HOME do utilizador, os dados de ligação, especificamente o utilizador e password
  • opção "s" (0,1,2,3|4|6)
    Controla as configurações de segurança do lado do servidor. Consulte a documentação para mais informação, mas:
    • 0 desativa a verificação dos ficheiros /etc/hosts.equiv e ~user/.rhosts (ou os seus equivalentes definidos nos parâmetros REMOTE_SERVER_CFG e REMOTE_USER_CFG)
    • 1 ativa a validação do ficheiro central de trusts (/etc/hosts.equiv ou o seu substituto indicado em REMOTE_SERVER_CFG) e desativa o ficheiro individual (~user/.rhosts e o seu substituto definido em REMOTE_USER_CFG)
    • 2 é o oposto de 1
    • 3 ativa ambos os ficheiros
    • 4 para portos configurados com PAM
    • 6 restringe o porto a conexões relacionadas com replicação (HDR, RSS e ER)
  • opção "k" (0|1)
    Ativa (1) a funcionalidade de TCP keep alive. Note que o intervalo de timeout e tentativas têm de ser configurados a nível de sistema operativo. Esta opção apenas força uma flag na gestão de sockets, sendo o resto feito ao nível do SO. Isto pode ser muito importante quando existem firewalls entre os clientes e servidores. Em alguns casos, se a funcionalidade não estiver ativa, os firewalls podem quebrar as ligações após um período de inatividade. Nestes casos os clientes podem receber um erro ao tentarem utilizar uma conexão que já não existe.
Como pode verificar na documentação existem muito mais opções. Mas para o objetivo deste artigo estou particularmente interessado nas opções de grupo. O conceito de grupos foi criado para a Enterprise Replication há muitos anos atrás, mas podemos usá-los para outros fins. Vejamos primeiro como criamos um grupo:

meu_grupo group - - i=100,c=0
meu_serveridor_1 onsoctcp meu_hostname_1 1526 k=1,g=meu_grupo
meu_serveridor_2 onsoctcp meu_hostname_2 1526 k=1,g=meu_grupo

Aqui estamos a criar um grupo com o nome "meu_grupo", definido porque usei "group" no campo do protocolo. Não utilizei o nome do servidor (hostname) nem o nome de serviço ou porto (sendo ambos substituídos por "-"), e usei duas opções:
  • i=100
    Apenas define um ID de grupo. Pode ser qualquer número (não repetido noutros grupos)
  • c=0
    Isto controla a forma como os clientes que acedem ao INFORMIXSERVER=meu_grupo lidam com os vários servidores do grupo. Esta opção pode ser definida a "0" ou "1":
    • 0 significa que tentam sempre ligar-se ao primeiro servidor do grupo, e se esse não responder passam ao seguinte e assim sucessivamente
    • 1 significa que irão aleatoriamente escolher um servidor para iniciar as tentativas de ligação e se não estiver a responder passam ao seguinte e assim sucessivamente
Como é que isto é útil? Vou dar dois cenários de utilização. O primeiro é um cluster com um servidor primário, um servidor HDR e outro RSS. Ambos os secundários estão em modo de leitura apenas e não planeamos mudar os papéis de cada um. É natural que o HDR esteja mais sincronizado com o primário que o RSS. Neste caso podemos desejar dirigir clientes de leitura preferencialmente para o nó HDR, mas em caso de falha ou manutenção planeada deverão ir para o RSS. As seguintes entradas do INFORMIXSQLHOSTS conseguiriam isto:

meu_grupo_leitura group - - i=100,c=0
meu_no_hdr onsoctcp meu_host_hdrt 1526 k=1,g=meu_grupo_leitura
meu_no_rss onsoctcp meu_host_rss 1526 k=1,g=meu_grupo_leitura

Depois basta usar INFORMIXSERVER=meu_grupo_leitura. Os clientes irão tentar ligar-se à instância "meu_no_hdr", mas se isso falhar vão tentar a conexão ao "meu_no_rss". E pronto... O redirecionamento de clientes mais simples que pode existir. Isto tem vantagens e desvantagens:
  • Não precisa de mais nenhum software (como o connection manager). É extremamente simples de configurar
  • Trabalha com clientes com versões muito antigas, que não saibam lidar com o modo REDIRECT do connection manager.(espero poder explicar isto num próximo artigo em que cubra o connection manager)
  • Não funcionará devidamente se trocarmos os papéis das instâncias (como primário para secundário e vice-versa)
  • Apesar de podermos definir "c=1" para distribuir aleatoriamente as conexões por ambos os servidores, os modos mais avançados de balanceamento só estão disponíveis no connection manager
Vejamos agora o segundo cenário. Como vimos acima, o connection manager permite mais flexibilidade. Mas sabemos que uma vez implementado, passa a ser um ponto de falha. Se estiver em baixo não será possível estabelecer ligações aos servidores, ainda que esteja tudo bem com eles. Naturalmente a solução para isto será ter dois (ou mais) connection managers a atuar em conjunto em máquinas diferentes. Mas depois, como configurar os clientes? Bom, de forma muito semelhante ao exemplo anterior. Mas desta vez, em vez dos listeners dos servidores teremos dois listeners (um em cada máquina que corra os connection managers), e queremos que os clientes vejam ambos e se tentem ligar através de ambos. Assim, assumindo que criamos os serviços (SLAs) cm_1 e cm_2 nos dois nós que correm o connection manager, ambos estarão configurados para redirecionar para os nós secundários. O INFORMIXSQLHOSTS do lado do cliente seria:

meu_grupo_leitura - - i=100,c=1
cm_1 onsoctcp cm1_hostname 1526 g=meu_grupo_leitura
cm_2 onsoctcp cm2_hostname 1526 g=meu_grupo_leitura

Portanto, os nossos clientes seriam configurados com INFORMIXSERVER=meu_grupo_leitura e tentariam ligar-se a um dos connection managers de forma aleatória. Depois de alcançarem um dos serviços cm_* seriam redirecionados para o nós secundário apropriado. A configuração dos connection managers não será abordada neste artigo.

Existe apenas mais um detalhe que merece referência. Por omissão os clientes Informix esperam muito tempo (60 segundos) até completarem uma tentativa de conexão. Havendo redirecionamento de conexões provavelmente não queremos esperar tanto tempo... Na verdade, se um servidor não responder em digamos, 10 segundos, provavelmente já não vai responder (e estou a acomodar algum tempo para problemas de DNS por exemplo). Podemos definir duas variáveis de ambiente para configurar este comportamento:
  • INFORMIXCONTIME
    O timeout que o cliente espera pelo fim do estabelecimento da conexão (em segundos)
  • INFORMIXCONRETRY
    O número de tentativas que o cliente faz dentro do tempo definido por INFORMIXCONTIME

No comments: