<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: João Victor Rocha</title>
    <description>The latest articles on DEV Community by João Victor Rocha (@vixtorocha).</description>
    <link>https://dev.to/vixtorocha</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F187719%2F86add14c-8103-487f-8467-977d7b906ec3.jpeg</url>
      <title>DEV Community: João Victor Rocha</title>
      <link>https://dev.to/vixtorocha</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vixtorocha"/>
    <language>en</language>
    <item>
      <title>Cache and Redis: Why and How to Use</title>
      <dc:creator>João Victor Rocha</dc:creator>
      <pubDate>Thu, 06 Aug 2026 20:33:01 +0000</pubDate>
      <link>https://dev.to/vixtorocha/cache-and-redis-why-and-how-to-use-36f6</link>
      <guid>https://dev.to/vixtorocha/cache-and-redis-why-and-how-to-use-36f6</guid>
      <description>&lt;p&gt;Imagine your application makes thousands of queries to the same database. All this traffic generates latency, CPU load, disk load, and increases costs. In such scenarios, &lt;strong&gt;cache&lt;/strong&gt; comes in: an ultra-fast memory (RAM) layer that stores recent results to avoid repeated database queries.&lt;/p&gt;

&lt;p&gt;Instead of reading from disk (which can take tens or hundreds of milliseconds), the cache responds in microseconds. In practice, using cache allows the application to do &lt;em&gt;much more&lt;/em&gt; "cheap" work in memory and very few expensive operations on the database.&lt;/p&gt;

&lt;p&gt;For example, imagine a gaming site with 1 million visits per second displaying results. Without cache, that would be 1 million SELECTs on SQL. With Redis configured with a short TTL (e.g., 3s), Redis would handle about 60 million queries per minute, and only ~30 SQL queries would be executed, resulting in a drastic reduction in load. In other words, with a cache you go from "1,000,000 expensive operations" to "1 expensive operation + 999,999 cheap RAM accesses".&lt;/p&gt;

&lt;p&gt;Redis is one of the most common tools for caching. It stores data in &lt;strong&gt;pure RAM memory&lt;/strong&gt;, providing responses at nanosecond latencies.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Various benchmarks show that a typical database query takes in the range of 50–200 ms, while the same operation on Redis takes &lt;strong&gt;&amp;lt; 1 ms&lt;/strong&gt;. In real situations, MySQL typically handles 500–1,000 queries per second, but a Redis server can exceed 100,000 operations per second on the same machine. Queries with multiple joins that took ~120 ms drop to ~0.8 ms on Redis. In the end, adding cache &lt;em&gt;drastically&lt;/em&gt; reduces latency and increases system throughput by 10–50× (or more). That's why "almost everything on the internet" relies on Redis or similar for caching.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Beyond the speed gain, there's also cost savings. Since Redis relieves the load on the main database, often you can &lt;strong&gt;postpone expensive&lt;/strong&gt; hardware upgrades. In summary: investing in RAM can be much cheaper than overloading CPUs and disks.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the Cache-Aside Pattern Works
&lt;/h2&gt;

&lt;p&gt;One of the most common ways to use cache is the so-called &lt;em&gt;Cache-Aside&lt;/em&gt; pattern (or &lt;em&gt;lazy-loading&lt;/em&gt;). The logic is simple and under application control: every time you need data, you &lt;strong&gt;first check the cache&lt;/strong&gt;. If you get a &lt;em&gt;cache hit&lt;/em&gt; (found it), great: return the value immediately. If you get a &lt;em&gt;cache miss&lt;/em&gt; (not found), then you go to the database, get the "official" data, and then &lt;strong&gt;store that result in the cache&lt;/strong&gt; for future reads. In practice:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The application tries to read from cache (for example, a Redis key).&lt;/li&gt;
&lt;li&gt;If it exists (&lt;em&gt;hit&lt;/em&gt;), return the value.&lt;/li&gt;
&lt;li&gt;If it doesn't exist (&lt;em&gt;miss&lt;/em&gt;), query the database, get the result, and store it in the cache for future queries.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This model is ideal when data is read much more often than written and when we tolerate &lt;strong&gt;eventual consistency&lt;/strong&gt; (if the cache gets slightly outdated, it doesn't break everything). The advantages are clear: fast memory reads instead of disk access, precise control over what goes into the cache, and much less pressure on the database, making the system more scalable and easier to implement.&lt;/p&gt;

&lt;p&gt;For example, in the cache-aside pattern in Node.js, you could do something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;redis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cacheKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`user:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cacheResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cacheKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cacheResult&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cache hit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cacheResult&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Returns from cache&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// Cache miss: fetch from database&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchUserById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Store in Redis with TTL (example: 1 hour = 3600s)&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cacheKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;EX&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cache updated with database result&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This logic (check cache first, then database, and then update cache) is exactly cache-aside in action.&lt;/p&gt;

&lt;p&gt;In this Python example, the &lt;code&gt;EX: 3600&lt;/code&gt; argument in &lt;code&gt;set&lt;/code&gt; indicates that the key should expire in 1 hour. This is a way to &lt;strong&gt;automatically invalidate&lt;/strong&gt; old data: after the time-to-live (&lt;code&gt;TTL&lt;/code&gt;), Redis deletes the key. So we don't need to manually delete each time since Redis itself cleans up expired keys.&lt;/p&gt;

&lt;p&gt;Using TTL works well when you can tolerate the information becoming outdated for a short period. It's a trade-off between performance and consistency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cache Invalidation and Considerations
&lt;/h2&gt;

&lt;p&gt;An important point is &lt;strong&gt;cache invalidation&lt;/strong&gt;. How do you ensure the cache reflects changes made to the database? If you only use TTL, you'll display the old value until the time expires. A common strategy is to &lt;strong&gt;explicitly invalidate&lt;/strong&gt; the cache whenever you write to the database. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;updateDatabase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Updates database&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redisClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;del&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`user:profile:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Invalidates corresponding cache key&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That way, on the next &lt;code&gt;getUser(id)&lt;/code&gt;, the cache &lt;strong&gt;miss&lt;/strong&gt; will be triggered and you would fetch the updated value from the database before re-populating the cache. This approach ensures immediate consistency: you don't risk serving stale data. It's important to coordinate the database write and cache removal in the same application logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Considerations
&lt;/h2&gt;

&lt;p&gt;Using Redis as a cache can revolutionize your applications' performance. In real tests, it's possible to notice latencies of dozens of milliseconds reduce to microseconds, and throughput jump by 10–50× or more. In high-traffic systems (like e-commerce, REST APIs, etc.), reducing database load is essential to scale without astronomical costs. Just remember: plan your cache pattern well (like cache-aside), use &lt;code&gt;EXPIRE&lt;/code&gt; to prevent stale data, and manually invalidate at write points. With that done, you'll have a much more agile system with less dependence on heavy reads from the main database.&lt;/p&gt;

</description>
      <category>redis</category>
      <category>backend</category>
      <category>programming</category>
    </item>
    <item>
      <title>O que é, e quando usar Kafka?</title>
      <dc:creator>João Victor Rocha</dc:creator>
      <pubDate>Thu, 06 Aug 2026 20:20:22 +0000</pubDate>
      <link>https://dev.to/vixtorocha/o-que-e-e-quando-usar-kafka-3n0f</link>
      <guid>https://dev.to/vixtorocha/o-que-e-e-quando-usar-kafka-3n0f</guid>
      <description>&lt;p&gt;Imagine o seguinte cenário: você é desenvolvedor de um e-commerce que recebe milhares de pedidos por hora; isso significa orquestrar eventos de pedidos, pagamentos, atualização de estoque e notificações. A &lt;strong&gt;Mensageria&lt;/strong&gt; brilharia nesse cenário onde há muitos eventos chegando em tempo real e múltiplos sistemas que precisam processá-los de forma assíncrona.&lt;/p&gt;

&lt;p&gt;Em ambientes com muitos sensores, como fazendas inteligentes, fábricas ou redes de equipamentos médicos, dispositivos de IoT (Internet das Coisas) enviam medições constantes, permitindo que outros dispositivos reajam a esses dados.&lt;/p&gt;

&lt;p&gt;Exemplo: um sensor mede a umidade, temperatura e luminosidade em um determinado ponto da plantação, envia essas informação a um message broker (como o Kafka), e a partir daí o serviço de irrigação lê os dados da umidade do solo e decide se precisa ligar os aspersores naquele local.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mensageria
&lt;/h2&gt;

&lt;p&gt;Mensageria é uma forma como diversos sistemas podem trocar informações entre si sem um serviço chamar diretamente o outro. Eles se comunicam enviando e recebendo mensagens por meio de um intermédio, como o Kafka, RabbitMQ, etc.&lt;/p&gt;

&lt;p&gt;A mensageria ajuda a resolver vários problemas comuns em sistemas modernos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Desacoplar serviços: garante que os microsserviços se comuniquem sem gerar acoplamento.&lt;/li&gt;
&lt;li&gt;Processar tarefas de forma assíncrona: A operação pode ocorrer em segundo plano, sem bloquear o usuário.&lt;/li&gt;
&lt;li&gt;Distribuir trabalho entre vários consumidores.&lt;/li&gt;
&lt;li&gt;Tornar o sistema mais resiliente: se um serviço cair, as mensagens ficam guardadas e serão processadas quando ele voltar.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Apache Kafka
&lt;/h2&gt;

&lt;p&gt;O Apache Kafka é um sistema open source de mensageria que armazena streams de dados de forma durável, ordenada e distribuída. Com ele é possível criar sistemas que coletam logs, acompanham a atividade de usuários e integram diversos componentes de forma resiliente.&lt;/p&gt;

&lt;p&gt;É justamente aí que o Kafka se diferencia da maioria. Em muitos brokers tradicionais, como o RabbitMQ, ActiveMQ e SQS, a mensagem costuma sumir depois que um consumidor lê e confirma o processamento.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vantagens
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Aguenta alto volume de mensagens.&lt;/li&gt;
&lt;li&gt;Processamento em tempo real.&lt;/li&gt;
&lt;li&gt;Durabilidade e tolerância a falhas.&lt;/li&gt;
&lt;li&gt;Durabilidade dos dados. Ideal para múltiplos consumidores.
### Desvantagens&lt;/li&gt;
&lt;li&gt;Overkill quando há baixo volume de dados (menos de 1000 mensagens por segundo).&lt;/li&gt;
&lt;li&gt;Complexidade de configuração e operação.&lt;/li&gt;
&lt;li&gt;Custo de manutenção e de especialistas.&lt;/li&gt;
&lt;li&gt;Alta curva de aprendizagem.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fontes:&lt;br&gt;
&lt;a href="https://hadoop.com.br/tecnologias/streaming/apache-kafka" rel="noopener noreferrer"&gt;https://hadoop.com.br/tecnologias/streaming/apache-kafka&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kafka</category>
      <category>programming</category>
      <category>backend</category>
    </item>
  </channel>
</rss>
