Ir para o conteúdo principal

Portal do Cidadão - Estudo de Ferramentas para Melhoria de Performance

OBJETIVO

Mapear soluções para melhoria de performance no projeto Portal do Cidadão conforme a User Story: “Eu como vingadores, preciso realizar um estudo de caso para melhoria de perfomance no Portal do Cidadão" presente na Sprint número 100 do time Vingadores.


JUSTIFICATIVA

Tendo em vista que o Portal do Cidadão terá um alto volume de acessos, os usuários poderão experimentar lentidões ou instabilidades durante o seu uso. Desta forma faz-se necessário a elaboração deste estudo para mapear possíveis soluções e ferramentas para a garantia da disponibilidade do sistema.


RESULTADOS ESPERADOS

Levantar ferramentas, técnicas ou soluções disponíveis que possam impactar significativamente na melhoria de performance do sistema parcialmente ou como um todo.


ENVOLVIDOS:

Gustavo Felix Gomes (Dev team)

Rafael Passos dos Santos (Dev team)

Emanuel Rufino Alcantara de Lima (Dev team)

Lucas de Souza e Sousa (Dev team)

André Honório de Andrade Silva (Dev team)

Alef Carvalho (Dev team)

Euriane Nogueira Frota (Product Owner)


1 - INTRODUÇÃO

É comum termos diversos dados das nossas aplicações que não mudam com frequência. Tudo que tem baixa mutabilidade, pode ser cacheado, evitando que a requisição precise chegar até a fonte de dados, sobrecarregando-a sem necessidade.

A técnica de cache normalmente é implementada entra a aplicação e a sua fonte de dados. Quando uma requisição ocorre, podemos cachear seus resultados em algum local e posteriormente, toda vez que esta mesma requisição for chamada, lemos estes dados ao invés de consultar o banco de dados.

O cache pode ser salvo em diversos lugares, incluindo memória e disco. Todos os dados possuem um tempo de expiração que quando atingido força a renovação do mesmo. Essa renovação significa que a próxima requisição irá novamente até o banco de dados e o processo de caching será feito novamente.


2 -  CENÁRIO ATUAL

No Portal do Cidadão, não há nenhum tipo de caching de dados ou estratégia semelhante em execução. Devido ao alto volume de acessos previsto após o lançamento da plataforma faz-se necessário a implementação de uma ou mais técnicas deste tipo afim de garantir a performance da aplicação em produção.


MEMCACHE

Memcached é um sistema de cache de objetos de memória distribuída de código aberto, de alto desempenho, que ajuda na redução da carga do banco de dados. Ele mantém os dados como uma loja de valor de chave na memória para pequenos pedaços de dados arbitrários (strings, objetos) que podem ser resultado de chamadas de API, leituras de banco de dados e assim por diante.


REDIS

Redis é um banco de dados estruturados em memória, open source, que pode ser utilizado como database, cache e/ou mensageria porém o seu uso mais comum é como sistema de cache.


REDIS - IMPLEMENTAÇÃO:

1 - Adicionar o pacote Nuget para Redis.

dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis

2 - Em seguida registrá-lo no método ConfigureServices da classe Startup:

public void ConfigureServices(IServiceCollection services)
{
    //...       
    services.AddStackExchangeRedisCache(options =>
    {
        options.Configuration = "localhost:6379";
    });
}

3 - Consumir cache:

[Route("api/[controller]")]
[ApiController]
public class CidadaoController : ControllerBase
{

	private readonly ICidadaoRepository<Cidadao> cidadaoRepository;
    private readonly IDistributedCache _cache;
    private ILogger<EmployeeController> logger;

    public CidadaoController(
    	ICidadaoRepository<Cidadao> cidadaoRepository,
        IDistributedCache cache,
        ILogger<EmployeeController> logger
    )
    {
        this.cidadaoRepository = cidadaoRepository;
        this.cache = cache;
        this.logger = logger;
    }

    [HttpGet]
    public async Task<IActionResult> Index()
    {
    
    	var cacheKey = "listaCidadoes";
   		var cidadoes = new List<Cidadao>();
        var json = await cache.GetStringAsync(cacheKey);
        
        if(json != null)
        {
            products = JsonSerializer.Deserialize<List<Cidadao>>(json);
        }  
        else
        {
            _logger.Log(LogLevel.Information, "Nenhum cidadão encontrado no cache Redis. Buscando do banco de dados...");

            cidadoes = cidadaoRepository.GetAll();

            _logger.Log(LogLevel.Information, "Salvando cidadões no cache Redis...");
            
            json = JsonSerializer.Serialize<List<Cidadao>>(cidadoes);
            await _cache.SetStringAsync(cacheKey, json);
            
        }

        return Ok(cidadoes);
        
    }
    
}


IN-MEMORY CACHE

O cache em memória em ASP.NET Core uma forma simples e nativa de cache em que o aplicativo armazena dados na memória do servidor web. Isso é baseado na interface que representa um objeto de cache armazenado na memória do aplicativo.

IN-MEMORY CACHE - IMPLEMENTAÇÃO:

1 - Registrar o Middleware de caching nativo no método ConfigureServices da classe Startup:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMemoryCache();
}

2 - Consumir o cache na aplicaçao:

[Route("api/[controller]")]
[ApiController]
public class CidadaoController : ControllerBase
{
    private const string cacheKey = "listaCidadoes";
    private readonly ICidadaoRepository<Cidadao> cidadaoRepository;
    private IMemoryCache cache;
    private ILogger<EmployeeController> logger;

    public CidadaoController(
    	ICidadaoRepository<Cidadao> cidadaoRepository,
        IMemoryCache cache,
        ILogger<EmployeeController> logger
    )
    {
        this.cidadaoRepository = cidadaoRepository;
        this.cache = cache;
        this.logger = logger;
    }

    [HttpGet]
    public async Task<IActionResult> Index()
    {
    
        if (_cache.TryGetValue(cacheKey, out IEnumerable<Cidadadao> cidadoes))
        {
            _logger.Log(LogLevel.Information, "Nenhum cidadão encontrado no cache.");
        }
        else
        {
            _logger.Log(LogLevel.Information, "Nenhum cidadão encontrado em cache. Buscando do banco de dados...");

            cidadoes = cidadaoRepository.GetAll();

            _logger.Log(LogLevel.Information, "Salvando cidadões no cache...");
            
            var cacheEntryOptions = new MemoryCacheEntryOptions()
                    .SetSlidingExpiration(TimeSpan.FromSeconds(60))
                    .SetAbsoluteExpiration(TimeSpan.FromSeconds(3600))
                    .SetPriority(CacheItemPriority.Normal)
                    .SetSize(1024);

            _cache.Set(cacheKey, cidadoes, cacheEntryOptions);
            
        }

        return Ok(cidadoes);
    }
    
}

Esta técnica de cache tem dois pontos importantes à serem levados em conta antes de uma possível implementação, a memória e a escalabilidade

Como estamos colocando os dados de cache na memória do servidor web, quanto mais dados forem inclusos em cache, mais memória será consumida pela aplicação em execução. O ASP.NET fica responsável por gerenciar a memória e desaloca-la caso necessário.

 

POSSÍVEIS PROBLEMAS NA UTILIZAÇÃO

Como a aplicação do Portal do CidadadãCidadão é executadaexecutado em ambiente Kubernetes (Openshift) faz-se necessário a observação de alguns pontos:

  • Ao utilizar o driver de cache nativo do ASP.NET a configuração padrão de escalonamento do Kubernetes faz com que quando a aplicação chegue à X% de CPU ou memória, um novo contâiner (pod) seja provisionad. Este novo contâiner possui apenas a aplicação em sí, a memória do container anterior não é replicada.
  • Ao utilizar o drivercache redisvia Redis agregamos mais um serviço no ecossistema da aplicação, trazendo com isso mais complexidade e custo a nossa infraestrutura.

 

HISTÓRIAS DE USUÁRIO

HISTÓRIA

PONTUAÇÃO

PRODUTO



Portal do Cidadão



Portal do Cidadão


Portal do Cidadão


Portal do Cidadão

TOTAL

0



CONCLUSÃO

Dado que, uma alteração no fluxo das solicitações se faz necessária, é de suma importância que seja devidamente mapeada na aplicação os dados com baixa imutabilidade afim de que seja implementado uma das estratégias de caching citadas anteriormente.

Considerado o alto volume de trafego do Portal do Cidadão o impacto da aplicação de caching em funcionalidades específicas  agrega valor ao produto final, impactando significativamente a experiência do usuário no uso da aplicação.