<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[aTech Guide]]></title><description><![CDATA[Hi, I'm Kamran Ali, Principal Engineer @Atlassian

I have ~11.5 years of experience in Designing and Building Transactional / Analytical Systems.]]></description><link>https://atech.guide</link><generator>RSS for Node</generator><lastBuildDate>Sat, 18 Apr 2026 03:09:55 GMT</lastBuildDate><atom:link href="https://atech.guide/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Scaling Caching at Etsy: A Story of handlings 1,000,000's of lookups / sec]]></title><description><![CDATA[Etsy optimised 1,000,000,000,000's of cached data handlings 1,000,000's lookups/sec
Story of Consistent Hashing with a secret sauce.

Etsy, uses memcached (to cache db queries, expensive calculations etc) and Varnish (to cache internal HTTP requests)...]]></description><link>https://atech.guide/consistent-hashing-cache-smearing-etsy</link><guid isPermaLink="true">https://atech.guide/consistent-hashing-cache-smearing-etsy</guid><category><![CDATA[consistent hashing]]></category><category><![CDATA[performance]]></category><category><![CDATA[scalability]]></category><category><![CDATA[caching]]></category><dc:creator><![CDATA[Kamran Ali]]></dc:creator><pubDate>Sun, 01 Sep 2024 14:26:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1725200607137/7145e5e0-6cb8-4df5-8c8d-358cd6ed7dcc.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Etsy optimised 1,000,000,000,000's of cached data handlings 1,000,000's lookups/sec</p>
<p>Story of Consistent Hashing with a secret sauce.</p>
<hr />
<p>Etsy, uses <a target="_blank" href="https://memcached.org/">memcached</a> (to cache db queries, expensive calculations etc) and <a target="_blank" href="https://varnish-cache.org/intro/index.html#intro">Varnish</a> (to cache internal HTTP requests) to improve performance and reduce load.</p>
<p>They have a pool of caching servers, each running memcached or Varnish.</p>
<hr />
<h2 id="heading-how-to-distribute-cached-data-across-servers">How to distribute Cached data across Servers?</h2>
<h3 id="heading-1-modulo-hashing">1. Modulo Hashing</h3>
<p>It is implemented as follows</p>
<ol>
<li><p>Hash the key to a number</p>
</li>
<li><p>Modulo it by the size of cache pool to store key value pair to a specific server</p>
</li>
</ol>
<h4 id="heading-example">Example</h4>
<ul>
<li><p>We need to store <code>some_key</code> and <code>some_value</code>.</p>
</li>
<li><p>We have 3 host servers numbered as 0, 1, 2</p>
</li>
<li><p>We map <code>some_key</code> to a number (via a hash function) let's say number is 4</p>
</li>
<li><p>Taking modulo <code>4 % 3 == 1</code>, hence we will store <code>some_key</code> to "1" server</p>
</li>
</ul>
<h4 id="heading-pros">Pros</h4>
<ul>
<li>Each cached value is stored on a single host</li>
</ul>
<h4 id="heading-cons">Cons</h4>
<ul>
<li><p>Changing the size of the cache pool will cause most cache keys to hash to a new server leading to tons of cache misses.</p>
<ul>
<li><p>In above example, if we add a fourth server.</p>
</li>
<li><p>Taking modulo <code>4 % 4 == 0</code>, <code>some_key</code> will now be cached at "0" server.</p>
</li>
<li><p>Worsening the cache hit rate</p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-2-consistent-hashing">2. Consistent hashing</h3>
<p>It is implemented as follows</p>
<ol>
<li><p>Fix the Hash space and divide it into large contiguous buckets</p>
</li>
<li><p>One (or more) buckets are assigned to a cache host</p>
</li>
<li><p>Keys that hash to a Range are looked up on the matching host</p>
</li>
</ol>
<h4 id="heading-example-1">Example</h4>
<ul>
<li><p>Let's say, Hash Space = 1,000</p>
</li>
<li><p>We divide it into 3 buckets of [0, 333), [333, 666), [666, 999]</p>
</li>
<li><p>We have two hosts,</p>
<ul>
<li><p><code>host 0</code> is assigned two buckets viz [0, 333), [333, 666)</p>
</li>
<li><p><code>host 1</code> is assigned one bucket viz [666, 999]</p>
</li>
</ul>
</li>
<li><p>We need to store <code>some_key</code> and <code>some_value</code>.</p>
</li>
<li><p>we map <code>some_key</code> to a number (via a hash function) let's say number is 44.</p>
</li>
<li><p>As "44" falls in first bucket range, it is stored in <code>host 0</code></p>
</li>
</ul>
<h4 id="heading-pro">Pro</h4>
<ul>
<li><p>Changing the pool size means moving few buckets from existing server to a new server. Hence it moves only a small number of Keys</p>
<ul>
<li><p>In above example, if we add another server <code>host 2</code> and move [333, 666) bucket to it</p>
</li>
<li><p>Only 333 keys will be moved to a new server i.e. 33% of key movement.</p>
</li>
<li><p>We can play around with bucket size to further decrease key redistribution.</p>
</li>
</ul>
</li>
</ul>
<p>They leverage <a target="_blank" href="https://github.com/RJ/ketama">Ketama</a> to implement Consistent Hashing</p>
<h2 id="heading-how-to-serve-hot-keys">How to serve Hot keys?</h2>
<p>Certain cache items are read and written more than others.</p>
<p>Ideally, a good hash function shall distribute the "hot keys" among many servers</p>
<hr />
<h3 id="heading-celebrity-key">"Celebrity" Key</h3>
<p>At Etsy, they've seen keys that are hit quite often, and stores a large enough value, that it saturate the network interface of their cache host.</p>
<p>The large number of clients are collectively generating a higher read rate than the cache server can provide.</p>
<p>To fix this they explored following solutions</p>
<h4 id="heading-solution-1-horizontal-scaling">Solution 1: Horizontal Scaling</h4>
<p>Adding more cache hosts doesn't help because it only changes the distribution of keys to hosts i.e. it would only move the problem key and saturate a different host</p>
<h4 id="heading-solution-2-faster-network-cards">Solution 2: Faster network cards</h4>
<p>It will have a substantial hardware cost.</p>
<h4 id="heading-solution-3-cache-smearing">Solution 3: Cache Smearing</h4>
<p>They used consistent hashing and added a small amount of entropy to certain hot cache keys for all reads and writes.</p>
<p>This effectively turns one key into several, each storing the same data and letting the hash function distribute the read and write volume for the new keys among several hosts.</p>
<p>Example</p>
<ul>
<li><p>Let's say <code>celebrity_key</code> is a Hot Key</p>
</li>
<li><p>Cache smearing appends a random number in a small range (let's say, <code>[0, 5</code>)) to the key before each read or write. So for e.g. <code>celebrity_key</code> will be transformed as <code>celebrity_key_1</code>, <code>celebrity_key_3</code>, <code>celebrity_key_0</code></p>
</li>
<li><p>As <code>celebrity_key_1</code>, <code>celebrity_key_3</code>, <code>celebrity_key_0</code> keys are different, they will be hashed to different hosts, sharing the load among the pool.</p>
</li>
</ul>
<p>Tradeoffs in choosing the range of random number</p>
<ul>
<li><p>Too-large range duplicates the cached data more than necessary to reduce load, and can lead to data inconsistencies</p>
</li>
<li><p>A too-small range doesn't spread the load effectively among the cache pool (and could even result in all the smeared keys still being hashed to the same pool member)</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In summary, combination of consistent hashing and cache smearing has been a great combination of efficiency and practicality</p>
<p>Allowing multiple hosts to serve requests for a Hot key, prevent any one host from being overloaded, increasing the overall read rate of the cache pool.</p>
<p>At Etsy, they manually added cache smearing to hottest keys, with entropy in a small range like 0 to 8 or 0 to 16.</p>
<hr />
<p>Understanding the Foundational Principles is the key to Effective Learning!</p>
<p>Follow along to Improve System Design Skills.</p>
<h2 id="heading-reference-and-image-credit">Reference and Image Credit</h2>
<ul>
<li><a target="_blank" href="https://www.etsy.com/codeascraft/how-etsy-caches/">How Etsy caches: hashing, Ketama, and cache smearing</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Mastering Database Scalability: Figma's Approach to Vertical Partitioning Database Explained]]></title><description><![CDATA[Figma used this strategy to Vertically Partition their Database
Learn the tradeoffs for your next System Design Interview 👇
Definition

Vertical partitioning is when a database is split by moving tables and/or columns into a separate database

Backg...]]></description><link>https://atech.guide/database-scaling-vertical-partitioning-figma</link><guid isPermaLink="true">https://atech.guide/database-scaling-vertical-partitioning-figma</guid><category><![CDATA[System Design]]></category><category><![CDATA[System Architecture]]></category><category><![CDATA[Databases]]></category><category><![CDATA[scalability]]></category><dc:creator><![CDATA[Kamran Ali]]></dc:creator><pubDate>Fri, 30 Aug 2024 12:35:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1725020375225/94128d82-ff6b-4d60-9d0d-fc1bb067294c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Figma used this strategy to Vertically Partition their Database</p>
<p>Learn the tradeoffs for your next System Design Interview 👇</p>
<h2 id="heading-definition">Definition</h2>
<blockquote>
<p>Vertical partitioning is when a database is split by moving tables and/or columns into a separate database</p>
</blockquote>
<h2 id="heading-background">Background</h2>
<p>Initially they were on a single large Amazon RDS database and observed upwards of 65% CPU utilization during peak traffic with Database latencies becoming increasingly unpredictable</p>
<h2 id="heading-first-tactical-fixes">First Tactical Fixes</h2>
<ol>
<li><p>Upgrade database to the largest instance available (from r5.12xlarge to r5.24xlarge) to maximize CPU utilization runway</p>
</li>
<li><p>Create multiple read replicas to scale read traffic</p>
</li>
<li><p>Establish new databases for new use cases to limit growth on original database</p>
</li>
<li><p>Add PgBouncer as a connection pooler to limit the impact of a growing number of connections</p>
</li>
</ol>
<p>on further Analysis they learned</p>
<ul>
<li><p>Writes contributed a significant portion of database utilization.</p>
</li>
<li><p>Not all reads could be moved to replicas due to application sensitivity to replication lag.</p>
</li>
</ul>
<p>Hence, they still needed to offload more work from our original database.</p>
<h2 id="heading-possible-solutions">Possible Solutions</h2>
<h3 id="heading-1-horizontal-scaling-the-database">1. Horizontal Scaling the Database</h3>
<p>They observed many popular managed solutions are not natively compatible with Postgres.</p>
<p>So, they would either have to find a Postgres-compatible managed solution, or self-host.</p>
<h3 id="heading-2-migrating-to-nosql">2. Migrating to NoSQL</h3>
<p>It would require</p>
<ul>
<li><p>Complex double read and write migration</p>
</li>
<li><p>Significant application side changes</p>
</li>
</ul>
<h3 id="heading-3-postgres-compatible-newsql">3. Postgres-compatible NewSQL</h3>
<p>They would’ve had one of the largest single-cluster footprints for cloud-managed distributed Postgres.</p>
<p>So they didn’t want to bear the burden of being the first customer to hit certain scaling issues while having little control over managed solutions.</p>
<h3 id="heading-4-self-hosting">4. Self Hosting</h3>
<p>It would mean</p>
<ul>
<li><p>Upfront work to acquire the training, knowledge, and skills to support self-hosting.</p>
</li>
<li><p>Large operational cost</p>
</li>
</ul>
<h3 id="heading-5-vertically-partition-the-db">5. Vertically Partition the DB</h3>
<p>They would move <em>groups of tables</em> onto their own databases.</p>
<p>This proved to have both short- and long-term benefits</p>
<ol>
<li><p>Vertical partitioning relieves the original database</p>
</li>
<li><p>Provide a path forward for horizontally sharding subsets of tables in the future</p>
</li>
</ol>
<h2 id="heading-how-they-implemented-vertical-partitioning">How they implemented Vertical Partitioning</h2>
<p>They first need to identify tables to partition into their own database. They chose the tables via following factors</p>
<ol>
<li><p>Impact: Moving the tables should move a significant portion of workload</p>
</li>
<li><p>Isolation: The tables should not be strongly connected to other tables</p>
</li>
</ol>
<h3 id="heading-1-measuring-impact">1. Measuring impact</h3>
<ul>
<li><p>They looked at Average Active Sessions (AAS) for queries (average number of active threads dedicated to a given query at a certain point in time).</p>
</li>
<li><p>They calculated this information by querying pg_stat_activity in 10 millisecond intervals to identify CPU waits associated with a query, and then aggregated the information by table name.</p>
</li>
</ul>
<h3 id="heading-2-measuring-isolation">2. Measuring isolation</h3>
<ul>
<li><p>They have Ruby based backend which use ActiveRecord to write queries</p>
</li>
<li><p>They created Validators that hooked into ActiveRecord and send production query and transaction information into Snowflake to look for queries and transactions that consistently referenced the same group of tables</p>
</li>
<li><p>If these workloads turned out to be costly, those tables would be identified as prime candidates for vertical partitioning</p>
</li>
</ul>
<h2 id="heading-table-migration">Table Migration</h2>
<p>The data movement has to be coordinated across thousands of application backend instances, so they could route queries to the new database at the correct moment.</p>
<p>They wanted a solution that met the following goals:</p>
<ol>
<li><p>Limit potential availability impact to &lt;1 minute</p>
</li>
<li><p>Automate the procedure so it is easily repeatable</p>
</li>
<li><p>Have the ability to undo a recent partition</p>
</li>
</ol>
<h2 id="heading-solution">Solution</h2>
<p>At a high level, they implemented the following</p>
<ol>
<li><p>Prepare client applications to query from multiple database partitions</p>
</li>
<li><p>Replicate tables from original database to a new database until replication lag is near 0</p>
</li>
<li><p>Pause activity on original database</p>
</li>
<li><p>Wait for databases to synchronize</p>
</li>
<li><p>Reroute query traffic to the new database</p>
</li>
<li><p>Resume activity</p>
</li>
</ol>
<h3 id="heading-1-preparing-client-application">1. Preparing client application</h3>
<p>They leveraged PgBouncer and created a separate PgBouncer services to virtually split traffic.</p>
<p>Partitioning the PgBouncer layer first would give clients leeway to route queries incorrectly.</p>
<p>They would be able to detect the routing mismatch, but since both PgBouncers have the same target database, the client would still successfully query data.</p>
<hr />
<p>Start state looks as follows</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725010003944/c2c3dfd6-1e77-4943-b72a-cd9e70f31c9d.webp" alt class="image--center mx-auto" /></p>
<p>State of the database after partitioning PgBouncer</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725010035118/92d8cd2b-42bd-497a-bd01-5fac590f5855.webp" alt class="image--center mx-auto" /></p>
<p>State of the database after partitioning data</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725010070349/94dcc413-07df-44f4-a471-1c4ce20b7117.webp" alt class="image--center mx-auto" /></p>
<p>Once they verified that applications are prepared with separate connections for each PgBouncer (and sending traffic appropriately), they’d proceed.</p>
<h3 id="heading-2-data-replication">2. Data Replication</h3>
<p>There are two ways to replicate data: Streaming Replication or Logical Replication.</p>
<p>They chose logical replication because it allows them to</p>
<ol>
<li><p>Port over a subset of tables, so they can start with a much smaller storage footprint in the destination database</p>
</li>
<li><p>Replicate to a database, which is running a different Postgres major version, meaning we can perform minimal-downtime major version upgrades with this tooling.</p>
</li>
<li><p>Set up reverse replication, which allows us to roll back the operation.</p>
</li>
</ol>
<p>Working with terabytes of production data, Logical Replication was quite slow because it copies rows in bulk but inefficiently updates indexes one row at a time.</p>
<p>So they removed indexes in the destination database and rebuild the indexes after the initial copying reducing the copy time to a matter of hours.</p>
<p>Modifications to the new database were also replicated back to the old database (via reverse replication stream), for the case they rolled back.</p>
<h3 id="heading-3-coordinating-query-rerouting">3. Coordinating Query Rerouting</h3>
<p>They performed sharding operation in two phases (partitioning PgBouncers, then data)</p>
<p>Overview of the operation:</p>
<ul>
<li><p>They stoped all relevant database traffic briefly in order for logical replication to synchronize the new database</p>
</li>
<li><p>PgBouncer paused new connections and revoked clients’ query privileges on the partitioned tables in the original database.</p>
</li>
<li><p>After a brief grace period, they canceled any remaining in flight queries.</p>
</li>
<li><p>With traffic paused, they used LSNs (Log Sequence Number) to determine if two databases were synchronized. They sample an LSN from original database and waited for the replica to replay past this LSN. At this point, the data is identical in both the original and the replica.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725010107138/3ee4ec50-f60b-4b63-ba4b-b0c7ad200be3.webp" alt class="image--center mx-auto" /></p>
<p>A visualization of our synchronization mechanism</p>
<hr />
<p>Post checking the replica is synchronized, they stoped replication and promote the replica to a new database.</p>
<p>Reverse replication is set up as previously mentioned. Then, they resume traffic in PgBouncer, but now the queries are routed to the new database.</p>
<p>A summary of the procedure</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725010204796/a3605161-7b00-4ab2-bf27-0e34a743d703.webp" alt class="image--center mx-auto" /></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>They observed a ~30 second period of partial availability impact (~2% of requests dropped).</p>
<p>Each database partition is operating with greatly increased headroom. Their largest partition has CPU utilization hovering ~10%</p>
<hr />
<p>Understanding the Foundational Principles is the key to Effective Learning!</p>
<p>Follow along to Improve System Design Skills.</p>
<hr />
<h2 id="heading-reference-and-image-credit">Reference and Image Credit</h2>
<ul>
<li><a target="_blank" href="https://www.figma.com/blog/how-figma-scaled-to-multiple-databases/">How Figma Scaled to multiple databases</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[From Spark to Ray: Amazon's $120MM/year Cost-Saving Journey]]></title><description><![CDATA[Amazon Business Data Technologies (BDT) Team moved EXABYTE scale jobs from Spark to this tech. 🤔
Cost saving of $120MM/year on EC2 on-demand R5 instance charges 🔥
Background
It started with migration from Oracle

To decouple storage and compute, th...]]></description><link>https://atech.guide/amazon-spark-to-ray-migration</link><guid isPermaLink="true">https://atech.guide/amazon-spark-to-ray-migration</guid><category><![CDATA[spark]]></category><category><![CDATA[ray ]]></category><category><![CDATA[System Design]]></category><category><![CDATA[System Architecture]]></category><dc:creator><![CDATA[Kamran Ali]]></dc:creator><pubDate>Wed, 28 Aug 2024 13:16:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724848571881/95eaecdf-9368-4b11-a5fa-db545b626c6e.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Amazon Business Data Technologies (BDT) Team moved EXABYTE scale jobs from Spark to this tech. 🤔</p>
<p>Cost saving of $120MM/year on EC2 on-demand R5 instance charges 🔥</p>
<h2 id="heading-background">Background</h2>
<p>It started with migration from Oracle</p>
<ul>
<li><p>To decouple storage and compute, they migrated over 50 PB of data from Oracle to S3 (storage) + Redshift / RDS / Hive / EMR (for compute)</p>
</li>
<li><p>Teams can now subscribe to S3-based table using their choice of analytics framework (e.g. Athena, Redshift, Spark, Flink etc) to run on-demand or scheduled queries.</p>
</li>
<li><p>They further built data cataloging metadata layers, data discovery services, job orchestration infrastructure, web service APIs and UIs, and finally released the minimum viable set of services they needed to replace Oracle.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724848641061/15864111-7cf1-44b0-af1b-93883e09da0a.png" alt class="image--center mx-auto" /></p>
<p>As all tables in their catalog composed of unbounded streams of S3 files, its the responsibility of each subscriber’s chosen compute framework to “merge,” all of the changes (inserts, updates, and deletes) at read time to yield the correct current table state.</p>
<h2 id="heading-problem-1">Problem 1</h2>
<p>With time, data has grown too large that "merge" operation started taking days or weeks to complete a merge, or they would just fail.</p>
<h2 id="heading-solution">Solution</h2>
<p>To solve this, BDT leveraged Spark on EMR to run the merge once and write back a read-optimized version of the table for other subscribers to use (copy-on-write)</p>
<p>They called this Spark job as Compactor</p>
<h2 id="heading-problem-2">Problem 2</h2>
<p>With time Amazon’s petabyte-scale data had grown to exabyte-scale.</p>
<p>Compaction jobs were exceeding their expected completion times, and had limited options to resolve performance issues as Spark abstracting away most of the low-level data processing details.</p>
<h2 id="heading-solution-1">Solution</h2>
<p>BDT Team did a PoC on Ray, with proper tuning they could compact 12X larger datasets than Spark, improve cost efficiency by 91%, and process 13X more data per hour</p>
<p>Factors that contributed to these results,</p>
<ul>
<li><p>Ray’s ability to reduce task orchestration and garbage collection overhead</p>
</li>
<li><p>Leverage zero-copy intranode object exchange during locality-aware shuffles</p>
</li>
<li><p>Better utilize cluster resources through fine-grained autoscaling.</p>
</li>
<li><p>Flexibility of Ray’s programming model, which let them hand-craft a distributed application specifically optimized to run compaction as efficiently as possible.</p>
</li>
</ul>
<p>They settled on an initial design for serverless job management using Ray on EC2 together with DynamoDB, SNS, SQS and S3 for durable job lifecycle tracking and management.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724848672717/269f439f-23d3-4dc8-8e7b-a7897fb965f8.png" alt class="image--center mx-auto" /></p>
<p>The solid lines of the primary workflow show the required steps needed to start and complete compaction jobs, while the dashed lines in the secondary workflow show the steps supporting job observability.</p>
<h3 id="heading-migration-of-spark-jobs-to-ray">Migration of Spark Jobs to Ray</h3>
<p>Initially they focused on migrating the tables that would yield the biggest impact first.</p>
<p>They targeted the largest ~1% of tables in their catalog, which accounted for ~40% of their overall Spark compaction cost and the vast majority of job failures.</p>
<h3 id="heading-shadow-testing">Shadow Testing</h3>
<p>They manually shadowed a subset of Spark compaction jobs on Ray by giving it the same input dataset as Spark.</p>
<p>They relied on their Ray-based data quality service to compare their respective outputs for equivalence.</p>
<p>Anything that didn’t pass DQ would be the target of a manual analysis, and either become a known/accepted difference to document or an issue to fix.</p>
<p>Lastly, they built a Data Reconciliation Service which compared the results of Spark and Ray-produced tables across multiple compute frameworks</p>
<p>Later they moved onto fully automated shadow compaction on Ray</p>
<p>This step required automatic 1:1 shadowing of all compaction jobs for any given table between Spark and Ray.</p>
<p>The purpose of this step was to get more direct comparisons with Spark, verify that Ray’s benefits held up across a wide variety of notoriously problematic tables, and to smoke out any latent corner-case issues that only appeared at scale.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724848736770/b545532d-d7af-4fc3-8ee8-76336cf95647.png" alt class="image--center mx-auto" /></p>
<p>To help avoid catastrophic failure, BDT built another service that let them dynamically switch individual table subscribers over from consuming the Apache Spark compactor’s output to Ray’s output.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>BDT team read over 20PiB/day of S3 data to compact across more than 1600 Ray jobs/day.</p>
<p>Ray has maintained a 100% on-time delivery rate with 82% better cost efficiency than Spark per GiB of S3 data compacted, which translates to $120MM/year on EC2 on-demand R5 instance charges.</p>
<p>#systemdesign #architecture #scalability</p>
<hr />
<p>Understanding the Foundational Principles is the key to Effective Learning!</p>
<p>Follow along to Improve System Design Skills.</p>
<h2 id="heading-reference-and-image-credits">Reference and Image Credits</h2>
<ul>
<li><a target="_blank" href="https://aws.amazon.com/blogs/opensource/amazons-exabyte-scale-migration-from-apache-spark-to-ray-on-amazon-ec2/">Amazon’s Exabyte-Scale Migration from Apache Spark to Ray on Amazon EC2</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[How Reddit Achieved 100k Reads/Sec for Media Metadata]]></title><description><![CDATA[Reddit used this database to handle ~100,000 Reads/sec with ~17ms (p99)👇
Use the proven techniques in your next System Design Interview 🔥
Background
Media metadata is classified as

Data on the post model e.g. video thumbnails, playback URLs, bitra...]]></description><link>https://atech.guide/how-reddit-achieved-100k-reads-persec-for-media-metadata</link><guid isPermaLink="true">https://atech.guide/how-reddit-achieved-100k-reads-persec-for-media-metadata</guid><category><![CDATA[reddit]]></category><category><![CDATA[System Design]]></category><category><![CDATA[scalability]]></category><category><![CDATA[Databases]]></category><dc:creator><![CDATA[Kamran Ali]]></dc:creator><pubDate>Mon, 26 Aug 2024 11:59:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724672326295/a6a10eb8-2bdd-4885-bd0b-299869e7aff5.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Reddit used this database to handle ~100,000 Reads/sec with ~17ms (p99)👇</p>
<p>Use the proven techniques in your next System Design Interview 🔥</p>
<h2 id="heading-background">Background</h2>
<p>Media metadata is classified as</p>
<ol>
<li><p>Data on the post model e.g. video thumbnails, playback URLs, bitrates etc</p>
</li>
<li><p>Metadata associated with the lifecycle of the media asset, e.g. processing state, encoding information, S3 file location etc.</p>
</li>
</ol>
<h2 id="heading-challenges">Challenges</h2>
<ol>
<li><p>Metadata distributed across multiple systems, resulting in inconsistent storage formats and varying query patterns.</p>
</li>
<li><p>Lack of proper mechanisms for auditing changes, analyzing content and categorizing metadata.</p>
</li>
</ol>
<h2 id="heading-functional-requirements">Functional Requirements</h2>
<ol>
<li><p>Move all existing media metadata into a Unified Storage.</p>
</li>
<li><p>Handle &gt;100,000 read requests per second with a very low latency</p>
</li>
<li><p>Data creation and updates have lower traffic compared to Reads, slightly higher latency is tolerable</p>
</li>
</ol>
<h2 id="heading-solution">Solution</h2>
<p>Reddit opted for AWS Aurora Postgres over Cassandra due to the challenges associated with ad-hoc queries for debugging in Cassandra, and the potential risk of some data not being denormalized and unsearchable.</p>
<h3 id="heading-1-abstraction">1. Abstraction</h3>
<p>Reads and writes to database are abstracted behind APIs.</p>
<h3 id="heading-2-data-migration">2. Data Migration</h3>
<p>Migration Process</p>
<ol>
<li><p>Enabling dual writes into our metadata APIs from clients of media metadata.</p>
</li>
<li><p>Backfill data from older databases to our metadata store</p>
</li>
<li><p>Enable dual reads on media metadata from our service clients</p>
</li>
<li><p>Monitor data comparisons for each read and fix data gaps</p>
</li>
<li><p>Slowly ramp up the read traffic to our database to make sure it can scale</p>
</li>
</ol>
<p>Scenarios leading to data differences</p>
<ol>
<li><p>Data transformation bugs in the service layer.</p>
</li>
<li><p>Writes into the new metadata store failed, while writes into the source database succeed</p>
</li>
<li><p>Race condition when data from the backfill process in step 2 overwrites newer data from service writes in step</p>
</li>
</ol>
<p>How to fix Data Differences</p>
<ul>
<li><p>Kafka consumer was set up to listen to a stream of data change events from the source database.</p>
</li>
<li><p>The consumer then performs data validation with the media metadata store.</p>
</li>
<li><p>If any data inconsistencies are detected, the consumer reports the differences to another data table in the database.</p>
</li>
<li><p>This allows engineers to query and analyze the data issues.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724673335392/396e24a1-c4f7-4d5a-9a41-8600142f24e6.webp" alt="Reddit Kafka solution to fix Data Differences" class="image--center mx-auto" /></p>
<h3 id="heading-3-scaling-strategies">3. Scaling Strategies</h3>
<p>Media metadata was optimised for reads.</p>
<p>At 100k requests per second, read latency of 2.6 ms at p50, 4.7 ms at p90, and 17 ms at p99.</p>
<p>which is 50% faster than our previous data system</p>
<h4 id="heading-3a-table-partitioning">3a Table Partitioning</h4>
<p>Size of media metadata will reach roughly 50 TB by the year 2030.</p>
<p>To address this they implemented table partitioning in Postgres using a partition management extension called pg_partman</p>
<p>And choose range-based partitioning (post_id as partition key) instead of hash-based partitioning.</p>
<p>As <em>post_id</em> increases monotonically with time, range-based partitioning allows to partition the table by distinct time periods.</p>
<p>This approach offers two important advantages</p>
<ol>
<li><p>Most read operations are for recently created posts, allowing the Postgres engine to cache the indexes of the most recent partitions, minimizing disk I/O. Hot working set remains in memory, enhancing query performance.</p>
</li>
<li><p>Many batch read requests were on multiple post IDs from the same time period. Hence, likely the data is retrieved from a single partition.</p>
</li>
</ol>
<h4 id="heading-3b-jsonb">3b. JSONB</h4>
<p>Storing the media metadata as serialized JSONB format for Reads, effectively transformed the table into a NoSQL-like key-value pair.</p>
<p>Benefits</p>
<ul>
<li><p>It efficiently fetches all the fields together using a single key</p>
</li>
<li><p>It eliminates the need for joins, simplifying the querying logic</p>
</li>
</ul>
<p>Which other Database you will choose to optimise for Reads?</p>
<hr />
<p>Understanding the Foundational Principles is the key to effective learning!</p>
<p>Follow along to Improve System Design Skills.</p>
<h2 id="heading-reference-and-image-credits">Reference and Image Credits</h2>
<ul>
<li><a target="_blank" href="https://www.reddit.com/r/RedditEng/comments/1avlywv/the_reddit_media_metadata_store/">https://www.reddit.com/r/RedditEng/comments/1avlywv/the_reddit_media_metadata_store/</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[How Discord Stores Trillions of Messages]]></title><description><![CDATA[Discord shared its journey from storing 1,000,000,000 (Billion) messages to 1,000,000,000,000 (Trillion) messages
Issues faced when Cassandra Cluster grew from 12 Nodes (in 2017) to 177 Nodes (in 2022)
Problems
In 2017, 12 Cassandra nodes were storin...]]></description><link>https://atech.guide/how-discord-stores-trillions-of-messages</link><guid isPermaLink="true">https://atech.guide/how-discord-stores-trillions-of-messages</guid><category><![CDATA[scalability]]></category><category><![CDATA[Cassandra]]></category><category><![CDATA[scylladb]]></category><dc:creator><![CDATA[Kamran Ali]]></dc:creator><pubDate>Mon, 26 Aug 2024 04:43:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724553601322/7a73e941-034a-46bb-97ee-def94c4cb554.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Discord shared its journey from storing 1,000,000,000 (Billion) messages to 1,000,000,000,000 (Trillion) messages</p>
<p>Issues faced when Cassandra Cluster grew from 12 Nodes (in 2017) to 177 Nodes (in 2022)</p>
<h2 id="heading-problems">Problems</h2>
<p>In 2017, 12 Cassandra nodes were storing Billions of messages which grew to 177 nodes storing Trillions of messages.</p>
<p>It became a high-toil system, with the following issues</p>
<ul>
<li><p>Unpredictable Latencies</p>
</li>
<li><p>The on-call team frequently gets paged for database issues</p>
</li>
<li><p>Multiple Concurrent Reads and Uneven Discord Server sizes <em>hot-spotting</em> a partition, (given Read in Cassandra are more expensive than Writes) affecting latency across the entire cluster</p>
</li>
<li><p>Compactions were falling behind creating cascading latency as a node tried to compact</p>
</li>
<li><p>To avoid GC pauses (which would cause significant latency spikes) a large amount of time was spent tuning the JVM’s garbage collector and heap settings</p>
</li>
</ul>
<h2 id="heading-architecture-changes">Architecture Changes</h2>
<h3 id="heading-fixing-hot-partitions">Fixing Hot Partitions</h3>
<ul>
<li><p>Enabling <em>Request Coalescing</em> (Query DB once for multiple requests for the same data) by building Data Services in Rust, as intermediary services that sit between API and database clusters containing roughly one gRPC endpoint per database query and no business logic</p>
</li>
<li><p>Building efficient consistent hash-based routing to the data services which routes requests for the same channel to the same instance of the service</p>
</li>
</ul>
<h3 id="heading-migration-to-scylla-db">Migration to Scylla DB</h3>
<ul>
<li><p>The data service library was extended to perform large-scale data migrations which read token ranges from a database, checkpoints them locally via SQLite, and then firehoses them into ScyllaDB</p>
</li>
<li><p>The estimated time was 9 days with a speed of 3.2 million per second</p>
</li>
<li><p>With an additional hiccup of intervention to compact gigantic ranges of tombstones (that were never compacted in Cassandra), migration was complete</p>
</li>
<li><p>Automated data validation was performed by sending a small percentage of reads to both databases and comparing the results</p>
</li>
</ul>
<h3 id="heading-post-migration">Post Migration</h3>
<ul>
<li><p>Decrease in Node count from 177 Cassandra Nodes to 72 ScyllaDB nodes</p>
</li>
<li><p>Each ScyllaDB node has 9 TB of disk space, up from the average of 4 TB per Cassandra node</p>
</li>
<li><p>Improved Tail latencies from p99 of between 40-125ms on Cassandra to 15ms p99 on ScyllaDB</p>
</li>
<li><p>Improved message insert performance from 5-70ms p99 on Cassandra, to a steady 5ms p99 on ScyllaDB</p>
</li>
</ul>
<h2 id="heading-reference-and-image-credit">Reference and Image Credit</h2>
<ul>
<li><a target="_blank" href="http://discord.com/blog/how-discord-stores-trillions-of-messages">discord.com/blog/how-discord-stores-trillions-of-messages</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Uber's strategy for a Bold Move to GCP ☁️]]></title><description><![CDATA[Uber's moved Batch Analytics and ML training stack to GCP
They hosts >1,000,000,000,000,000,000 byte of data across tens of thousands of servers. 🔥

Uber, managing a mind-boggling 1 exabyte of data, has strategically migrated its Batch Analytics and...]]></description><link>https://atech.guide/ubers-strategy-for-a-bold-move-to-gcp</link><guid isPermaLink="true">https://atech.guide/ubers-strategy-for-a-bold-move-to-gcp</guid><category><![CDATA[migration]]></category><category><![CDATA[GCP]]></category><category><![CDATA[data-engineering]]></category><dc:creator><![CDATA[Kamran Ali]]></dc:creator><pubDate>Sat, 24 Aug 2024 17:02:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724553100105/0ca5c0e6-8e5b-42e1-bf54-ed625191b973.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Uber's moved Batch Analytics and ML training stack to GCP</strong></p>
<p>They hosts &gt;1,000,000,000,000,000,000 byte of data across tens of thousands of servers. 🔥</p>
<hr />
<p>Uber, managing a mind-boggling 1 exabyte of data, has strategically migrated its Batch Analytics and ML training stack to Google Cloud Platform (GCP).</p>
<p>Here's a breakdown of their strategy.</p>
<h2 id="heading-key-decisions"><strong>Key Decisions</strong></h2>
<ol>
<li><p>Adopted GCP's object store for storage</p>
</li>
<li><p>Migrate the Data Stack to GCP's IaaS (Infrastructure as a Service)</p>
</li>
</ol>
<p>This 'lift and shift' approach allowed for a rapid migration with minimal disruption, as they could replicate their existing setup on GCP's IaaS.</p>
<p>Future plans include leveraging GCP's PaaS offerings (Dataproc, BigQuery) for even more elasticity and performance.</p>
<h2 id="heading-migration-principles">Migration Principles</h2>
<h3 id="heading-1-seamless-data-access-for-users">1. Seamless Data Access for Users</h3>
<ul>
<li><p>IaaS prevented users from needing to modify their artifacts or services.</p>
</li>
<li><p>Cloud storage connector ensured HDFS compatibility.</p>
</li>
<li><p>They standardized HDFS clients to abstract the on-prem HDFS implementation specifics. The standardized HDFS client will be modified to translate the HDFS paths to Object store based paths via a “Path Translation Service.”</p>
</li>
</ul>
<h3 id="heading-2-enhanced-data-access-proxies">2. Enhanced Data Access Proxies</h3>
<p>Abstracted the underlying compute clusters for Presto, Spark, and Hive.</p>
<h3 id="heading-3-cloud-agnostic-infrastructure">3. Cloud-Agnostic Infrastructure</h3>
<p>Uber's container environment and deployment tools were already built to be cloud-agnostic, making the expansion to GCP smoother.</p>
<h3 id="heading-4-proactive-data-governance">4. Proactive Data Governance</h3>
<p>Focused on supporting selected, approved GCP data services to avoid future complexities.</p>
<h2 id="heading-reference-and-image-credit">Reference and Image Credit</h2>
<ul>
<li><a target="_blank" href="https://www.uber.com/en-AU/blog/modernizing-ubers-data-infrastructure-with-gcp/">Modernizing-ubers-data-infrastructure-with-gcp</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[How to Create Python Projects Using Poetry: A Beginner's Guide (2024 Edition)]]></title><description><![CDATA[Introduction
Are you tired of wrestling with Python project dependencies, virtual environments, and the complexities of packaging?
Let's revisit the challenges that often plague Python projects:
👉 Inconsistent Environments: Have you ever run into a ...]]></description><link>https://atech.guide/python-poetry-8-steps-beginner-guide</link><guid isPermaLink="true">https://atech.guide/python-poetry-8-steps-beginner-guide</guid><category><![CDATA[python-poetry]]></category><category><![CDATA[python projects]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[python beginner]]></category><dc:creator><![CDATA[Kamran Ali]]></dc:creator><pubDate>Mon, 24 Jun 2024 13:51:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1718524281552/ffbc1294-a0fb-4959-ad77-d54b2df5387a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Are you tired of wrestling with Python project dependencies, virtual environments, and the complexities of packaging?</p>
<p>Let's revisit the challenges that often plague Python projects:</p>
<p>👉 <strong>Inconsistent Environments:</strong> Have you ever run into a "works on my machine" scenario? Mismatched dependencies can cause headaches when code behaves differently across environments.</p>
<p>👉 <strong>Version Conflicts:</strong> The dreaded dependency hell – when incompatible versions clash and break your code.</p>
<p>👉 <strong>Manual Tracking:</strong> Keeping track of every package and its version can quickly become overwhelming.</p>
<p>👉 <strong>Complex Packaging:</strong> Preparing your project for distribution can involve a series of manual steps.</p>
<p>Imagine a world where setting up your Python projects is as easy as pie.</p>
<p>Welcome to the world of <strong>Poetry</strong>!</p>
<p>Poetry addresses these issues head-on, by providing a streamlined and efficient way to handle dependencies, package projects etc making your Python projects more reliable and easier to manage.</p>
<p>In this beginner-friendly tutorial, we'll guide you through how to create Python projects using Poetry, step by step.</p>
<p>Everything you need to know.</p>
<h2 id="heading-step-1-installing-poetry-via-official-installer">Step 1: Installing Poetry (via Official Installer)</h2>
<p>To embark on our Poetry journey, we need to install it.</p>
<p>The recommended way is via the official installer.</p>
<p>You can find detailed instructions on the <a target="_blank" href="https://python-poetry.org/docs/#installing-with-the-official-installer">Poetry installation page</a>.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># For Linux, macOS, Windows (WSL)</span>

curl -sSL https://install.python-poetry.org | python3 -
</code></pre>
<h2 id="heading-step-2a-creating-your-first-python-project-with-poetry">Step 2a: Creating Your First Python Project with Poetry</h2>
<p>Once Poetry is installed, let's create a new Python project using Poetry's intuitive <code>new</code> command:</p>
<pre><code class="lang-bash">poetry new my-awesome-project
</code></pre>
<h3 id="heading-project-structure">Project Structure</h3>
<p>After running the command, Poetry generates a project structure that looks like this:</p>
<pre><code class="lang-bash">my-awesome-project/
├── pyproject.toml   
├── README.md 
├── my_awesome_project/
│   └── __init__.py
├── tests/
    └── __init__.py
</code></pre>
<ul>
<li><p><code>pyproject.toml</code>: The heart of your project! This file contains project metadata, dependencies, and scripts.</p>
</li>
<li><p><code>README.md</code>: A place to describe your project in markdown format.</p>
</li>
<li><p><code>my_awesome_project/</code>: Your project's source code directory.</p>
</li>
<li><p><code>tests/</code>: A dedicated folder for your project's tests.</p>
</li>
</ul>
<h2 id="heading-step-2b-breathing-poetry-into-existing-projects">Step 2b: Breathing Poetry into Existing Projects</h2>
<p>If you already have a Python project you want to manage with Poetry, it's easy to migrate.</p>
<p>Navigate to your project's root directory and run:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> pre-existing-project
poetry init
</code></pre>
<p>Poetry will guide you through creating a <code>pyproject.toml</code> file, asking questions about your project's name, description, and dependencies.</p>
<h2 id="heading-step-2c-demystifying-pyprojecttoml">Step 2c: Demystifying pyproject.toml</h2>
<p>The <code>pyproject.toml</code> file generated via <code>poetry new my-awesome-project</code> command includes the following components:</p>
<pre><code class="lang-ini"><span class="hljs-section">[tool.poetry]</span>
<span class="hljs-attr">name</span> = <span class="hljs-string">"my-awesome-project"</span>
<span class="hljs-attr">version</span> = <span class="hljs-string">"0.1.0"</span>
<span class="hljs-attr">description</span> = <span class="hljs-string">""</span>
<span class="hljs-attr">authors</span> = [<span class="hljs-string">"Kamran Ali &lt;kamranalinitb@gmail.com&gt;"</span>]
<span class="hljs-attr">readme</span> = <span class="hljs-string">"README.md"</span>

<span class="hljs-section">[tool.poetry.dependencies]</span>
<span class="hljs-attr">python</span> = <span class="hljs-string">"^3.12"</span>


<span class="hljs-section">[build-system]</span>
<span class="hljs-attr">requires</span> = [<span class="hljs-string">"poetry-core"</span>]
<span class="hljs-attr">build-backend</span> = <span class="hljs-string">"poetry.core.masonry.api"</span>
</code></pre>
<ul>
<li><p><code>[tool.poetry]</code>: Contains the main metadata for your project such as <code>name</code>, <code>version</code>, <code>description</code>, <code>authors</code>.</p>
</li>
<li><p><code>[tool.poetry.dependencies]</code>: Lists all the dependencies required to run your project.</p>
</li>
<li><p><code>[build-system]</code>: Specifies the build system requirements, including <code>requires</code> and <code>build-backend</code> which are necessary for building your project.</p>
</li>
</ul>
<h2 id="heading-step-3-poetrys-operating-modes">Step 3: Poetry's Operating Modes</h2>
<p>Poetry offers two operating modes:</p>
<ul>
<li><p><strong>Package Mode: (default)</strong> Use this mode, if you want to package your project into an sdist or a wheel and publish it to a package index</p>
<ul>
<li><p>Metadata such as name and version which are required for packaging, are mandatory.</p>
</li>
<li><p>The project itself will be installed in editable mode when running <code>poetry install</code>.</p>
</li>
</ul>
</li>
<li><p><strong>Non-package Mode:</strong> Use this mode, If you want to use Poetry only for dependency management</p>
</li>
</ul>
<p>We can disable package mode via</p>
<pre><code class="lang-bash">[tool.poetry]
package-mode = <span class="hljs-literal">false</span>
</code></pre>
<h2 id="heading-step-4-virtual-environments-made-easy-with-poetry">Step 4: Virtual Environments Made Easy with Poetry</h2>
<p>Poetry manages virtual environments automatically.</p>
<p>By default, they are created in a central location</p>
<p>But you can configure Poetry to create virtual environments within your project directory by setting <code>virtualenvs.in-project</code> Config.</p>
<p>Having virtual environments within the project directory simplifies project management and ensures all project-related files are in one place.</p>
<p>Secondly, tools like vscode can detect the virtual environment of our project</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Enable virtualenvs.in-project via following command</span>

poetry config virtualenvs.in-project <span class="hljs-literal">true</span>

<span class="hljs-comment"># To list poetry configs</span>
poetry config --list
</code></pre>
<h3 id="heading-virtual-environment-commands">Virtual Environment Commands</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Command</td><td>Short Description</td></tr>
</thead>
<tbody>
<tr>
<td><code>poetry shell</code></td><td>Activates the virtual environment</td></tr>
<tr>
<td><code>deactivate</code></td><td>Deactivates the virtual environment</td></tr>
<tr>
<td><code>poetry env list</code></td><td>Lists all virtual environments</td></tr>
</tbody>
</table>
</div><h3 id="heading-external-virtual-environment-management">External Virtual Environment Management</h3>
<p>Poetry can also work with external virtual environments. Just activate the external virtual environment before running Poetry commands.</p>
<h2 id="heading-step-5-mastering-dependency-management-with-poetry">Step 5: Mastering Dependency Management with Poetry</h2>
<p>Dependencies are the building blocks of any Python project. Poetry makes adding, removing, and updating them a breeze.</p>
<h3 id="heading-adding-and-removing-dependencies">Adding and Removing Dependencies</h3>
<p>To add a dependency:</p>
<pre><code class="lang-bash">poetry add &lt;package&gt;
</code></pre>
<p>To remove a dependency:</p>
<pre><code class="lang-bash">poetry remove &lt;package&gt;
</code></pre>
<h3 id="heading-showing-and-updating-packages">Showing and Updating Packages</h3>
<p>To show installed packages:</p>
<pre><code class="lang-bash">poetry show
</code></pre>
<p>To update packages:</p>
<pre><code class="lang-bash">poetry update

<span class="hljs-comment"># Update specific packages </span>
poetry update package_1 package_2
</code></pre>
<h3 id="heading-poetry-dependency-management-commands">Poetry Dependency Management Commands</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Command</td><td>Example</td><td>Description</td></tr>
</thead>
<tbody>
<tr>
<td><code>poetry add</code></td><td><code>poetry add requests</code></td><td>Adds a new dependency</td></tr>
<tr>
<td><code>poetry remove</code></td><td><code>poetry remove requests</code></td><td>Removes a dependency</td></tr>
<tr>
<td><code>poetry show</code></td><td><code>poetry show -t</code></td><td>Shows installed packages</td></tr>
<tr>
<td><code>poetry update</code></td><td><code>poetry update</code></td><td>Updates all dependencies</td></tr>
<tr>
<td><code>poetry install</code></td><td><code>poetry install</code></td><td>Installs dependencies defined in pyproject.toml file</td></tr>
</tbody>
</table>
</div><h3 id="heading-the-importance-of-poetrylock">The Importance of <code>poetry.lock</code></h3>
<p>The <code>poetry.lock</code> file is your project's snapshot of dependencies and their exact versions.</p>
<p>It ensures that everyone working on your project has the same environment preventing surprises down the road.</p>
<h2 id="heading-step-6-dependency-groups">Step 6: Dependency Groups</h2>
<p>Poetry introduces dependency groups, a powerful feature for organizing your project's dependencies logically based on their purpose.</p>
<p>You can think of dependency groups as <strong>labels</strong> associated with your dependencies</p>
<p>Common groups include <code>main</code> and <code>test</code></p>
<h3 id="heading-creating-a-test-group">Creating a Test Group</h3>
<pre><code class="lang-bash">poetry add --group &lt;group&gt; &lt;package&gt;

poetry add --group <span class="hljs-built_in">test</span> pytest
</code></pre>
<p>The above command will create following section in pyproject.toml</p>
<pre><code class="lang-toml">
<span class="hljs-section">[tool.poetry.group.test.dependencies]</span>
<span class="hljs-attr">pytest</span> = <span class="hljs-string">"^8.2.2"</span>
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">The dependencies declared in <code>tool.poetry.dependencies</code> are part of an implicit <code>main</code> group.</div>
</div>

<h3 id="heading-creating-optional-groups">Creating Optional Groups</h3>
<p>Optional groups let you define dependencies that are not always required</p>
<p>To create an optional group:</p>
<pre><code class="lang-ini"><span class="hljs-section">[tool.poetry.group.docs]</span> <span class="hljs-comment"># Marking "docs" group as Optional</span>
<span class="hljs-attr">optional</span> = <span class="hljs-literal">true</span>

<span class="hljs-section">[tool.poetry.group.docs.dependencies]</span>
<span class="hljs-attr">mkdocs</span> = <span class="hljs-string">"*"</span>
</code></pre>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Flags</td><td>Example</td><td>Description</td></tr>
</thead>
<tbody>
<tr>
<td><code>--with</code></td><td><code>poetry install --with docs</code></td><td>Optional groups can be installed in addition to the <strong>default</strong> dependencies by using the <code>--with</code> option of the <code>install</code>command.</td></tr>
<tr>
<td><code>--without</code></td><td><code>poetry install --without test,docs</code></td><td>To <strong>exclude</strong> one or more groups we can use <code>--without</code> option</td></tr>
<tr>
<td><code>--only</code></td><td><code>poetry install --only docs</code></td><td>If we want to install <strong>only specific groups</strong> of dependencies without installing the default set of dependencies use the <code>--only</code> option.</td></tr>
</tbody>
</table>
</div><h2 id="heading-step-7-packaging-your-project-with-poetry">Step 7: Packaging Your Project with Poetry</h2>
<p>Ready to share your masterpiece with the world?</p>
<p>Poetry makes packaging a breeze</p>
<p>To build your project:</p>
<pre><code class="lang-bash">poetry build
</code></pre>
<p>This command creates both a source distribution (<code>.tar.gz</code>) and a wheel (<code>.whl</code>) in the <code>dist/</code> directory, ready for installation.</p>
<p>To create only wheel, use following command</p>
<pre><code class="lang-bash">poetry build -f wheel
</code></pre>
<h2 id="heading-step-8-publishing-to-pypi-or-private-repositories">Step 8: Publishing to PyPI or Private Repositories</h2>
<p>Poetry streamlines publishing your package to the Python Package Index (PyPI):</p>
<p>To publish your package:</p>
<pre><code class="lang-bash">poetry publish
</code></pre>
<p>To publish to a private repository, you need to configure the repository URL:</p>
<pre><code class="lang-bash">poetry config repositories.&lt;repo-name&gt; &lt;repo-url&gt;
</code></pre>
<p>Then publish using:</p>
<pre><code class="lang-bash">poetry publish -r &lt;repo-name&gt;
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Python Poetry empowers you to create, manage, and share your Python projects with confidence.</p>
<p>Say goodbye to dependency nightmares and hello to a streamlined development workflow.</p>
<p>From installation to publication, Poetry's intuitive interface and powerful features make it an indispensable tool for beginners and experienced developers alike.</p>
<p>So, why not give Poetry a try for your next Python adventure? You might just find yourself wondering how you ever managed without it.</p>
<p>Are you ready to start your next Python project with Poetry?</p>
<h2 id="heading-reference">Reference</h2>
<ul>
<li><p>https://python-poetry.org/docs/basic-usage/</p>
</li>
<li><p>https://python-poetry.org/docs/managing-dependencies/</p>
</li>
<li><p>https://python-poetry.org/docs/libraries/</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Installing Python "The Right Way" on a MacBook for Beginners (2024 Edition)]]></title><description><![CDATA[Can You Relate?
👉 You are facing frustrations with version conflicts between different projects requiring specific Python versions?
👉 You are concerned about environment pollution caused by globally installing various packages?
👉 You are strugglin...]]></description><link>https://atech.guide/install-python-on-mac-beginner-step-by-step-guide</link><guid isPermaLink="true">https://atech.guide/install-python-on-mac-beginner-step-by-step-guide</guid><category><![CDATA[Python 3]]></category><category><![CDATA[python beginner]]></category><category><![CDATA[Python]]></category><category><![CDATA[python-install]]></category><dc:creator><![CDATA[Kamran Ali]]></dc:creator><pubDate>Fri, 31 May 2024 15:34:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1710206419633/bdd5e5aa-de34-4ec9-8dfe-3f69333ecb46.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-can-you-relate">Can You Relate?</h2>
<p>👉 You are facing frustrations with <strong>version conflicts</strong> between different projects requiring specific Python versions?</p>
<p>👉 You are concerned about <strong>environment pollution</strong> caused by globally installing various packages?</p>
<p>👉 You are struggling to <strong>replicate</strong> your development environment on another machine due to dependency issues?</p>
<p>👉 You are worried about the risk of <strong>breaking your system</strong> during package installation or uninstallation?</p>
<p>If you answered yes to any of these, this guide is here to help!</p>
<p>Let's Begin!</p>
<h2 id="heading-pre-requisites">Pre Requisites</h2>
<ul>
<li><p>MacBook</p>
</li>
<li><p>Homebrew Installation</p>
</li>
</ul>
<h3 id="heading-step-1-installing-homebrew-if-not-already-installed">Step 1: Installing Homebrew (if not already installed)</h3>
<p>Before we dive into Python installation, let's install <strong>Homebrew</strong>.</p>
<p>It's a package manager that makes installing software on your Mac a breeze.</p>
<p>Open your terminal and run the following command:</p>
<pre><code class="lang-bash">/bin/bash -c <span class="hljs-string">"<span class="hljs-subst">$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)</span>"</span>
</code></pre>
<h3 id="heading-step-2-installing-pyenv">Step 2: Installing PyEnv</h3>
<ul>
<li><p>This tool helps in installing and easily switching between multiple versions of Python.</p>
</li>
<li><p>We can set <em>Global Python</em> version on a per-user basis.</p>
</li>
<li><p>We can set <em>Per Project</em> Python versions.</p>
</li>
</ul>
<h4 id="heading-2a-installing-pyenv">2a Installing PyEnv</h4>
<p>Run <code>brew install pyenv</code> to install PyEnv.</p>
<p>Post-installation, run <code>pyenv --version</code> to confirm the installation.</p>
<p>Next, we need to set up our shell environment for Pyenv.</p>
<p>For zsh Shell, run the following commands:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">'export PYENV_ROOT="$HOME/.pyenv"'</span> &gt;&gt; ~/.zshrc
<span class="hljs-built_in">echo</span> <span class="hljs-string">'[[ -d $PYENV_ROOT/bin ]] &amp;&amp; export PATH="$PYENV_ROOT/bin:$PATH"'</span> &gt;&gt; ~/.zshrc
<span class="hljs-built_in">echo</span> <span class="hljs-string">'eval "$(pyenv init -)"'</span> &gt;&gt; ~/.zshrc
</code></pre>
<p>For other shells, refer <a target="_blank" href="https://github.com/pyenv/pyenv#set-up-your-shell-environment-for-pyenv">this</a> section</p>
<h4 id="heading-2b-pyenv-useful-commands">2b PyEnv Useful Commands</h4>
<p><strong>To install a version of Python</strong></p>
<ol>
<li><p>To do that, first, we need to check all the available versions of Python via <code>pyenv install --list</code>.</p>
</li>
<li><p>Run <code>pyenv install &lt;version&gt;</code> to install a particular version.</p>
</li>
<li><p>Example</p>
<ol>
<li><p><code>pyenv install 3.11.8</code></p>
</li>
<li><p><code>pyenv install 3.10.13</code></p>
</li>
</ol>
</li>
</ol>
<p>Let's install both of them</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">🦂</div>
<div data-node-type="callout-text">Error Resolution</div>
</div>

<p>If you see below error while installing 3.11.8</p>
<pre><code class="lang-plaintext">Traceback (most recent call last):

  File "&lt;string&gt;", line 1, in &lt;module&gt;In

  File "/Users/atech-guide/.pyenv/versions/3.11.8/lib/python3.11/lzma.py", line 27, in &lt;module&gt;
tppl
    from _lzma import *

ModuleNotFoundError: No module named '_lzma'
</code></pre>
<p>As solution, do the following</p>
<ul>
<li><p>Install xz =&gt; brew install xz</p>
</li>
<li><p>un-install Python =&gt; pyenv uninstall 3.11.8</p>
</li>
<li><p>reinstall Python =&gt; pyenv install 3.11.8</p>
</li>
</ul>
<p>Post successful installation, let's list the Python versions via <code>pyenv versions</code>, we see the following:</p>
<pre><code class="lang-bash">atech.guide@macbook-air-m1 ~ % pyenv versions
* system (<span class="hljs-built_in">set</span> by /Users/atech-guide/.pyenv/version)
  3.10.13
  3.11.8
</code></pre>
<p>Where <code>system</code> represents the Python that comes with MacBook.</p>
<h4 id="heading-to-use-a-version-of-python-in-the-current-folder">To Use a version of Python in the current Folder</h4>
<p>Run <code>pyenv local &lt;version&gt;</code></p>
<h4 id="heading-to-set-a-version-of-python-globally">To set a version of Python Globally</h4>
<p>Run <code>pyenv global &lt;version&gt;</code></p>
<p>E.g. <code>pyenv global 3.10.13</code></p>
<h4 id="heading-to-delete-a-version-of-python">To delete a version of Python</h4>
<p>Run <code>pyenv uninstall &lt;version&gt;</code></p>
<p>E.g. <code>pyenv uninstall 3.10.13</code></p>
<h4 id="heading-2c-pyenv-example">2c PyEnv Example</h4>
<p>Let's create a folder named <code>python_projects</code> .</p>
<p>Under it let's create two example projects, <code>example_python_project_1</code> and <code>example_python_project_2</code> .</p>
<p>At end, we have a folder structure as follows</p>
<pre><code class="lang-bash">atech.guide@macbook-air-m1 python_projects % tree
.
├── example_python_project_1
└── example_python_project_2
</code></pre>
<p>Under each project sub folder, lets use different versions of python by running</p>
<ul>
<li><p><code>pyenv local 3.11.8</code> for example_python_project_1</p>
</li>
<li><p><code>pyenv local 3.10.13</code> for example_python_project_2</p>
</li>
</ul>
<p>If we check the python versions under both the sub folders (via <code>python --version</code>) we will see different versions</p>
<pre><code class="lang-bash">atech.guide@macbook-air-m1 python_projects % <span class="hljs-built_in">cd</span> example_python_project_1
atech.guide@macbook-air-m1 example_python_project_1 % pyenv <span class="hljs-built_in">local</span> 3.11.8
atech.guide@macbook-air-m1 example_python_project_1 % python --version
Python 3.11.8

atech.guide@macbook-air-m1 example_python_project_1 % <span class="hljs-built_in">cd</span> ../example_python_project_2

atech.guide@macbook-air-m1 example_python_project_2 % pyenv <span class="hljs-built_in">local</span> 3.10.13      
atech.guide@macbook-air-m1 example_python_project_2 % python --version
Python 3.10.13
</code></pre>
<h4 id="heading-2d-pyenv-command-table">2d PyEnv Command Table</h4>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Action</td><td>Command</td></tr>
</thead>
<tbody>
<tr>
<td>To check versions and which python is activated</td><td><code>pyenv versions</code></td></tr>
<tr>
<td>To check Available versions</td><td><code>pyenv install --list</code></td></tr>
<tr>
<td>To install a version</td><td><code>pyenv install 3.11.8</code></td></tr>
<tr>
<td>Where is python installed</td><td><code>ls ~/.pyenv/versions/</code></td></tr>
<tr>
<td>Uninstalling Python</td><td><code>pyenv uninstall 3.10.5</code></td></tr>
<tr>
<td>Setting Global Python</td><td><code>pyenv global 3.10.5</code></td></tr>
<tr>
<td>Setting Local Python</td><td><code>pyenv local 2.7.15</code></td></tr>
<tr>
<td>Which python is activated in pyenv</td><td><code>pyenv which python</code></td></tr>
</tbody>
</table>
</div><p>This solves one part of the problem.</p>
<p>Another part is we need to create Isolated Environments for each Python Project.</p>
<p>For that, we will need another tool.</p>
<h3 id="heading-step-3-pyenv-virtualenv">Step 3 PyEnv Virtualenv</h3>
<ul>
<li>It is a PyEnv plugin that provides features to manage virtualenvs for Python.</li>
</ul>
<h4 id="heading-3a-installing-pyenv-virtualenv">3a Installing PyEnv Virtualenv</h4>
<p>Run <code>brew install pyenv-virtualenv</code> to install PyEnv</p>
<p>Next, we need to set up our shell environment for Pyenv Virtualenv.</p>
<p>For zsh Shell, run <code>echo 'eval "$(pyenv virtualenv-init -)"' &gt;&gt; ~/.zshrc</code>.</p>
<h4 id="heading-3b-pyenv-virtualenv-useful-commands">3b PyEnv Virtualenv Useful Commands</h4>
<h4 id="heading-to-create-a-virtual-env">To create a virtual env</h4>
<p>Run <code>pyenv virtualenv &lt;python_version&gt; &lt;environment_name&gt;</code>.</p>
<h4 id="heading-to-use-virtual-env">To use virtual env</h4>
<p>Run <code>pyenv local &lt;my-virtual-env&gt;</code></p>
<h4 id="heading-to-list-virtual-env">To List virtual env</h4>
<p>Run <code>pyenv virtualenvs</code></p>
<h4 id="heading-to-delete-virtual-env">To delete virtual env</h4>
<p>Run <code>pyenv virtualenv-delete &lt;my-virtual-env&gt;</code></p>
<p>E.g. <code>pyenv virtualenv-delete python_project-3.11</code></p>
<h4 id="heading-3c-pyenv-virtualenv-example">3c PyEnv Virtualenv Example</h4>
<p>Before Creating Virtual environment</p>
<pre><code class="lang-bash">atech.guide@macbook-air-m1 ~ % pyenv versions
* system (<span class="hljs-built_in">set</span> by /Users/atech-guide/.pyenv/version)
  3.10.13
  3.11.8
</code></pre>
<p>Creating a Virtual Environment -&gt; <code>pyenv virtualenv 3.11.8 example_python_project_1</code></p>
<pre><code class="lang-bash">atech.guide@macbook-air-m1 ~ % pyenv virtualenv 3.11.8 example_python_project_1 
atech.guide@macbook-air-m1 ~ % pyenv versions
* system (<span class="hljs-built_in">set</span> by /Users/atech-guide/.pyenv/version)
  3.10.13
  3.11.8
  3.11.8/envs/example_python_project_1
  example_python_project_1 --&gt; /Users/atech-guide/.pyenv/versions/3.11.8/envs/example_python_project_1
</code></pre>
<p>Where <code>3.11.8/envs/example_python_project_1</code> is virtual env and <code>example_python_project_1</code> is Symlink</p>
<h4 id="heading-3d-pyenv-virtualenv-command-table">3d PyEnv Virtualenv Command Table</h4>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Action</td><td>Command</td></tr>
</thead>
<tbody>
<tr>
<td>Create Virtual Env</td><td><code>pyenv virtualenv &lt;python_version&gt; &lt;environment_name&gt;</code></td></tr>
<tr>
<td>Use Virtual env</td><td><code>pyenv local &lt;environment_name&gt;</code></td></tr>
<tr>
<td>List virtual env</td><td><code>pyenv virtualenvs</code></td></tr>
<tr>
<td>Remove Virtual env</td><td><code>pyenv virtualenv-delete &lt;environment_name&gt;</code></td></tr>
</tbody>
</table>
</div><hr />
<p>Congratulations!</p>
<p>You've successfully installed and configured Python on your Mac using PyEnv and PyEnv Virtualenv.</p>
<p>You're now equipped to tackle Python projects with confidence, knowing you can manage versions and dependencies like a pro.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<ul>
<li><p>PyEnv and PyEnv Virtualenv are powerful tools for managing Python development environment.</p>
</li>
<li><p>Virtual environments keep our projects organized and prevent dependency conflicts.</p>
</li>
</ul>
<p>Let me know if you'd like a follow-up article on setting up your first Python project.</p>
<h2 id="heading-references">References</h2>
<ul>
<li><p><a target="_blank" href="https://brew.sh">Homebrew</a></p>
</li>
<li><p>PyEnv <a target="_blank" href="https://github.com/pyenv/pyenv">GitHub</a></p>
</li>
<li><p>PyEnv pyenv-virtualenv <a target="_blank" href="https://github.com/pyenv/pyenv-virtualenv">GitHub</a></p>
</li>
<li><p>Python 3.11.8 installation error solution <a target="_blank" href="https://gist.github.com/iandanforth/f3ac42b0963bcbfdf56bb446e9f40a33">Gist</a></p>
</li>
<li><p>Image Credit: Google Gemini</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Reactive Systems]]></title><description><![CDATA[Reactive is an overloaded word in software development industry. We may often hear this buzzword associated with,

Reactive Systems
Reactive Programming
Functional Reactive Programming
Reactive Design
Reactive Architecture Patterns
Reactive applicati...]]></description><link>https://atech.guide/what-are-reactive-systems</link><guid isPermaLink="true">https://atech.guide/what-are-reactive-systems</guid><category><![CDATA[System Architecture]]></category><category><![CDATA[architecture]]></category><category><![CDATA[design and architecture]]></category><category><![CDATA[distributed system]]></category><dc:creator><![CDATA[Kamran Ali]]></dc:creator><pubDate>Mon, 01 Oct 2018 04:51:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724674349364/4c970d53-8e10-47fd-a487-54c062c41b18.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Reactive</strong> is an overloaded word in software development industry. We may often hear this buzzword associated with,</p>
<ul>
<li>Reactive Systems</li>
<li>Reactive Programming</li>
<li>Functional Reactive Programming</li>
<li>Reactive Design</li>
<li>Reactive Architecture Patterns</li>
<li>Reactive application</li>
</ul>
<p>and may be much more ...</p>
<p>I would argue every topic requires an article for itself and I would like to primarily focus on <em>Reactive Systems</em> in this article. </p>
<p>Before proceeding forward I would like to bring us all on same page by defining few terms that I will frequently use in this article. Beginning with,</p>
<h3 id="heading-system">System</h3>
<blockquote>
<p>A system provides set of services to its clients/Users</p>
</blockquote>
<p>For example, a website allowing us to book a Hotel is a System in itself. Keeping it simple, lets say it provides its users/clients with following services</p>
<ul>
<li>Making a reservation in the hotel of their choice</li>
<li>Cancellation</li>
</ul>
<p>A system is then further divided into <em>Components</em>. So let's define</p>
<h3 id="heading-component">Component</h3>
<blockquote>
<p>Components of a System collaborate with each other to provide services.</p>
</blockquote>
<p>Continuing with the example of <em>Booking System</em>, <strong>Making a reservation</strong> is one service which require following components to talk to each other</p>
<ul>
<li><em>Front End</em>: Website loaded in the browser</li>
<li><em>User management</em>: Maitaining profile of user</li>
<li><em>Payment</em>: Which charges the Credit/Debit Card</li>
<li><em>Notification</em>: Informing customer and user</li>
</ul>
<p>... and much more <strong>you got the idea.</strong></p>
<p>Interaction between these components can be simple client-server Or queue based and so on. </p>
<p>We can optinally group few components and call them <strong>Sub Systems</strong>.</p>
<p>You know the drill.</p>
<p>Moving on lets begin by answering a simple question,</p>
<h2 id="heading-what-are-reactive-systems">What are Reactive Systems?</h2>
<p>I personally like the Reactive Systems definition on Oreilly blog, which says</p>
<blockquote>
<p>A reactive system is an architectural style that allows multiple individual applications to coalesce as a single unit, reacting to its surroundings, while remaining aware of each other.</p>
</blockquote>
<p>If above definition looks too abstract, lets try again</p>
<blockquote>
<p>Reactive Systems in a nutshell is an Architectural and Design pattern of building large scale, responsive, resilient, self healing systems where individual components talk to each other over Asynchronous Messaging.</p>
</blockquote>
<p>I guess above definition packs too many "buzzword". Trust me I will add details. :)</p>
<p>First lets focus on </p>
<h2 id="heading-why-reactive-system">Why Reactive System</h2>
<p>As rightly mentioned in <a target="_blank" href="https://www.reactivemanifesto.org/">Reactive manifesto</a>,</p>
<blockquote>
<p>Today's demands are simply not met by yesterday’s software architectures</p>
</blockquote>
<p>Applications developed today requires to have</p>
<ul>
<li>Faster release cycle to ship new functionality quickly</li>
<li>Milliseconds response time</li>
<li>Cloud based clusters</li>
<li>100% uptime</li>
<li>Tolerant to failure </li>
</ul>
<p>and much more depending on the use cases.</p>
<p>Even the underlying hardware has evolved to multi-core processors generating compute capacity to handle data in petabytes.</p>
<p>The requirements mentioned above are more or less common in every organisation trying to solve a problem through technology.</p>
<p>Even though the problems may be completely different but the guidelines and design principles that we choose to solve it, does overlap.</p>
<p><strong>Shall we benefit from those already tested Solutions?</strong></p>
<p>Definitely, <em>Yes !!</em></p>
<p>Like-minded people have already identified common patters in those problems and drafted guidelines which may act as blue print for next generation application.</p>
<p>One such attempt is <a target="_blank" href="https://www.reactivemanifesto.org/">Reactive Manifesto</a>, which believes</p>
<blockquote>
<p>All necessary aspects are already recognised individually</p>
</blockquote>
<p>Basically it says, </p>
<blockquote>
<p>Systems should be Responsive, Resilient, Elastic and Message Driven. </p>
</blockquote>
<p>They call such systems as <strong>Reactive Systems</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1653808454814/o1njHTdqy.png" alt="Reactive Systems" class="image--center mx-auto" /></p>
<p>So without further ado, lets drill into the</p>
<h2 id="heading-characteristics-of-reactive-system">Characteristics of Reactive System</h2>
<h3 id="heading-responsiveness">Responsiveness</h3>
<p>Responsiveness means that Reactive Systems</p>
<ul>
<li>Should respond in <em>consistent and timely manner.</em> <ul>
<li>when an API call is made we expect a predictable and consistent response within SLAs. It helps in setting a reliable upper bound paving way for effective error handling and building confidence for its clients.</li>
</ul>
</li>
<li>Will detect problems quickly and mitigate it effectively.<ul>
<li>It demonstrates the self healing nature of reactive systems in which once bleeding begins, it is detected quickly and system takes appropriate actions to mitigate it.</li>
</ul>
</li>
</ul>
<h3 id="heading-resilient">Resilient</h3>
<blockquote>
<p>Resilience means that Reactive Systems should be responsive in face of failure.</p>
</blockquote>
<p>i.e. Failure(s) in one component should neither burden its client for handling the failures nor should bring the entire system to a grinding halt.</p>
<p>Resilience is achieved by </p>
<ul>
<li><em>Replication:</em> To ensure high availability we use replication. e.g. replicating master nodes of Redis Cluster.</li>
<li><em>Containment:</em> Failures are contained within each component. e.g. Failures in component responsible for lets say Async Notification should not bring down Sync Notification.</li>
<li><em>Isolation:</em> Components of a system are isolated ensuring part of system can fail and recover without compromising the entire system.</li>
<li><em>Delegation:</em> Recovery of each component is delegated to another component (maybe external). e.g. falling back to alternate data source if primary data source is unavailable</li>
</ul>
<h3 id="heading-elastic">Elastic</h3>
<blockquote>
<p>Elasticity means that Reactive Systems should be responsive under varying workload.</p>
</blockquote>
<p>Reactive Systems react to changes in the input rate by increasing or decreasing the resources allocated to service these inputs. Best example to understand this situation is cluster of similar services behind a load balancer. When load increases additional nodes are added via predictive or reactive scaling algorithm and vice versa.</p>
<p>Management of resources under varying workload is a very powerful concept  </p>
<ul>
<li>Ensuring we have no contention points or central bottlenecks</li>
<li>Enabling us to shard or replicate components and distribute inputs among them</li>
</ul>
<p><strong>Note:</strong> Elasticity is achieved in cost-effective way on commodity hardware and software platforms.</p>
<h3 id="heading-message-driven">Message Driven</h3>
<blockquote>
<p>Reactive systems have <em>Asynchronous Messaging</em> i.e. while requesting data we don’t wait for response, instead we register a callback and return. When data is available, it is pushed to callback method.</p>
</blockquote>
<p><em>Asynchronous Messaging</em> establishes a boundary between components which further helps in ensuring </p>
<ul>
<li><strong>Loose coupling and Isolation</strong> implying sender and receiver can have independent life-cycles. They do not need to be present at the same time and run on same process for communication to be possible. For example, queue based systems in which sender is pushing into queue and reciever is pulling from the queue.</li>
<li><strong>Elasticity</strong> implying throughput of a system scales up or down automatically to meet varying demand.</li>
<li><strong>Location transparency</strong> (also known as Decoupling in space) implying we are not dependent on server A talking to server B instead a cluster of micro service 'A'talks to cluster of micro service 'B'.</li>
<li><strong>Load Management</strong> implying sender and receiver can scale independently. For example, if the rate by which sender is pushing messages in the queue increases then reciever can scale independently to consume and process messages from the queue.</li>
</ul>
<p><strong>Note</strong></p>
<ul>
<li>Boundary between components ensures failures are notified in form of messages.</li>
<li>Non-blocking communication facilitates only consume resources while active, leading to less system overhead.</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>I would like to conclude it by suggesting the readers to look into/apply the characteristics discussed above, next time they are building New System. You may also look into the case study of <a target="_blank" href="https://medium.com/paypal-tech/squbs-a-new-reactive-way-for-paypal-to-build-applications-127126bf684b">How Paypal is handling billions of requests per day on 8 VMs and 2 vCPU?</a> by building Reactive Systems on Akka and Squbs.</p>
<p>See everything boils down to the satisfaction of your customer/client when they visit your site. If site is slow, unresponsive and in worse case down, then that's <strong>terrible experience</strong>.</p>
<p><strong>Take all steps to avoid it</strong></p>
<h2 id="heading-reference">Reference</h2>
<ul>
<li><a target="_blank" href="https://www.reactivemanifesto.org/">Reactive manifesto</a></li>
<li><a target="_blank" href="https://www.reactivemanifesto.org/glossary">Reactive manifesto glossary</a></li>
<li><a target="_blank" href="https://www.youtube.com/watch?v=0ueFTvSdxpw">Tech Primers - What is Reactive Programming?</a></li>
<li><a target="_blank" href="https://www.oreilly.com/radar/reactive-programming-vs-reactive-systems/">O Reilly - reactive-programming-vs-reactive-systems</a></li>
</ul>
]]></content:encoded></item></channel></rss>