<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Barbara Aboagye</title>
    <description>You miss 100% of the shots you don't take - Wayne Gretzky.</description>
    <link>http://barbaraaboagye.github.io//</link>
    <atom:link href="http://barbaraaboagye.github.io//feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Thu, 21 Dec 2023 04:07:49 +0000</pubDate>
    <lastBuildDate>Thu, 21 Dec 2023 04:07:49 +0000</lastBuildDate>
    <generator>Jekyll v3.9.3</generator>
    
      <item>
        <title></title>
        <description>&lt;h1 id=&quot;how-to-build-a-school-and-scholarship-search-app-3sa-using-python-and-streamlit-part-1-data-cleaning-and-preprocessing&quot;&gt;HOW TO BUILD A SCHOOL AND SCHOLARSHIP SEARCH APP (3SA) USING PYTHON AND STREAMLIT (PART 1): DATA CLEANING AND PREPROCESSING&lt;/h1&gt;

&lt;p&gt;How many of you have been shocked by University tuition cost? How many hours have you spent searching for suitable schools and scholarships that match your program of interest and still not found anything?&lt;/p&gt;

&lt;p&gt;To address these two major issues - the high cost of education and the difficulty of finding program-specific schools and scholarships, - I’ve built the School and Scholarship Search App (3SA) using Python and Streamlit.&lt;/p&gt;

&lt;p&gt;This app allows students to find schools that are tailored to their programs with accompanying scholarships, explore country-specific scholarships based on their program of interest, and find scholarships or schools based on their academic level of interest.&lt;/p&gt;

&lt;p&gt;In this article, we’ll explore the process of building the School and Scholarship Search App (3SA) in two parts: Part 1 focuses on cleaning and pre-processing the data, while Part 2 focuses on creating a user-friendly interface. Specifically, we’ll cover cleaning, handling missing data, and restructuring the dataset to build 3SA.&lt;/p&gt;

&lt;h2 id=&quot;data-cleaning-and-preprocessing-process-to-build-3sa&quot;&gt;Data Cleaning and Preprocessing Process to build 3SA&lt;/h2&gt;

&lt;p&gt;Let’s break down the steps involved :&lt;/p&gt;

&lt;h3 id=&quot;1-data-collection&quot;&gt;1. Data Collection&lt;/h3&gt;

&lt;p&gt;The first step is collecting the dataset. The data used in this project was manually collected from university websites and social media platforms (Twitter and LinkedIn). You can find and download the raw dataset &lt;a href=&quot;https://raw.githubusercontent.com/barbaraaboagye/My-MachineLearning-Journey/1e19a3a7caf86f8b0603ed100144ff94d536a769/Projects/Scholarship%20recommender%20system/scholarshipdatabase.csv&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;2-importing-libraries-and-loading-dataset&quot;&gt;2. Importing libraries and loading dataset&lt;/h3&gt;

&lt;p&gt;Let’s start by importing the necessary libraries and the &lt;a href=&quot;https://raw.githubusercontent.com/barbaraaboagye/My-MachineLearning-Journey/1e19a3a7caf86f8b0603ed100144ff94d536a769/Projects/Scholarship%20recommender%20system/scholarshipdatabase.csv&quot;&gt;dataset&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The libraries used are :&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;numpy&lt;/code&gt; for numerical operations.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pandas&lt;/code&gt; for data manipulation and DataFrame operations&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#Importing necessary python libraries
&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;numpy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pandas&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pd&lt;/span&gt;


&lt;span class=&quot;c1&quot;&gt;# Load dataset
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;df&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read_csv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'scholarshipdatabase.csv'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Display the first few rows
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;df&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/barbaraaboagye/barbaraaboagye.github.io/blob/a22929b7fca24b580f62be82c1afd8b539b3fb69/_posts/images/scholarship%20snapshot.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;.&lt;/p&gt;

&lt;p&gt;The dataset has various headings with several missing data as shown above. The next step will be to explore the dataset further.&lt;/p&gt;

&lt;h3 id=&quot;3-data-exploration&quot;&gt;3. Data Exploration&lt;/h3&gt;
&lt;p&gt;Now, let’s use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;info()&lt;/code&gt; method to get information about the data types and the presence of any missing values in our dataset.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Get information about the dataset
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;df&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/barbaraaboagye/barbaraaboagye.github.io/blob/dbabfe3bc4b66751f6acca4dbc48dfcce439eee6/_posts/images/info.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There are 704 entries with several null entries. The shape of the original dataset is (704,11)&lt;/p&gt;

&lt;h3 id=&quot;4-features-selection&quot;&gt;4. Features selection&lt;/h3&gt;

&lt;p&gt;Out of the 11 columns/features present in the dataset, we are only interested in 4. We will therefore create a new DataFrame with only the relevant features.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;# New dataframe with selected features
features = ['Name', 'Area of specialisation', 'Country', 'Level needed']
data = df[features]
data.head()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/barbaraaboagye/barbaraaboagye.github.io/blob/ca7a71275b7e6c24faf594320cf6ca13c87fb5b4/_posts/images/filtered%20dataset.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The new DataFrame &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data&lt;/code&gt; has only 4 features: Name, Area of specialisation, Country and Level needed. Let’s check the shape&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;data.shape
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/barbaraaboagye/barbaraaboagye.github.io/blob/552426fca6c3657fd9bf0c3ea08a2e467ea2b692/_posts/images/uncleaned%20dataset%20shape.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;5-splitting-columns-into-separate-rows&quot;&gt;5. Splitting Columns into Separate Rows&lt;/h3&gt;

&lt;p&gt;The selected features: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Area of specialisation&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Country&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Level needed&lt;/code&gt; contains multiple entries separated by commas. Split these entries into separate rows to make the data more accessible.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;# Split certain columns into separate rows
data = data.assign(**{'Area of specialisation': data['Area of specialisation'].str.split(', ')})
data = data.explode('Area of specialisation')

data = data.assign(**{'Country': data['Country'].str.split(', ')})
data = data.explode('Country')

data = data.assign(**{'Level needed': data['Level needed'].str.split(&quot;, &quot;)})
data = data.explode('Level needed')

# Reset the index for unique labels
data.reset_index(drop=True, inplace=True)

data.head()
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/barbaraaboagye/barbaraaboagye.github.io/blob/22edbc8a4187cf47be5361a44e2c59cac57b4712/_posts/images/cleaned%20dataset.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There are no more multiple entries for the columns. Let’s check the shape.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;data.shape
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/barbaraaboagye/barbaraaboagye.github.io/blob/66397cb5881e6f8f9c6ee2417c668b88b7411b85/_posts/images/cleaned%20dataset%20shape.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The splitting has resulted in more rows in our DataFrame, changing the shape from (704,4) to (3829,4).&lt;/p&gt;

&lt;h3 id=&quot;6-handling-missing-data&quot;&gt;6. Handling Missing Data&lt;/h3&gt;

&lt;p&gt;Now that our data is organized, we will now identify and address the missing data.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;# Further identify missing data
data.isnull().sum()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/barbaraaboagye/barbaraaboagye.github.io/blob/de0698a2051bc062f4e6941823c1f0924282845d/_posts/images/shape%20filtered%20dataset.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;# Drop rows with missing 'Name' values
data.dropna(subset=['Name'], inplace=True)

# Fill remaining missing values with empty strings
data.fillna('', inplace=True)
data.isnull().sum()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/barbaraaboagye/barbaraaboagye.github.io/blob/d98f46baa50cd15daa61f70925e03e05137677ef/_posts/images/shape%20filtered%20dataset%20after%20filling.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;7-data-saving&quot;&gt;7. Data Saving&lt;/h3&gt;

&lt;p&gt;Our dataset is now clean and ready to be used to build 3SA. It is saved in a new CSV file as “scholarship_df.csv”&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;# Save the cleaned dataset
data.to_csv('scholarship_df.csv', index=False)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, your dataset is clean and ready to be used for building the School and Scholarship Search App (3SA). You can access the complete Python code &lt;a href=&quot;https://github.com/barbaraaboagye/My-MachineLearning-Journey/blob/31e326d6e5a6ac53e94cd4e9fc3145590a404c52/Projects/Scholarship%20recommender%20system/Data_processing.ipynb&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Thu, 21 Dec 2023 04:07:49 +0000</pubDate>
        <link>http://barbaraaboagye.github.io//2023/12/21/2023-12-15-Data-Cleaning-for-School-And-Scholarship-Search/</link>
        <guid isPermaLink="true">http://barbaraaboagye.github.io//2023/12/21/2023-12-15-Data-Cleaning-for-School-And-Scholarship-Search/</guid>
        
        
      </item>
    
      <item>
        <title>Distribute Storage System Design Part2 -- Memcache Redis And Spanner</title>
        <description>&lt;h2 id=&quot;1-memcache-分布式hashtable缓存-dht&quot;&gt;1 Memcache 分布式HashTable缓存 (DHT)&lt;/h2&gt;

&lt;p&gt;Memcache是Facebook在单机版memcached基础上设计的分布式的KV存储.
在Facebook, 对分布式HashTable(DHT)的使用需求:&lt;/p&gt;

&lt;p&gt;1) near real-time communication.&lt;/p&gt;

&lt;p&gt;2) aggregate content on-the-fly from multi sources&lt;/p&gt;

&lt;p&gt;3) able to access and update popular shared content&lt;/p&gt;

&lt;p&gt;4) scale to millions qps.&lt;/p&gt;

&lt;p&gt;5) Read-heavy workload and wide fan-out.&lt;/p&gt;

&lt;p&gt;Memcache用做数据的缓存, 在设计上有取舍, 降低整体系统的复杂性:&lt;/p&gt;

&lt;p&gt;1) 按需的lool-aside cache. Choose to delete cache data instead of update, cause of idempotent. 
   look-aside cache的流程如下, 读取时, 先读缓存再读db, cacahe miss写缓存. 更新时, 先写db, 再失效缓存. 失效缓存而不是更新缓存, 避免了concurrent更新缓存带来的时序问题(由db解决).
   &lt;img src=&quot;http://nickolashu.github.io/img/look-aside cache.png&quot; alt=&quot;look-aside cache&quot; style=&quot;zoom:50%;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;2) 各个Memcache服务之间不做通信, 各个Region之间通过数据库做同步. 数据一致性由后端存储(MySQL)保障. (最终一致性). 保持memcache 是stateless的server. 各个实例独立运行, Memcache很容易水平扩展, 增加服务, 不影响现有的节点. 但不能直接做数据的Partition(依赖DB的Partition).
   &lt;img src=&quot;http://nickolashu.github.io/img/overall architecture.png&quot; alt=&quot;overall architecture&quot; style=&quot;zoom:50%;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;此外, Memcache在系统延迟, 异常处理, 缓存冷启, 跨Region一致性优化上, 有很多实践的经验.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;降低系统延迟:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;1) 使用batch和并发请求.  通过DAG(DAG represent dependcy of data.)一次获取多个key的数据. Client-Server之间也通过并发请求降低延迟.&lt;/p&gt;

&lt;p&gt;2) Client-Server通信优化. 读取请求(get)使用udp降低延迟和负载. put/delete请求使用tcp保证可靠性.
实践经验udp network failure 0.25% (80% late or drop packet), 将网络异常treat as error, 但skip fill memcached, 避免不必要的网络开销.&lt;/p&gt;

&lt;p&gt;3) Incast congestion: 使用sliding window限制incast congestion. 
发生Incast congestion的原因是, client会并发请求大量的key, response有可能同时到达, 从而把路由器等设备打卦.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;使用租约(lease)降低后端负载:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;当cache miss的时候会生成lease. lease is a 64-bit token bound to the specific key the client originally requested.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;stale write: happens when concurrent update to memcache get reordered. 当set value时, 会校验lease.如果key在request到put期间收到了delete reqeust, lease会失效.&lt;/p&gt;

    &lt;p&gt;考虑以下场景R1, R2先后两次读取, U1, U2先后两次更新, 分别更新值为A,B, 更新都先于读. 因此R1,R2触发了两次写W1,W2. 如果W2先于W1到达, 则最终值为A. 即为stale write.&lt;/p&gt;

    &lt;p&gt;带lease的场景, W2由R2触发, lease有效可以更新. W1由R1触发, lease期间有数据更新U2, 因此lease失效, 更新被拒绝. 因此最终值为B.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;缓存击穿(thundering herds):  token每10秒会生成一个, 在10秒内, client带有lease的请求会被延迟hold一段时间, 这样当请求时, 缓存的数据已经被更新. 从而减少了大量的数据更新时带来的缓存击穿问题.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
  &lt;li&gt;Handle failures:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Dedicate a small set of machines(1%), to take over the responsiblities of a few failed servers, named Gutter.&lt;/p&gt;

&lt;p&gt;When a memcached client receives no response to its get request, the client assumes the server has failed and issues the request again to the Gutter pool.&lt;/p&gt;

&lt;p&gt;Regional Invalidation: MySQL commit log - batch deletes to McSqueal - unpack to individual memcache server&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://nickolashu.github.io/img/memcache invalidation@2x.png&quot; alt=&quot;memcache invalidation@2x&quot; style=&quot;zoom:50%;&quot; /&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Cold Cluster Warmup: Allow “cold cluster” retrieve data from “warm cluster” rather than a persitent storage.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;​	Race conditions: cold cluster database update - simultaneously request stale data from warm cluster.&lt;/p&gt;

&lt;p&gt;​		solution:&lt;/p&gt;

&lt;p&gt;​				Client:&lt;/p&gt;

&lt;p&gt;​					when a miss id detected,&lt;/p&gt;

&lt;p&gt;​					client re-request the key from the warm cluster&lt;/p&gt;

&lt;p&gt;​					and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;adds&lt;/code&gt; it into the cold cluster.&lt;/p&gt;

&lt;p&gt;​					Cold Cluster: all deletes to colud cluster issued with a two second hold-off (which reject add)&lt;/p&gt;

&lt;p&gt;​					the failure of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add&lt;/code&gt; indicates that the newer data is avaliable.&lt;/p&gt;

&lt;p&gt;​					client refetch on the database.&lt;/p&gt;

&lt;p&gt;​	Close time: When cold cluster’s hit rate stabilizse.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Across Region Consistency:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;​	Benifits: local memcached server + local MySql provides low latency; avoids reace condition in which an invalidation arrives before the data replicated from the master db region.&lt;/p&gt;

&lt;p&gt;​	Problem: replica may lag behind the master database. reqeust may get the stale data be&lt;/p&gt;

&lt;p&gt;​	Solution: provide best-effort eventual consistency. Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;remote marker&lt;/code&gt; to minimize the probability of reading stale data. the marker indicates that data in the local replica database are potentially stale, and the query should be redirected to the master region.&lt;/p&gt;

&lt;p&gt;1) befrore client update key k, set a remote marker in the region&lt;/p&gt;

&lt;p&gt;2) client perform write to the master db.&lt;/p&gt;

&lt;p&gt;3) client deletes k in the local memcache cluster.&lt;/p&gt;

&lt;p&gt;4) client get cache miss, check the remote marker of k, decide whether direct query to master/local databese.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; Trade consistency with speed.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;​&lt;/p&gt;

&lt;h2 id=&quot;2-redis&quot;&gt;2 Redis&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Availability
master replica pattern
support async(default) and sync replication.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;replica PSYNC -&amp;gt; master &amp;lt;Replication ID, offset&amp;gt;
   查询backlog
   计算incremental update
   or 查询不到 full sync
      background process RDB file
      buffer commands
      load RDB file, send all to replica&lt;/p&gt;

&lt;p&gt;A replication ID basically marks a given history of the data set. Every time an instance restarts from scratch as a master, or a replica is promoted to master, a new replication ID is generated for this instance.&lt;/p&gt;

&lt;p&gt;why a replica promoted to master needs to change its replication ID after a failover: it is possible that the old master is still working as a master because of some network partition: retaining the same replication ID would violate the fact that the same ID and same offset of any two random instances mean they have the same data set.&lt;/p&gt;

&lt;p&gt;Redis Cluster&lt;/p&gt;

&lt;p&gt;Hash Slot:&lt;/p&gt;

&lt;p&gt;Every node is connected to every other node, The client is in theory free to send requests to all the nodes in the cluster, getting redirected if needed.&lt;/p&gt;

&lt;p&gt;https://medium.com/opstree-technology/redis-cluster-architecture-replication-sharding-and-failover-86871e783ac0#:~:text=Redis%20Cluster%20is%20an%20active,a%20subset%20of%20those%20slots
https://redis.io/docs/manual/replication/&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Consistency
https://www.allthingsdistributed.com/2021/11/amazon-memorydb-for-redis-speed-consistency.html&lt;/p&gt;

    &lt;p&gt;Redis Cluster uses asynchronous replication between nodes, and &lt;strong&gt;last failover wins&lt;/strong&gt; implicit merge function. This means that the last elected master dataset eventually replaces all the other replicas. There is always a window of time when it is possible to lose writes during partitions.&lt;/p&gt;

    &lt;p&gt;防止split brain: 奇数个master, 每个master两个replica.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Persistence
https://redis.io/docs/manual/persistence/&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Performance
– IO MultiPlexing - epoll/kqueue
Redis event library https://github.com/redis/redis/blob/99ab4236afb210dc118fad892210b9fbb369aa8e/src/ae.c
https://austingwalters.com/io-multiplexing/&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;– Single Thread&lt;/p&gt;

&lt;p&gt;– Pipelining
https://redis.io/docs/manual/pipelining/#:~:text=Redis%20is%20a%20TCP%20server,way%2C%20for%20the%20server%20response.&lt;/p&gt;

&lt;p&gt;https://aws.amazon.com/redis/&lt;/p&gt;

&lt;h2 id=&quot;3-spanner&quot;&gt;3 Spanner&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://nickolashu.github.io/img/spanner.png&quot; alt=&quot;spanner&quot; style=&quot;zoom:40%;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;MVCC: no locking consistent read, with snapshot. (with no write after read casual consistency problem)&lt;/p&gt;

&lt;p&gt;read transcation(Tr) can only read transcations before Tr;&lt;/p&gt;

&lt;p&gt;Write transcation(Tw) will not overwrite value, but create a new value with timestamp.&lt;/p&gt;

&lt;p&gt;MySQL local timestamp, Spanner global unique timestamp generate.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://nickolashu.github.io/img/spanner-transcation-commit.png&quot; alt=&quot;spanner-transcation-commit&quot; style=&quot;zoom:40%;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://nickolashu.github.io/img/spanner-true-time.png&quot; style=&quot;zoom:40%;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;4-总结&quot;&gt;4 总结&lt;/h2&gt;
</description>
        <pubDate>Sun, 15 May 2022 00:00:00 +0000</pubDate>
        <link>http://barbaraaboagye.github.io//2022/05/15/Distribute-Storage-System-Design-Part2-Memcache-Redis-And-Spanner/</link>
        <guid isPermaLink="true">http://barbaraaboagye.github.io//2022/05/15/Distribute-Storage-System-Design-Part2-Memcache-Redis-And-Spanner/</guid>
        
        
      </item>
    
  </channel>
</rss>
