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.


3 - 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.

Para que seja utilizado é necessário que o Redis esteja instalado na máquina atual ou em algum servidor remoto. Existem versões para os principais sistemas operacionais do mercado, além da opção de rodar o servidor via Docker.

3.1 - REDIS - IMPLEMENTAÇÃO:

Adicionar o pacote Nuget:

dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis

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

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

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);
        
    }
    
}


4 - ASP.NET 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.

4.1 ASP.NET IN-MEMORY CACHE - IMPLEMENTAÇÃO:

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

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

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.


5 - POSSÍVEIS PROBLEMAS NA UTILIZAÇÃO

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

  • Ao utilizar o 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 cache via Redis agregamos mais um serviço no ecossistema da aplicação, trazendo com isso mais complexidade e custo a nossa infraestrutura.


6 - HISTÓRIAS DE USUÁRIO

HISTÓRIA

PONTUAÇÃO

PRODUTO

Implementar caching de dados via REDIS para as informações da carta e seus serviços.


13

Portal do Cidadão

Implementar caching de dados via REDIS para as informações de média de avaliações de um serviço.
8
Portal do Cidadão
Implementar caching de dados via REDIS para as informações de locais e horários de atendimento de um serviço.
8
Portal do Cidadão

Implementar caching de dados via REDIS para as informações de serviços mais acessados na homepage do Portal.

8
Portal do Cidadão
Implementar caching de dados via REDIS para as categorias de serviços exibidas na homepage do Portal.8Portal do Cidadão
Implementar caching de dados via REDIS para a lista de horários de atendimento do serviço dentro da visualização dos detalhes da solicitação.8Portal do Cidadão
Implementar caching de dados via REDIS para a lista de solicitações e agendamentos realizados pelo cidadão.8 Portal do Cidadão

TOTAL

061



7 - 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.


8 - REFERÊNCIAS:

ASP.NET Memory Cache | balta.io

Implementando cache distribuído no ASP.NET Core | Blog TreinaWeb

Configurando e usando memcached em ASP.NET núcleo - Referbruv