Sessões fixas refere-se à necessidade de redirecionar as solicitações de um determinado usuário para o mesmo servidor em que sua sessão reside. Isso é considerado um antipadrão, pois, em caso de falha do servidor, todos os usuários conectados a ele perderão suas sessões.
A associação entre o usuário e o servidor geralmente é configurada por meio do balanceador de carga, e estratégias simples de balanceamento de carga, como Redondo-robin muitas vezes não são suficientes para garantir uma distribuição uniforme das solicitações, pois os usuários pesados podem acabar todos no mesmo nó. Há muitas maneiras de evitar as sessões fixas, mas se o seu aplicativo armazena os dados do usuário na sessão HTTPS, as opções sem a necessidade de uma refatoração substancial são um pouco limitadas.
Uma solução rápida para esse problema é armazenar a sessão no banco de dados em vez de usar a memória do servidor. Nesse cenário, não importa qual nó receba a solicitação, ele carregará a sessão do usuário diretamente do armazenamento de dados. Essa abordagem é mais simples do que as soluções específicas para contêineres e também permite que você consulte as sessões como qualquer outra coisa no seu banco de dados.
O Couchbase se encaixa particularmente bem nesse cenário: ele usa o mecanismo interno de valor-chave e também aproveita a camada de cache interna para manter na memória as sessões usadas recentemente. Na prática, isso significa que essa é uma solução que terá um bom desempenho mesmo em escala. É por isso que estamos adicionando o suporte da comunidade Sessão de primavera:
Sessão do Couchbase Spring torna trivial o suporte a sessões em cluster, armazenando-o no banco de dados e, do ponto de vista do desenvolvedor, é totalmente transparente. Tudo o que você precisa fazer é adicionar a seguinte dependência:
|
1 2 3 4 5 |
<dependency> <groupId>io.github.couchbaselabs</groupId> <artifactId>spring-session-data-couchbase</artifactId> <version>1.1</version> </dependency> |
e, em seguida, em sua classe principal, adicione a tag @EnableCouchbaseHttpSession anotação:
|
1 2 3 4 5 6 7 8 9 |
@SpringBootApplication @EnableCouchbaseHttpSession público classe SessionStoreApplication { público estático vazio principal(Cordas[] argumentos) { SpringApplication.executar(SessionStoreApplication.classe, argumentos); } } |
e pronto! De agora em diante, o Spring salvará automaticamente a HTTPSession no Couchbase:
|
1 2 3 4 5 6 7 8 |
@GetMapping("/newSession") público Cordas newSession(HttpServletRequest solicitação, Modelo modelo) lançamentos Exceção { solicitação.getSession().invalidar(); HttpSession newSession = solicitação.getSession(); newSession.setAttribute("foo", novo Foo("chave", "valor")); retorno defaultPage(modelo, newSession); } |
Por padrão, a sessão será armazenada no banco de dados em um documento com um tipo igual a "sessões“:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
//key : 5b357ade-6059-4d16-aea3-6f784765e7b5 { "_principal": nulo, "_intervalo": 1800, "_expireAt": 1554743279889, "_created": 1554741479889, "_accessed": 1554741479889, "_type": "sessões", "_attr": "\"rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAABdAADZm9vc3IAHWNvbS5jYi5zZXNzaW9uc3RvcmUubW9kZWwuRm9vO5F+XaK9pV0CAAJMAAphdHRyaWJ1dGUxdAASTGphdmEvbGFuZy9TdHJpbmc7TAAKYXR0cmlidXRlMnEAfgAEeHB0AAZ2YWx1ZTF0AAZ2YWx1ZTJ4\"" } |
Mas você pode alterar o nome do atributo de tipo, o valor do tipo e a duração da sessão:
|
1 2 3 4 5 6 7 8 9 |
@SpringBootApplication @EnableCouchbaseHttpSession(typeName = "myType", typeValue = "myValueType", maxInactiveIntervalInSeconds = 1800) público classe SessionStoreApplication { público estático vazio principal(Cordas[] argumentos) { SpringApplication.executar(SessionStoreApplication.classe, argumentos); } } |
Consultar a sessão do usuário
Observe que todos os dados da sessão são armazenados de forma binária em um atributo chamado _attr:
|
1 2 3 4 |
{ ... "_attr": "\"rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAABdAADZm9vc3IAHWNvbS5jYi5zZXNzaW9uc3RvcmUubW9kZWwuRm9vO5F+XaK9pV0CAAJMAAphdHRyaWJ1dGUxdAASTGphdmEvbGFuZy9TdHJpbmc7TAAKYXR0cmlidXRlMnEAfgAEeHB0AAZ2YWx1ZTF0AAZ2YWx1ZTJ4\"" } |
O Spring não sabe quais tipos de objetos estão na sessão, portanto, não há uma maneira fácil de convertê-lo em um formato legível por humanos. Você pode superar essa limitação definindo o atributo manterStringAsLiteral como verdadeiro no EnableCouchbaseHttpSession anotação:
|
1 2 3 4 5 6 7 8 9 |
@SpringBootApplication @EnableCouchbaseHttpSession(manterStringAsLiteral = verdadeiro) público classe SessionStoreApplication { público estático vazio principal(Cordas[] argumentos) { SpringApplication.executar(SessionStoreApplication.classe, argumentos); } } |
manterStringAsLiteral dirá Sessão do Couchbase Spring para armazenar todos os atributos String da sessão como propriedades de nível superior no documento. Por exemplo, em vez de adicionar uma instância diretamente à sessão, poderíamos converter o objeto em um formato String codificado em JSON usando a função Mapeador de objetos:
|
1 2 |
Mapeador de objetos mapeador = novo Mapeador de objetos(); sessão.setAttribute("chave", mapeador.writeValueAsString(myClassInstance)) |
E então, quando você precisar ler o carrinho de sessão, converta-o novamente em um objeto:
|
1 2 |
Mapeador de objetos mapeador = novo Mapeador de objetos(); mapeador.readValue( sessão.getAttribute("chave").toString(), Minha classe.classe); |
|
1 2 3 4 5 6 7 8 9 10 11 12 |
//key : 5b2a2487-4825-43de-b089-1b61703556b2 { "_principal": nulo, "_intervalo": 1800, "_expireAt": 1554746972015, "_created": 1554745163803, "_accessed": 1554745172015, "chave": "{\"shoppingCart\":{\"created\":1554745170784,\"items\":[{\"itemName\":\"Tennis Shoes\",\"price\":38.25186017511709,\"quantity\":3}]},\"user\":{\"username\":\"robertst\",\"phoneNumber\":\"(500)-383-1668\"},\"location\":{\"address\":\"90 Arrowhead Avenue Jonesboro, GA 30236\",\"country\":\"USA\",\"coordinates\":{\"lat\":10,\"lon\":37}}}", "_type": "sessões", "_attr": "\"rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAB3CAAAABAAAAAAeA==\"" } |
Observe que ainda temos o _att para objetos que não sejam uma String. No entanto, agora também temos um atributo chamado chave, que é exatamente o objeto que adicionamos à sessão no exemplo anterior.
Agora, se você quiser consultar sua sessão, N1QL tem uma função chamada DECODE_JSONque pode transformar uma string codificada em JSON em um objeto:
|
1 2 3 4 5 |
SELECIONAR meta().id como id, _criado, ARRAY_COUNT(DECODE_JSON(sessionCart).shoppingCart.items) DE loja de sessão ORDEM BY _criado DESC LIMITE 10 |
Observação: Em um ambiente de produção, recomendamos que você crie um índice com o objeto decodificado em vez de decodificá-lo no momento da consulta.
Se você quiser saber mais sobre o Couchbase Spring Session, confira este tutorial
Se tiver alguma dúvida, sinta-se à vontade para entrar em contato comigo pelo e-mail @deniswrosa