<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
  <channel>
    <title>Melon blog</title>
    <link></link>
    <description>My personal blog</description>
    
      <item>
        <title>Attention is all you need</title>
        <link>/2026/01/04/attention-is-all-you-need.html</link>
        <guid isPermaLink="true">/2026/01/04/attention-is-all-you-need.html</guid>
        <pubDate>Sun, 04 Jan 2026 00:00:00 +0000</pubDate>
        <description>&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Transformer, an encoder and decoder model, solely based on attention mechanisms.&lt;/li&gt;
  &lt;li&gt;Not using recurrence and convolutions, more parallelizable, capturing long-distance context in &lt;script type=&quot;math/tex&quot;&gt;O(1)&lt;/script&gt;. Therefore, it requires less time to train.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/ml/attention-model.png&quot; alt=&quot;Model architecture&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;One layer contains two sub-layers: attention and Feed Forward (FFN).&lt;/li&gt;
  &lt;li&gt;Employ a residual connection around each of the two sub-layers, then layer normalization.
    &lt;ul&gt;
      &lt;li&gt;The output of each sub-layer is &lt;script type=&quot;math/tex&quot;&gt;\text{LayerNorm}(x + \text{Sublayer}(x))&lt;/script&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Multiple &lt;script type=&quot;math/tex&quot;&gt;N&lt;/script&gt; layers. e.g., Llama-3-8B has 32 layers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;input-preparation&quot;&gt;Input preparation&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;Input is a natural language sequence with &lt;script type=&quot;math/tex&quot;&gt;n&lt;/script&gt; tokens.&lt;/li&gt;
  &lt;li&gt;Input is first converted to a matrix &lt;script type=&quot;math/tex&quot;&gt;X&lt;/script&gt; of dimension &lt;script type=&quot;math/tex&quot;&gt;[n, d_{model}]&lt;/script&gt;. &lt;script type=&quot;math/tex&quot;&gt;d_{model}&lt;/script&gt; is the dimension of token embedding vector. e.g., 768, 4096.&lt;/li&gt;
  &lt;li&gt;Add positional embeddings to the input matrix to provide position info for each token. The dimension doesn’t change.
    &lt;ol&gt;
      &lt;li&gt;Using fixed sinusoid function. Can also use learned ones.&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;self-attention&quot;&gt;Self-attention&lt;/h2&gt;

&lt;p&gt;While processing a sequence, automatically learn the contexts, relations between different parts.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/ml/attention-qkv.png&quot; alt=&quot;attention&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Calculate &lt;script type=&quot;math/tex&quot;&gt;Q&lt;/script&gt;(Query), &lt;script type=&quot;math/tex&quot;&gt;K&lt;/script&gt;(Key), &lt;script type=&quot;math/tex&quot;&gt;V&lt;/script&gt;(Value) using the input matrix and projection matrices &lt;script type=&quot;math/tex&quot;&gt;W^Q, W^K, W^V&lt;/script&gt;.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;script type=&quot;math/tex&quot;&gt;Q = X W^Q&lt;/script&gt;, the query, for each position, what context it wants to search for
    &lt;ol&gt;
      &lt;li&gt;&lt;script type=&quot;math/tex&quot;&gt;W^Q&lt;/script&gt; is of dimension &lt;script type=&quot;math/tex&quot;&gt;[d_{model}, d_{model}]&lt;/script&gt;. &lt;script type=&quot;math/tex&quot;&gt;Q&lt;/script&gt; is of dimension &lt;script type=&quot;math/tex&quot;&gt;[n, d_{model}]&lt;/script&gt;.&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;script type=&quot;math/tex&quot;&gt;K = X W^K&lt;/script&gt;, the key, for each position, what info it can provide for the search, like a search index
    &lt;ol&gt;
      &lt;li&gt;&lt;script type=&quot;math/tex&quot;&gt;W^K&lt;/script&gt; is of dimension &lt;script type=&quot;math/tex&quot;&gt;[d_{model}, d_{model}]&lt;/script&gt;. &lt;script type=&quot;math/tex&quot;&gt;V&lt;/script&gt; is of dimension &lt;script type=&quot;math/tex&quot;&gt;[n, d_{model}]&lt;/script&gt;.&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;$V = X W^V$$, the value, for each position, if selected, what detailed info it can provide, like the payload
    &lt;ol&gt;
      &lt;li&gt;&lt;script type=&quot;math/tex&quot;&gt;W^V&lt;/script&gt; is of dimension &lt;script type=&quot;math/tex&quot;&gt;[d_{model}, d_{model}]&lt;/script&gt;. &lt;script type=&quot;math/tex&quot;&gt;V&lt;/script&gt; is of dimension &lt;script type=&quot;math/tex&quot;&gt;[n, d_{model}]&lt;/script&gt;.&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With training, &lt;script type=&quot;math/tex&quot;&gt;W^Q&lt;/script&gt; and &lt;script type=&quot;math/tex&quot;&gt;W^K&lt;/script&gt; learn about searching and matching contexts. &lt;script type=&quot;math/tex&quot;&gt;W^V&lt;/script&gt; learns about information providing.&lt;/p&gt;

&lt;p&gt;\[\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V\]&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;script type=&quot;math/tex&quot;&gt;Q K^T&lt;/script&gt; is calculating similarity between query and all keys.&lt;/li&gt;
  &lt;li&gt;&lt;script type=&quot;math/tex&quot;&gt;\sqrt{d_k}&lt;/script&gt; is for scaling to prevent gradient vanishing.&lt;/li&gt;
  &lt;li&gt;Softmax is for normalizing similarity scores to probabilities, the total is 1.&lt;/li&gt;
  &lt;li&gt;&lt;script type=&quot;math/tex&quot;&gt;\times V&lt;/script&gt; gets the final value. Values with higher similarities occupy larger portion in the final value. The dimension is &lt;script type=&quot;math/tex&quot;&gt;[n, d_{model}]&lt;/script&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;multi-head-attention&quot;&gt;Multi-head attention&lt;/h2&gt;

&lt;p&gt;Learn the same sequence from multiple aspects. Multi-head attention allows the model to learn these aspects independently, in parallel. There could be shallow heads focusing on local info, deep heads for global info.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Linear projection for &lt;script type=&quot;math/tex&quot;&gt;h&lt;/script&gt; heads: project the initial &lt;script type=&quot;math/tex&quot;&gt;Q, K, V&lt;/script&gt; for each head &lt;script type=&quot;math/tex&quot;&gt;i&lt;/script&gt; with &lt;script type=&quot;math/tex&quot;&gt;W_i^Q, W_i^K, W_i^V&lt;/script&gt;.
    &lt;ol&gt;
      &lt;li&gt;The dimension &lt;script type=&quot;math/tex&quot;&gt;d_{model}&lt;/script&gt; is usually split equally across heads. &lt;script type=&quot;math/tex&quot;&gt;d_h = \frac{d_{model}}{h}&lt;/script&gt;. So the dimension of &lt;script type=&quot;math/tex&quot;&gt;QW_i^Q&lt;/script&gt; is &lt;script type=&quot;math/tex&quot;&gt;[n, d_h]&lt;/script&gt;. So multi-head won’t increase computation cost.&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;Parallel attention: &lt;script type=&quot;math/tex&quot;&gt;\text(head)_i = \text(Attention)(QW_i^Q, KW_i^K, VW_i^V)&lt;/script&gt;
    &lt;ol&gt;
      &lt;li&gt;The dimension is &lt;script type=&quot;math/tex&quot;&gt;[n, d_h]&lt;/script&gt;.&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;Concatenation: Concatenate the outputs of all heads. The dimension is &lt;script type=&quot;math/tex&quot;&gt;[n, d_{model}]&lt;/script&gt;.&lt;/li&gt;
  &lt;li&gt;Final linear: use a &lt;script type=&quot;math/tex&quot;&gt;W^O&lt;/script&gt; to project the output back to the original dimension, also synchronize info from all heads.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
  &lt;li&gt;Diversity: learns in various aspects.&lt;/li&gt;
  &lt;li&gt;Robustness: If one head fails due to noise, other heads are still working.&lt;/li&gt;
  &lt;li&gt;Sub-space learning: Easier to capture complex info by learning in multiple lower-dimensional spaces.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;feed-forward-network-ffn&quot;&gt;Feed Forward network (FFN)&lt;/h2&gt;

&lt;p&gt;FFN is after the attention layer. It’s position/point-wise, each position only cares about itself, learning deeper information. This layer adds nonlinear to the overall model.&lt;/p&gt;

&lt;p&gt;\[\text{FFN}\left(x\right) = \text{activation}\left(xW_1+b_1\right)W_2+b_2\]&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Dimension expansion
    &lt;ul&gt;
      &lt;li&gt;Using &lt;script type=&quot;math/tex&quot;&gt;W_{up}&lt;/script&gt; of dimension &lt;script type=&quot;math/tex&quot;&gt;[d_{model}, d_{ff}]&lt;/script&gt; to expand the input dimension to &lt;script type=&quot;math/tex&quot;&gt;[n, d_{ff}]&lt;/script&gt;&lt;/li&gt;
      &lt;li&gt;&lt;script type=&quot;math/tex&quot;&gt;d_{ff}&lt;/script&gt; is usually larger (~4X) than &lt;script type=&quot;math/tex&quot;&gt;d_{model}&lt;/script&gt;. It’s easier to identify and extract complex details in higher-dimensional spaces.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Dimension reduction
    &lt;ul&gt;
      &lt;li&gt;Use &lt;script type=&quot;math/tex&quot;&gt;W_{down}&lt;/script&gt; of dimension &lt;script type=&quot;math/tex&quot;&gt;[d_{ff}, d_{model}]&lt;/script&gt; to reduce to the original dimension.&lt;/li&gt;
      &lt;li&gt;Filter noise and compress useful info.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
  &lt;li&gt;The activation function is nonlinear, e.g., ReLU, &lt;script type=&quot;math/tex&quot;&gt;MAX()&lt;/script&gt;.&lt;/li&gt;
  &lt;li&gt;Token has gained context info from attention layer; FFN is for further digesting these info.&lt;/li&gt;
  &lt;li&gt;Dimension expansion:&lt;/li&gt;
  &lt;li&gt;Store knowledge and memories in FFN weight matrices.&lt;/li&gt;
  &lt;li&gt;~2/3 weights in a LLM are in FFN.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;training&quot;&gt;Training&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Adam optimizer&lt;/li&gt;
  &lt;li&gt;Regularization
    &lt;ul&gt;
      &lt;li&gt;Residual dropout on (1) the output of each sub-layer and (2) the addition of input embedding and positional embedding.&lt;/li&gt;
      &lt;li&gt;Label smoothing&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://arxiv.org/pdf/1706.03762&quot;&gt;paper&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
    
      <item>
        <title>Design patterns</title>
        <link>/2025/07/25/design-patterns.html</link>
        <guid isPermaLink="true">/2025/07/25/design-patterns.html</guid>
        <pubDate>Fri, 25 Jul 2025 00:00:00 +0000</pubDate>
        <description>&lt;h2 id=&quot;books&quot;&gt;Books&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://library.uniteddiversity.coop/Ecological_Building/The_Timeless_Way_of_Building_Complete.pdf&quot;&gt;The timeless way of building&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.javier8a.com/itc/bd1/articulo.pdf&quot;&gt;Gang of Four, Design Patterns: Elements of Reusable Object-Oriented Software&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/ajitpal/BookBank/master/%5BO%60Reilly.%20Head%20First%5D%20-%20Head%20First%20Design%20Patterns%20-%20%5BFreeman%5D.pdf&quot;&gt;Head First Design Patterns&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://arl.human.cornell.edu/linked%20docs/Alexander_A_Pattern_Language.pdf&quot;&gt;A Pattern Language&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;advantages&quot;&gt;Advantages&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;More flexible
    &lt;ul&gt;
      &lt;li&gt;Easier to add/remove/modify behavior&lt;/li&gt;
      &lt;li&gt;Easier to reuse behavior&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Easier to understand&lt;/li&gt;
  &lt;li&gt;Less code to write/debug/maintain&lt;/li&gt;
  &lt;li&gt;More efficient method of creating software&lt;/li&gt;
  &lt;li&gt;More value per line-of-code&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;strategy-proxy-decorator&quot;&gt;Strategy, proxy, decorator&lt;/h2&gt;

&lt;h3 id=&quot;strategy&quot;&gt;Strategy&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Strategy
    &lt;ul&gt;
      &lt;li&gt;Strategy pattern is just polymorphism.&lt;/li&gt;
      &lt;li&gt;“Code to interfaces, not to their implementations”&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Proxy
    &lt;ul&gt;
      &lt;li&gt;is the delegation strategy: A strategy which uses a strategy.&lt;/li&gt;
      &lt;li&gt;Lets you swap implementation without the knowledge of clients&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Decorator
    &lt;ul&gt;
      &lt;li&gt;A proxy which adds behavior.&lt;/li&gt;
      &lt;li&gt;Add new behaviors to objects dynamically at runtime, flexible alternative to subclassing/inheritance.&lt;/li&gt;
      &lt;li&gt;Decoration reuses an Object (dynamic); inheritance reuses a Class (static, compile time).&lt;/li&gt;
      &lt;li&gt;Separation of concerns: breaking a program into distinct features that overlap as little as possible. A concern can be considered as a feature of behavior.&lt;/li&gt;
      &lt;li&gt;Implement features separately, small, focused classes.&lt;/li&gt;
      &lt;li&gt;Avoids # class explosion.
        &lt;ul&gt;
          &lt;li&gt;10 classes, adding 5 behaviors
            &lt;ul&gt;
              &lt;li&gt;Inheritance: 10 * 2^5&lt;/li&gt;
              &lt;li&gt;Decorator: 10 + 5&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Advantages:
        &lt;ul&gt;
          &lt;li&gt;Efficient to implement behavior&lt;/li&gt;
          &lt;li&gt;Less code to write/maintain.&lt;/li&gt;
          &lt;li&gt;Separation of Concerns&lt;/li&gt;
          &lt;li&gt;Easier to extend&lt;/li&gt;
          &lt;li&gt;Testable&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-java 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;// Decoration&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SynchronizedRunnable&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RunnableProxy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;SynchronizedRunnable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Runnable&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;delegate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Takes an object&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delegate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;synchronized&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;delegate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Inheritance&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SynchronizedMyRunnable&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Runnable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;SynchronizedMyRunnable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{}&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;synchronized&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;path-to-mvc&quot;&gt;Path to MVC&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Observer Pattern
    &lt;ul&gt;
      &lt;li&gt;Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;Observerble{attach(Observer); detach(Observer); notify()}; Observer{update()}&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Mediator Pattern
    &lt;ul&gt;
      &lt;li&gt;A mediator serves as an intermediary that keeps objects in a group from referring to each other explicitly.&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;(Mediated object 1) -&amp;gt; (Mediator) &amp;lt;- (Mediated object 2)&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Adaptor and Bridge
    &lt;ul&gt;
      &lt;li&gt;Special types of strategy.&lt;/li&gt;
      &lt;li&gt;Rely on another object to do the job(interface), which has a different interface.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Composite Pattern
    &lt;ul&gt;
      &lt;li&gt;Compose objects into tree structures to represent part-whole hierarchies. Clients can then treat individual objects and compositions of objects uniformly.&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Any idea is better when made recursive&lt;/strong&gt; – Brian Randell.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Flyweight
    &lt;ul&gt;
      &lt;li&gt;Use sharing to support large numbers of fine-grained objects efficiently.&lt;/li&gt;
      &lt;li&gt;Often implemented as a stateless Singleton.&lt;/li&gt;
      &lt;li&gt;Object to be worked with is passed as an argument.&lt;/li&gt;
      &lt;li&gt;Useful for creating extensions to existing classes.&lt;/li&gt;
      &lt;li&gt;Java comparator example: &lt;code class=&quot;highlighter-rouge&quot;&gt;public interface Comparator { int compare(Object o1, Object o2)}&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;mvc&quot;&gt;MVC&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Model: Data model
    &lt;ul&gt;
      &lt;li&gt;Adaptor/Bridge strategy representing data, state and logic&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;View: UI
    &lt;ul&gt;
      &lt;li&gt;Adaptor strategy for interacting with users&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Controller: control logic, mediator
    &lt;ul&gt;
      &lt;li&gt;Mediator between model and view&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Good to always use Factory to create objects, which is more flexible and can have different creation options.&lt;/p&gt;
</description>
      </item>
    
      <item>
        <title>读人类简史</title>
        <link>/2025/07/13/sapiens.html</link>
        <guid isPermaLink="true">/2025/07/13/sapiens.html</guid>
        <pubDate>Sun, 13 Jul 2025 00:00:00 +0000</pubDate>
        <description>&lt;h2 id=&quot;第一部分认知革命-the-cognitive-revolution&quot;&gt;&lt;strong&gt;第一部分：认知革命 (The Cognitive Revolution)&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;核心观点：&lt;/strong&gt; 大约在7万年前，智人（Homo sapiens）的思维和沟通方式发生了革命性的变化，这使得我们能够超越其他人类物种，并最终主宰地球。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;第一章：无足轻重的人类 (An Animal of No Significance)&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;在历史长河的大部分时间里，智人只是一种生活在非洲角落、毫不起眼的动物。&lt;/li&gt;
      &lt;li&gt;地球上曾同时存在多种人类物种（如尼安德特人、丹尼索瓦人等）。&lt;/li&gt;
      &lt;li&gt;人类位于食物链的中端，直到学会用火后地位才开始显著提升。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;第二章：知善恶树 (The Tree of Knowledge)&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;认知革命&lt;/strong&gt;的发生是智人崛起的关键，可能源于一次偶然的基因突变。&lt;/li&gt;
      &lt;li&gt;这场革命赋予了智人全新的&lt;strong&gt;虚构语言能力 (Fictive Language)&lt;/strong&gt;，能够讨论不存在的事物，如部落的神、国家、法律和金钱：想象的现实。&lt;/li&gt;
      &lt;li&gt;正是这种对“虚构故事”的共同信仰，使得大规模、灵活的合作成为可能，突破了约150人的生理社群规模限制。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;第三章：亚当和夏娃的一天 (A Day in the Life of Adam and Eve)&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;描述了采集狩猎者的生活方式。他们知识广博，工作时间可能比现代人短，营养也更均衡。&lt;/li&gt;
      &lt;li&gt;他们是“最初的富裕社会”，但生活也充满危险，如野兽、意外和暴力。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;第四章：毁天灭地的人类洪水 (The Flood)&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;随着智人走出非洲，他们所到之处，大型动物（巨型动物群）纷纷灭绝。&lt;/li&gt;
      &lt;li&gt;这表明智人早在农业革命和工业革命之前，就已经是地球生态系统中最具破坏力的物种。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;第二部分农业革命-the-agricultural-revolution&quot;&gt;&lt;strong&gt;第二部分：农业革命 (The Agricultural Revolution)&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;核心观点：&lt;/strong&gt; 农业革命是“史上最大的骗局”。虽然它为人类提供了更多的粮食，但也带来了更辛苦的劳动、更差的营养、更严重的疾病和更深重的社会不平等。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;第五章：史上最大骗局 (History’s Biggest Fraud)&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;农业革命并非人类主动选择，而是一个缓慢的、诱人深入的陷阱。&lt;/li&gt;
      &lt;li&gt;从某种意义上说，并非人类驯化了小麦，而是小麦“驯化”了人类。人类被迫定居下来，生活变得更辛苦，饮食更单一。&lt;/li&gt;
      &lt;li&gt;种群的成功并不等同于个体的幸福。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;第六章：盖起金字塔 (Building Pyramids)&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;农业带来的剩余粮食催生了更大规模的社会组织，如村庄、城镇和王国。&lt;/li&gt;
      &lt;li&gt;人们开始为“未来”而焦虑，担心收成和天气。&lt;/li&gt;
      &lt;li&gt;出现了不事生产的统治精英阶层，并利用&lt;strong&gt;想象的秩序 (Imagined Order)&lt;/strong&gt;，如法律和神话，来维持社会阶级和不平等。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;第七章：记忆过载 (Memory Overload)&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;随着社会规模扩大，人类大脑无法处理海量的信息（如税收、财产记录）。&lt;/li&gt;
      &lt;li&gt;为了管理复杂的社会，&lt;strong&gt;文字&lt;/strong&gt;被发明出来。最早的文字主要用于记账和行政管理。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;第八章：历史从无正义 (There is No Justice in History)&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;想象的秩序（如种族、阶级、性别制度）往往会造成不公正的歧视，并通过恶性循环自我强化。&lt;/li&gt;
      &lt;li&gt;一个偶然的历史事件导致某个群体处于劣势，然后通过法律和习俗将这种劣势固化，并宣称其是“自然的”或“神定的”。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;第三部分人类的融合统一-the-unification-of-humankind&quot;&gt;&lt;strong&gt;第三部分：人类的融合统一 (The Unification of Humankind)&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;核心观点：&lt;/strong&gt; 历史的大方向是走向融合与统一。三种普世秩序——金钱、帝国和宗教——将原本分散的文化连接成一个全球性的文明。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;第九章：历史的方向 (The Arrow of History)&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;历史的大趋势是融合，原本数千个独立的小世界逐渐合并成一个“全球村”。&lt;/li&gt;
      &lt;li&gt;这种融合是通过金钱、帝国和宗教三种普世秩序实现的。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;第十章：金钱的味道 (The Scent of Money)&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;金钱&lt;/strong&gt;是历史上最成功的“虚构故事”，是一种普世的信任体系。&lt;/li&gt;
      &lt;li&gt;它能跨越文化和地理障碍，让陌生人高效合作，因为所有人都相信它的价值。&lt;/li&gt;
      &lt;li&gt;为什么黄金的价值在欧亚大陆都被认可？
        &lt;ul&gt;
          &lt;li&gt;因为远距离贸易的存在，使各区域对价值的认知趋同。&lt;/li&gt;
          &lt;li&gt;相比之下，美洲印第安文明只把黄金作为装饰。&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;第十一章：帝国的愿景 (Imperial Visions)&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;帝国&lt;/strong&gt;虽然常伴随着暴力和压迫，但也极大地促进了思想、技术、法律和文化的传播与融合。&lt;/li&gt;
      &lt;li&gt;几乎所有现代文化都是帝国遗产的混合体，帝国创造的标准化体系为今天的全球化奠定了基础。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;第十二章：宗教的法则 (The Law of Religion)&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;宗教&lt;/strong&gt;是另一种强大的统一力量，它赋予人类社会超人类的合法性，使其规范和价值观具有普世性。
        &lt;ul&gt;
          &lt;li&gt;成为全球性宗教的关键是普世性和传播欲望。&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;近代以来，新形式的“人文主义宗教”（如自由主义、社会主义）开始取代神本位宗教，它们崇拜的是“人性”。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;第四部分科学革命-the-scientific-revolution&quot;&gt;&lt;strong&gt;第四部分：科学革命 (The Scientific Revolution)&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;核心观点：&lt;/strong&gt; 科学革命并非知识的革命，而是一场“承认无知”的革命。它催生了欧洲的崛起、资本主义的扩张，并彻底改变了人类社会和生态。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;第十三章：发现自己的无知 (The Discovery of Ignorance)&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;现代科学的核心特征是：愿意承认“我们不知道”，并以&lt;strong&gt;观察&lt;/strong&gt;和&lt;strong&gt;数学&lt;/strong&gt;为中心来寻求新知。&lt;/li&gt;
      &lt;li&gt;这与传统知识体系（如宗教）形成鲜明对比，后者认为所有重要知识都已存在于古代经典中。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;第十四章：科学与帝国的联姻 (The Marriage of Science and Empire)&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;科学革命和欧洲帝国主义相互促进，形成了强大的共生关系。&lt;/li&gt;
      &lt;li&gt;科学为帝国提供了技术和合法性，而帝国为科学提供了资金、数据和保护。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;第十五章：资本主义的教条 (The Capitalist Creed)&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;资本主义&lt;/strong&gt;为科学发展提供了经济动力，其核心信念是对“未来”和“增长”的信任。&lt;/li&gt;
      &lt;li&gt;科学、帝国和资本主义形成了一个强大的“铁三角”，共同驱动了现代历史的进程。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;第十六章：工业的巨轮 (The Wheels of Industry)&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;工业革命的核心是&lt;strong&gt;能源转换&lt;/strong&gt;的革命，人类学会了利用各种新能源，摆脱了对自然能量循环的依赖，导致生产力空前爆发。
        &lt;ul&gt;
          &lt;li&gt;不再主要需要生物肌肉进行转换。&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;消费主义兴起，家庭和社区的功能被国家和市场所取代。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;第十七章：国家的胜利 (A Permanent Revolution)&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;工业革命彻底改变了社会结构，传统的家庭和社群解体，取而代之的是&lt;strong&gt;国家&lt;/strong&gt;和&lt;strong&gt;市场&lt;/strong&gt;这两个想象的共同体。
        &lt;ul&gt;
          &lt;li&gt;国家、市场势力强大 -&amp;gt; 个人能力强大 -&amp;gt; 传统社群实力弱 -&amp;gt; 国家、市场势力强大。&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;我们依赖国家提供教育、医疗和安全，依赖市场提供商品和服务。不再继续依赖传统社群提供保障。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;第十八章：和平的时代 (And They Lived Happily Ever After)&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;尽管20世纪有两次世界大战，但二战后，人类进入了有史以来最和平的时期。&lt;/li&gt;
      &lt;li&gt;战争的成本（核武器）急剧上升，而利润却在下降（财富形式转向知识和技术），使得大规模战争变得不划算。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;第十九章：智人的终结 (The End of Homo Sapiens)&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;尽管人类在物质上取得了巨大进步，但我们是否比过去更快乐并不确定。快乐更多取决于&lt;strong&gt;期望&lt;/strong&gt;与&lt;strong&gt;现实&lt;/strong&gt;的差距，以及身体的&lt;strong&gt;生物化学机制&lt;/strong&gt;。&lt;/li&gt;
      &lt;li&gt;人类正开始挑战自然选择的法则，通过&lt;strong&gt;生物工程&lt;/strong&gt;（基因改造）、&lt;strong&gt;仿生工程&lt;/strong&gt;（人机结合）和&lt;strong&gt;无机生命工程&lt;/strong&gt;（人工智能）来升级自己。&lt;/li&gt;
      &lt;li&gt;智人可能即将终结自己的历史，被我们自己创造出的“神人”（Homo Deus）所取代。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;后记：变成神的动物 (The Animal that Became a God)&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;我们从一种无足轻重的动物，通过一系列革命，成为了地球的主宰，正走在将自己升级为“神”的道路上。&lt;/li&gt;
      &lt;li&gt;赫拉利最后提出了一个开放性问题：我们希望自己成为什么样的“神”？拥有神一般的能力，却不知道自己想要什么，这比以往任何时候都更加危险。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
    
      <item>
        <title>Mixture of Experts model papers</title>
        <link>/2025/07/12/moe-papers.html</link>
        <guid isPermaLink="true">/2025/07/12/moe-papers.html</guid>
        <pubDate>Sat, 12 Jul 2025 00:00:00 +0000</pubDate>
        <description>&lt;h2 id=&quot;switch-transformers&quot;&gt;Switch Transformers&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://arxiv.org/abs/2101.03961&quot;&gt;Switch Transformers: Scaling to Trillion Parameter Models with Simple and Efficient Sparsity&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;precursor-of-switch-transformers&quot;&gt;Precursor of Switch Transformers&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://arxiv.org/abs/1701.06538&quot;&gt;Outrageously Large Neural Networks: The Sparsely-Gated Mixture-of-Experts Layer&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;mixtral-sota&quot;&gt;Mixtral SOTA&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://mistral.ai/news/mixtral-of-experts/&quot;&gt;Mixtral of Experts blog post&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;adaptive-mixtures-of-local-experts&quot;&gt;Adaptive mixtures of local experts&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.cs.toronto.edu/~fritz/absps/jjnh91.pdf&quot;&gt;Adaptive mixtures of local experts&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;hierarchical-mixtures-of-experts-and-the-em-algorithm&quot;&gt;Hierarchical Mixtures Of Experts And The Em Algorithm&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.cs.toronto.edu/~hinton/absps/hme.pdf&quot;&gt;Hierarchical Mixtures Of Experts And The Em Algorithm&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;blackboard-design-pattern&quot;&gt;Blackboard design pattern&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://hillside.net/plop/plop97/Proceedings/lalanda.pdf&quot;&gt;Two complementary patterns to build multi-expert systems&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;querying-various-data-sources&quot;&gt;Querying various data sources&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://infolab.stanford.edu/~royg/wsqdsq.pdf&quot;&gt;WSQ/DSQ: A Practical Approach for Combined Querying of Databases and the Web&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://arxiv.org/pdf/1609.07548&quot;&gt;The BigDAWG Polystore System and Architecture&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.vldb.org/conf/1997/P276.PDF&quot;&gt;Garlic: Optimizing Queries across Diverse Data Sources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
    
      <item>
        <title>English phrases</title>
        <link>/2025/06/26/work-english.html</link>
        <guid isPermaLink="true">/2025/06/26/work-english.html</guid>
        <pubDate>Thu, 26 Jun 2025 00:00:00 +0000</pubDate>
        <description>&lt;h2 id=&quot;severance-tv-show&quot;&gt;“Severance” TV show&lt;/h2&gt;

&lt;h3 id=&quot;season-1&quot;&gt;Season 1&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Should I have consulted you?&lt;/li&gt;
  &lt;li&gt;Good initiative&lt;/li&gt;
  &lt;li&gt;Keep it between us&lt;/li&gt;
  &lt;li&gt;That’s one less horrible thing&lt;/li&gt;
  &lt;li&gt;Weird energy&lt;/li&gt;
  &lt;li&gt;Careful out there&lt;/li&gt;
  &lt;li&gt;Thanks for noticing&lt;/li&gt;
  &lt;li&gt;He was coming at you&lt;/li&gt;
  &lt;li&gt;I know what you’re up to&lt;/li&gt;
  &lt;li&gt;Save it&lt;/li&gt;
  &lt;li&gt;I haven’t worked it out yet&lt;/li&gt;
  &lt;li&gt;Are you sweet on this guy&lt;/li&gt;
  &lt;li&gt;You disapprove?&lt;/li&gt;
  &lt;li&gt;Get the hell out of here.&lt;/li&gt;
  &lt;li&gt;You aware what MDR is up to right now?&lt;/li&gt;
  &lt;li&gt;I thought that’s what you were paid for&lt;/li&gt;
  &lt;li&gt;I will have a word with&lt;/li&gt;
  &lt;li&gt;Looks like we both made it through&lt;/li&gt;
  &lt;li&gt;Congratulations there&lt;/li&gt;
  &lt;li&gt;I am a leader who cares about his employees&lt;/li&gt;
  &lt;li&gt;must be held accountable for the actions&lt;/li&gt;
  &lt;li&gt;Change can be disorienting&lt;/li&gt;
  &lt;li&gt;That’s poetic as shit, man&lt;/li&gt;
  &lt;li&gt;We’re not children, we didn’t do anything wrong&lt;/li&gt;
  &lt;li&gt;I trusted you, you abused the trust&lt;/li&gt;
  &lt;li&gt;I’m good with water, thank you&lt;/li&gt;
  &lt;li&gt;It’s a privilege&lt;/li&gt;
  &lt;li&gt;If it’s lame, we will leave&lt;/li&gt;
  &lt;li&gt;How are you holding up&lt;/li&gt;
  &lt;li&gt;I think we gonna take off&lt;/li&gt;
  &lt;li&gt;I’ve had a day&lt;/li&gt;
  &lt;li&gt;You are being weird&lt;/li&gt;
  &lt;li&gt;It’s kind of a big deal for me&lt;/li&gt;
  &lt;li&gt;Just getting a head start on the day&lt;/li&gt;
  &lt;li&gt;Just see how the day goes&lt;/li&gt;
  &lt;li&gt;You look troubled&lt;/li&gt;
  &lt;li&gt;That we shall&lt;/li&gt;
  &lt;li&gt;You deserve something special&lt;/li&gt;
  &lt;li&gt;Stay tuned&lt;/li&gt;
  &lt;li&gt;Not knowing is probably the best&lt;/li&gt;
  &lt;li&gt;Lead the way&lt;/li&gt;
  &lt;li&gt;How about a round of applause for the man of the hour&lt;/li&gt;
  &lt;li&gt;Come and circle up, gather around&lt;/li&gt;
  &lt;li&gt;I come home feeling tired but fulfilled, feel satisfied&lt;/li&gt;
  &lt;li&gt;Bon voyage&lt;/li&gt;
  &lt;li&gt;We made it, despite a staffing shake-up&lt;/li&gt;
  &lt;li&gt;Just now, just a moment ago&lt;/li&gt;
  &lt;li&gt;You do all sorts of wonderful things&lt;/li&gt;
  &lt;li&gt;I just have so much to do today&lt;/li&gt;
  &lt;li&gt;I’m over her, just wanna be friends&lt;/li&gt;
  &lt;li&gt;On your go, then&lt;/li&gt;
  &lt;li&gt;In case we don’t come back. Or, I don’t know, in case we do?&lt;/li&gt;
  &lt;li&gt;Sorry to just pop over&lt;/li&gt;
  &lt;li&gt;I’m not feeling quite myself&lt;/li&gt;
  &lt;li&gt;I don’t want to be nosy(curious)&lt;/li&gt;
  &lt;li&gt;I got a little woozy&lt;/li&gt;
  &lt;li&gt;I’m gonna stop by the bathroom&lt;/li&gt;
  &lt;li&gt;So nice to finally meet you. Likewise.&lt;/li&gt;
  &lt;li&gt;This better be working, assholes&lt;/li&gt;
  &lt;li&gt;You don’t have to weigh in on that&lt;/li&gt;
  &lt;li&gt;Discussing whether it might have been a wiser move for .. to ..&lt;/li&gt;
  &lt;li&gt;This is gonna sound weird&lt;/li&gt;
  &lt;li&gt;I know&lt;/li&gt;
  &lt;li&gt;I’m certainly gonna try&lt;/li&gt;
  &lt;li&gt;Family is both my bedrock and my inspiration&lt;/li&gt;
  &lt;li&gt;I can crane&lt;/li&gt;
  &lt;li&gt;It’s going great&lt;/li&gt;
  &lt;li&gt;The drink just hit me a bit&lt;/li&gt;
  &lt;li&gt;Spared from the pain&lt;/li&gt;
  &lt;li&gt;Lumon has their hands in so many pies&lt;/li&gt;
  &lt;li&gt;I will tee you up&lt;/li&gt;
  &lt;li&gt;Just stick to the talking points&lt;/li&gt;
  &lt;li&gt;Use the line that …&lt;/li&gt;
  &lt;li&gt;Bumps in the roads&lt;/li&gt;
  &lt;li&gt;With any transformative technology, there have been setbacks&lt;/li&gt;
  &lt;li&gt;We are on a verge of a revolution&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;season-2&quot;&gt;Season 2&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;I think it’s best to save any queries till&lt;/li&gt;
  &lt;li&gt;Been a minute&lt;/li&gt;
  &lt;li&gt;We have much to discuss, I don’t want them distracting you.&lt;/li&gt;
  &lt;li&gt;But we must be cut to heal&lt;/li&gt;
  &lt;li&gt;I’d like to hear it from them&lt;/li&gt;
  &lt;li&gt;Please see that it’s taken care of.&lt;/li&gt;
  &lt;li&gt;I will put some thoughts on it.&lt;/li&gt;
  &lt;li&gt;If anything of note occurred&lt;/li&gt;
  &lt;li&gt;I feel confident that he’d approve me saying so&lt;/li&gt;
  &lt;li&gt;Let’s Occam’s razor this shit&lt;/li&gt;
  &lt;li&gt;I imagine you have a few questions&lt;/li&gt;
  &lt;li&gt;You could say that&lt;/li&gt;
  &lt;li&gt;You have my word&lt;/li&gt;
  &lt;li&gt;We do need to know what we’re dealing with&lt;/li&gt;
  &lt;li&gt;We’ve just said all there is to say&lt;/li&gt;
  &lt;li&gt;I will circle back&lt;/li&gt;
  &lt;li&gt;If we can just get a half-step more confirmation&lt;/li&gt;
  &lt;li&gt;My third question concerns …&lt;/li&gt;
  &lt;li&gt;It just takes time, I hope you give us that time&lt;/li&gt;
  &lt;li&gt;Hopefully there will be some chemistry&lt;/li&gt;
  &lt;li&gt;Of course, I bear full responsibility&lt;/li&gt;
  &lt;li&gt;This is unheard of&lt;/li&gt;
  &lt;li&gt;Everything chill?&lt;/li&gt;
  &lt;li&gt;Looks like you can use some coffee&lt;/li&gt;
  &lt;li&gt;Not like we have a lot of options right now&lt;/li&gt;
  &lt;li&gt;You don’t have an objective perspective due to&lt;/li&gt;
  &lt;li&gt;I’m teasing&lt;/li&gt;
  &lt;li&gt;xx has forced our hand&lt;/li&gt;
  &lt;li&gt;I don’t give three dry fuck to xx&lt;/li&gt;
  &lt;li&gt;Wow, some actual honesty&lt;/li&gt;
  &lt;li&gt;If you are taking feedback, I hate it&lt;/li&gt;
  &lt;li&gt;Words has consequences&lt;/li&gt;
  &lt;li&gt;A little sugar with your usual salt&lt;/li&gt;
  &lt;li&gt;Well, I hope that won’t be necessary&lt;/li&gt;
  &lt;li&gt;But the bulk of our day will revolve around the following&lt;/li&gt;
  &lt;li&gt;It’s quite a legacy you will leave&lt;/li&gt;
  &lt;li&gt;I’m tightening the leash&lt;/li&gt;
  &lt;li&gt;Have a restful evening&lt;/li&gt;
  &lt;li&gt;I’m just trying to speak their language&lt;/li&gt;
  &lt;li&gt;I will reflect on your words&lt;/li&gt;
  &lt;li&gt;This is a fiscal and creative opportunity unlike any I’ve ever seen, I’m not inclined to walk away from it&lt;/li&gt;
  &lt;li&gt;Call it a quirk&lt;/li&gt;
  &lt;li&gt;Using your time well, focusing on your own duty&lt;/li&gt;
  &lt;li&gt;She tricked both of us&lt;/li&gt;
  &lt;li&gt;You have a lot of stages, diverse&lt;/li&gt;
  &lt;li&gt;He is looking for the exit&lt;/li&gt;
  &lt;li&gt;I heard nothing but good things about you&lt;/li&gt;
  &lt;li&gt;Please don’t mess with me&lt;/li&gt;
  &lt;li&gt;It’s a settled fxxking law, the end&lt;/li&gt;
  &lt;li&gt;Locked and loaded&lt;/li&gt;
  &lt;li&gt;That’s kind of you&lt;/li&gt;
  &lt;li&gt;I’m not sick, I just needed the day, ok?&lt;/li&gt;
  &lt;li&gt;I have your word …?&lt;/li&gt;
  &lt;li&gt;I took their word for it&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;common-english-phrases-for-daily-life&quot;&gt;Common English phrases for daily life&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://youtu.be/md3HfH0SWOI?si=VSSdco2poFOscjK9&quot;&gt;“English in Comfort” podcast&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;“How’s it going?”&lt;/strong&gt; - A casual way to ask “how are you?”&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“I’m just chilling”&lt;/strong&gt; - Relaxing and taking it easy.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Grab a bite”&lt;/strong&gt; - Getting a quick meal or snack.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Call it a day”&lt;/strong&gt; - Stopping work or an activity.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Take a break”&lt;/strong&gt; - Pausing to rest.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Run errands”&lt;/strong&gt; - Completing small tasks.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Keep in touch”&lt;/strong&gt; - Staying connected with someone.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“In a hurry”&lt;/strong&gt; - Rushing or not having much time.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Pick up”&lt;/strong&gt; - Collecting something or someone.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Just in case”&lt;/strong&gt; - Being prepared for a possibility.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Get things done”&lt;/strong&gt; - Being productive.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Catch up”&lt;/strong&gt; - Reconnecting or getting back on track.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Out of order”&lt;/strong&gt; - Something is broken.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“On the go”&lt;/strong&gt; - Being busy and moving.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Make the most of it”&lt;/strong&gt; - Taking full advantage of a situation.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Settle down”&lt;/strong&gt; - Calming down or establishing a stable lifestyle.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Hang out”&lt;/strong&gt; - Spending time casually with someone.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Hit the road”&lt;/strong&gt; - Leaving or starting a journey.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Break the ice”&lt;/strong&gt; - Starting a conversation in an awkward situation.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Get the ball rolling”&lt;/strong&gt; - Starting a project or discussion.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“What’s up”&lt;/strong&gt; - A casual greeting.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Long time no see”&lt;/strong&gt; - Used when you haven’t seen someone in a while.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“I’m beat”&lt;/strong&gt; - Being very tired.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“It’s a piece of cake”&lt;/strong&gt; - Something is very easy.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Call it a night”&lt;/strong&gt; - Stopping an activity for the evening.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Running late”&lt;/strong&gt; - Being behind schedule.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Hold on a second”&lt;/strong&gt; - Asking someone to wait.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“It slipped my mind”&lt;/strong&gt; - Forgetting something.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“I’m all ears”&lt;/strong&gt; - Ready to listen attentively.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“It’s on me”&lt;/strong&gt; - Offering to pay.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Play it by ear”&lt;/strong&gt; - Deciding plans as you go.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Feeling under the weather”&lt;/strong&gt; - Not feeling well.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Hit the hay”&lt;/strong&gt; - Going to bed.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Not a big deal”&lt;/strong&gt; - Something isn’t important.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Pulling your leg”&lt;/strong&gt; - Joking or teasing.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Get down to business”&lt;/strong&gt; - Focusing on a task.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“In the same boat”&lt;/strong&gt; - Being in the same situation.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“It’s up to you”&lt;/strong&gt; - Letting someone else decide.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“I’m swamped”&lt;/strong&gt; - Being very busy.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Wrap it up”&lt;/strong&gt; - Finishing something.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Throw someone under the bus”&lt;/strong&gt; - Blaming someone else.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Spill the beans”&lt;/strong&gt; - Revealing a secret.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Hit the nail on the head”&lt;/strong&gt; - Being exactly right.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Think outside the box”&lt;/strong&gt; - Being creative.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Take it with a grain of salt”&lt;/strong&gt; - Not believing something completely.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Once in a blue moon”&lt;/strong&gt; - Something happens rarely.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“On the same page”&lt;/strong&gt; - Agreeing or understanding a plan.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Cutting edge”&lt;/strong&gt; - Super modern or advanced.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Back to the drawing board”&lt;/strong&gt; - Starting over after a failure.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Burn the midnight oil”&lt;/strong&gt; - Working late into the night.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“The ball is in your court”&lt;/strong&gt; - It’s your turn to decide or act.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Cost an arm and a leg”&lt;/strong&gt; - Something is very expensive.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Sit on the fence”&lt;/strong&gt; - Unable to decide.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Bite the bullet”&lt;/strong&gt; - Doing something difficult you have to do.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“In a nutshell”&lt;/strong&gt; - Summarizing something briefly.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Take it easy”&lt;/strong&gt; - Relaxing or not worrying.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“That’s a win-win”&lt;/strong&gt; - A situation where everyone benefits.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“You’re spot on”&lt;/strong&gt; - You’re exactly right.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Not my cup of tea”&lt;/strong&gt; - A polite way to say you don’t like something.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“That’s the last straw”&lt;/strong&gt; - When a small thing finally makes you lose patience.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Hang in there”&lt;/strong&gt; - Encouraging someone who is struggling.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“I’m on it”&lt;/strong&gt; - You’ll handle something right away.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Break a leg”&lt;/strong&gt; - Wishing someone good luck.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“What do you have in mind”&lt;/strong&gt; - Asking for someone’s idea.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“It’s a no-brainer”&lt;/strong&gt; - An easy decision.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“I’ll sleep on it”&lt;/strong&gt; - Needing time to decide.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“That rings a bell”&lt;/strong&gt; - Something sounds familiar.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Go the extra mile”&lt;/strong&gt; - Putting in more effort.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Cut corners”&lt;/strong&gt; - Doing something cheaply and badly.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Cross that bridge when we come to it”&lt;/strong&gt; - Dealing with a problem later.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Let’s face it”&lt;/strong&gt; - Acknowledging an uncomfortable truth.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“I’m on the fence”&lt;/strong&gt; - Being unsure.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Let’s shake on it”&lt;/strong&gt; - Informally agreeing.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“It’s up in the air”&lt;/strong&gt; - Plans are uncertain.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Running on fumes”&lt;/strong&gt; - Being exhausted.&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
    
      <item>
        <title>C++ data structures for leetcode</title>
        <link>/2024/01/14/c-data-structures-for-leetcode.html</link>
        <guid isPermaLink="true">/2024/01/14/c-data-structures-for-leetcode.html</guid>
        <pubDate>Sun, 14 Jan 2024 00:00:00 +0000</pubDate>
        <description>&lt;h2 id=&quot;stdvector&quot;&gt;std::vector&lt;/h2&gt;

&lt;div class=&quot;language-c++ 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;// constructors
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// size of 5
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 5 ints with value 1
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// copying v3
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// copying v3
// construct from arrays
&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;int_arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;int_arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;int_arr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;int_arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;emplace_back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pop_back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; 
&lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;erase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// return the iterator of the next element.
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// insert 5 before the iter element.
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&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;h2 id=&quot;stdunordered_map&quot;&gt;std::unordered_map&lt;/h2&gt;

&lt;div class=&quot;language-c++ 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;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unordered_map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;found&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;found&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;found&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;found&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// key, value
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;stdheap&quot;&gt;std::heap&lt;/h2&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;stdstring&quot;&gt;std::string&lt;/h2&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;stdqueue&quot;&gt;std::queue&lt;/h2&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;stdstack&quot;&gt;std::stack&lt;/h2&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;arrays&quot;&gt;arrays&lt;/h2&gt;

&lt;div class=&quot;language-c++ 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;n&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;persons&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Volvo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;BMW&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Ford&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Pass string array as argument
&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myFunction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cars&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;h2 id=&quot;string-functions&quot;&gt;string functions&lt;/h2&gt;

&lt;div class=&quot;language-c++ 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;// string to integer
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;-12.3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stoi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// -12
// string to long
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// -12
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Append characters
&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;my_char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;'!'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;my_char&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;h2 id=&quot;new-data&quot;&gt;new data&lt;/h2&gt;

&lt;div class=&quot;language-c++ 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;cm&quot;&gt;/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Solution&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;TreeNode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createNewRoot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TreeNode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;TreeNode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_node&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TreeNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;nullptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&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;
</description>
      </item>
    
      <item>
        <title>Reading &quot;Clean code&quot;</title>
        <link>/2022/05/28/clean-code.html</link>
        <guid isPermaLink="true">/2022/05/28/clean-code.html</guid>
        <pubDate>Sat, 28 May 2022 00:00:00 +0000</pubDate>
        <description>&lt;ul&gt;
  &lt;li&gt;Clean codes are elegant and efficient.
    &lt;ul&gt;
      &lt;li&gt;Straightforward, minimal dependencies, articulated error handling, optimal performance, does one thing well.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Boy Scout Rule: Leave the campground cleaner than you found it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;meaningful-names&quot;&gt;Meaningful names&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Use intention-revealing names
    &lt;ul&gt;
      &lt;li&gt;Answers all big questions; no comment required&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Avoid disinformation
    &lt;ul&gt;
      &lt;li&gt;Like single-letter names&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Make meaningful distinctions
    &lt;ul&gt;
      &lt;li&gt;Not sufficient to add numbers, noise words or prefix conventions (“a”, “the”, etc) to distinguish two similar variables
        &lt;ul&gt;
          &lt;li&gt;e.g., &lt;code class=&quot;highlighter-rouge&quot;&gt;list_1&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;list_2&lt;/code&gt;; &lt;code class=&quot;highlighter-rouge&quot;&gt;product_info&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;product_data&lt;/code&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Use pronounceable names
    &lt;ul&gt;
      &lt;li&gt;Avoid names like &lt;code class=&quot;highlighter-rouge&quot;&gt;genymdhms&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Use searchable names
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;MAX_CLASSES_PER_STUDENT&lt;/code&gt; instead of 7.&lt;/li&gt;
      &lt;li&gt;Single-letter names may be fine as a local variable inside short methods.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Avoid encodings
    &lt;ul&gt;
      &lt;li&gt;Avoid encode type or scope information into names&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;No member prefixes like &lt;code class=&quot;highlighter-rouge&quot;&gt;m_address&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Interfaces and implementations
    &lt;ul&gt;
      &lt;li&gt;Prefer to leave interfaces unadorned, &lt;code class=&quot;highlighter-rouge&quot;&gt;ShapeFactory&lt;/code&gt; instead of &lt;code class=&quot;highlighter-rouge&quot;&gt;IShapeFactory&lt;/code&gt;. Users don’t need to know we are handling them an interface. Implementations can be encoded like &lt;code class=&quot;highlighter-rouge&quot;&gt;ShapeFactoryImpl&lt;/code&gt;.&lt;/li&gt;
      &lt;li&gt;Avoid mental mapping
        &lt;ul&gt;
          &lt;li&gt;Readers shouldn’t have to mentally translated a name into other name they already know, like &lt;code class=&quot;highlighter-rouge&quot;&gt;t&lt;/code&gt; for &lt;code class=&quot;highlighter-rouge&quot;&gt;time&lt;/code&gt;.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Class names
    &lt;ul&gt;
      &lt;li&gt;Should be noun or noun phrases like &lt;code class=&quot;highlighter-rouge&quot;&gt;Customer&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;Account&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;AddressParser&lt;/code&gt;.&lt;/li&gt;
      &lt;li&gt;Choose a more descriptive names, avoid &lt;code class=&quot;highlighter-rouge&quot;&gt;Manager&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;Processor&lt;/code&gt; &lt;code class=&quot;highlighter-rouge&quot;&gt;Data&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;Info&lt;/code&gt;.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Method names
    &lt;ul&gt;
      &lt;li&gt;Should be verb or verb phrases.&lt;/li&gt;
      &lt;li&gt;Try use &lt;code class=&quot;highlighter-rouge&quot;&gt;get&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;set&lt;/code&gt; prefixes.&lt;/li&gt;
      &lt;li&gt;When the constructors are overloaded, prefer static factory methods with names that describe the arguments.
        &lt;ul&gt;
          &lt;li&gt;e.g., &lt;code class=&quot;highlighter-rouge&quot;&gt;Complex.FromRealNumber(23.0)&lt;/code&gt; is better than &lt;code class=&quot;highlighter-rouge&quot;&gt;new Complex(23.0)&lt;/code&gt;.&lt;/li&gt;
          &lt;li&gt;Consider making corrsponding constructors private.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Don’t be cute
    &lt;ul&gt;
      &lt;li&gt;Say what you mean. Avoid using slangs. Just &lt;code class=&quot;highlighter-rouge&quot;&gt;DeleteItems&lt;/code&gt; instead of &lt;code class=&quot;highlighter-rouge&quot;&gt;HolyHandGrenade&lt;/code&gt;.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Pick one word per concept
    &lt;ul&gt;
      &lt;li&gt;and stick with it. &lt;code class=&quot;highlighter-rouge&quot;&gt;get&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;fetch&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;retrieve&lt;/code&gt;; &lt;code class=&quot;highlighter-rouge&quot;&gt;controller&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;manager&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;driver&lt;/code&gt; etc.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Use solution domain names
    &lt;ul&gt;
      &lt;li&gt;CS terms, algorithm names etc. &lt;code class=&quot;highlighter-rouge&quot;&gt;Visitor&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;Queue&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Using problem domain names&lt;/li&gt;
  &lt;li&gt;Add meaningful context
    &lt;ul&gt;
      &lt;li&gt;Use &lt;code class=&quot;highlighter-rouge&quot;&gt;addrState&lt;/code&gt; to note the state is for address. Using an &lt;code class=&quot;highlighter-rouge&quot;&gt;Address&lt;/code&gt; class is even better.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Don’t add gratuitous context
    &lt;ul&gt;
      &lt;li&gt;Don’t use the same prefix for many methods and classes. Shorter names are generally better. Add no more context to a name than is necessary.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;functions&quot;&gt;Functions&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Small
    &lt;ul&gt;
      &lt;li&gt;Functions should hardly ever be 20 lines long.&lt;/li&gt;
      &lt;li&gt;The indent level of a function should not be greater than one or two.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Do one thing
    &lt;ul&gt;
      &lt;li&gt;Do it well and do it only.&lt;/li&gt;
      &lt;li&gt;Sections within functions, a clear indication that a function is doing more than one thing.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;One level of abstraction per function&lt;/li&gt;
  &lt;li&gt;The stepdown rule, reading code from top to bottom
    &lt;ul&gt;
      &lt;li&gt;We want the code to read like a top-down narrative.&lt;/li&gt;
      &lt;li&gt;Every function to be followed by those at the next level of abstractions.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
    
      <item>
        <title>读浪潮之巅</title>
        <link>/2021/11/01/riding-the-wave.html</link>
        <guid isPermaLink="true">/2021/11/01/riding-the-wave.html</guid>
        <pubDate>Mon, 01 Nov 2021 00:00:00 +0000</pubDate>
        <description>&lt;h2 id=&quot;帝国余晖att&quot;&gt;帝国余晖，AT&amp;amp;T&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;1877年创始，贝尔电话公司&lt;/li&gt;
  &lt;li&gt;1885年为长途电话业务设立AT&amp;amp;T子公司&lt;/li&gt;
  &lt;li&gt;1916年，成为道琼斯指数成分股&lt;/li&gt;
  &lt;li&gt;1925年成立Bell Labs，同时分离加拿大电信业务
    &lt;ul&gt;
      &lt;li&gt;后来加拿大部分发展成北方电信&lt;/li&gt;
      &lt;li&gt;收缩可能帮助躲过大萧条&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;1956年，司法部协议限制活动范围
    &lt;ul&gt;
      &lt;li&gt;垄断法逼着公司追求技术进步，而不是单纯利用垄断资源&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;1984年反垄断拆分，市话业务剥离成8家Baby Bell公司（包括SBC），主体更名为AT&amp;amp;T
    &lt;ul&gt;
      &lt;li&gt;因垄断美国电信业&lt;/li&gt;
      &lt;li&gt;之后10年间， AT&amp;amp;T在电话，网络与移动通信业务上一直世界领先&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;1995年，内部提出拆分计划&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;三部分：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;AT&amp;amp;T: 电信服务
    &lt;ul&gt;
      &lt;li&gt;2004年拆分为：
        &lt;ul&gt;
          &lt;li&gt;AT&amp;amp;T：个人和企业业务
            &lt;ul&gt;
              &lt;li&gt;传统长途电话业务&lt;/li&gt;
              &lt;li&gt;没有发展潜力&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
          &lt;li&gt;AT&amp;amp;T Wireless
            &lt;ul&gt;
              &lt;li&gt;没有资金支持扩张&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
          &lt;li&gt;AT&amp;amp;T宽带&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;2004年，道琼斯指数除名&lt;/li&gt;
      &lt;li&gt;2005年，被SBC吞并，基本是没有技术含量的基础设施公司&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;朗讯：设备制造
    &lt;ul&gt;
      &lt;li&gt;这样就可以做其他电信商的生意，销售额增长，股价暴涨10+倍&lt;/li&gt;
      &lt;li&gt;职业经理人，董事会，投资公司看重短期利益&lt;/li&gt;
      &lt;li&gt;朗讯利润不足以支撑两万人的贝尔实验室&lt;/li&gt;
      &lt;li&gt;为了促进收入增长，借钱给其他公司购买其设备
        &lt;ul&gt;
          &lt;li&gt;互联网泡沫破裂后转为亏损&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Carly Fiorina杀鸡取卵，再次拆分无线设备部门Avaya&lt;/li&gt;
      &lt;li&gt;互联网冲击下，数据交换设备（思科）需求超过语音交换设备&lt;/li&gt;
      &lt;li&gt;2006年，阿尔卡特和朗讯合并&lt;/li&gt;
      &lt;li&gt;2016年，被诺基亚收购&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;NCR：计算机业务&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;一些想法：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;幸运的是发现并顺应潮流&lt;/li&gt;
  &lt;li&gt;追求短期利益对公司的伤害很大
    &lt;ul&gt;
      &lt;li&gt;当无人拥有控制权时，长期发展会有问题&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;蓝色巨人ibm&quot;&gt;蓝色巨人，IBM&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;保守&lt;/li&gt;
  &lt;li&gt;to B的先天基因，与政府、军方保持良好关系，客户主要是政府，银行，科研机构，经营终端消费品经验不足。&lt;/li&gt;
  &lt;li&gt;二战后在机械和电子产业中选择电子&lt;/li&gt;
  &lt;li&gt;引领计算机革命，把计算机推向民间，商用&lt;/li&gt;
  &lt;li&gt;司法部发起反垄断诉讼，长达10年&lt;/li&gt;
  &lt;li&gt;推出IBM PC，但是公司不重视&lt;/li&gt;
  &lt;li&gt;和微软的合作中吃亏了
    &lt;ul&gt;
      &lt;li&gt;微软一方面为IBM开发操作系统，一面自己开发Windows&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;1993年，Louis Gerstner接任CEO，把公司转型为以软件和服务为主
    &lt;ul&gt;
      &lt;li&gt;裁撤项目，变卖资产，回收分拆的服务公司&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;用户目标定位为企业，放弃个人消费者&lt;/li&gt;
  &lt;li&gt;申请很多进攻性专利，收益不菲&lt;/li&gt;
  &lt;li&gt;不断剥离利润低业务，总利润增长&lt;/li&gt;
  &lt;li&gt;在金融危机中股价也很稳定，
    &lt;ul&gt;
      &lt;li&gt;因为是给大客户卖服务，有持续收入&lt;/li&gt;
      &lt;li&gt;把很多工作岗位迁到印度&lt;/li&gt;
      &lt;li&gt;全球化收入&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;发展云计算，人工智能沃森&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;八叛徒与硅谷&quot;&gt;八叛徒与硅谷&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;William Shockley在贝尔实验室发明晶体管&lt;/li&gt;
  &lt;li&gt;1955年Shockley辞去工作在湾区创建公司生产半导体
    &lt;ul&gt;
      &lt;li&gt;期间招来包括Robert Noyce等人&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;1956年，八人受不了Shockley的独裁作风，集体离职&lt;/li&gt;
  &lt;li&gt;1957年，Traitorous Eight，八人创办仙童公司，得到IBM大股东仙童家族的投资&lt;/li&gt;
  &lt;li&gt;仙童公司拿到军工和IBM的晶体管合同，不到一年盈利&lt;/li&gt;
  &lt;li&gt;1958年诺伊斯发明集成电路&lt;/li&gt;
  &lt;li&gt;硅谷的发展
    &lt;ul&gt;
      &lt;li&gt;1951年斯坦福设立斯坦福工业园，吸引科技公司&lt;/li&gt;
      &lt;li&gt;1952年IBM创立Almanden lab&lt;/li&gt;
      &lt;li&gt;仙童公司流失的人才在当地创业
        &lt;ul&gt;
          &lt;li&gt;当时集成电路成本高，仙童公司投资人希望优先发展成熟的晶体管产业赚钱。多人离职建立集成电路和投资公司
            &lt;ul&gt;
              &lt;li&gt;Teledyne，Signetics，Molectro，Kleiner Perkins，Sequoia Capital，Intel&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;革命性技术出现，诞生一家巨无霸公司，既有可能压榨本地区其他新公司的产生，也有可能开枝散叶，促进地区发展&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;科技时尚苹果&quot;&gt;科技时尚，苹果&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;1976年，乔布斯和Steve Wozniak，Ron Wayne创办苹果
    &lt;ul&gt;
      &lt;li&gt;推出几百美金的Apple I&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;1984年推出Macintosh
    &lt;ul&gt;
      &lt;li&gt;图形交互系统，优于IBM PC，但是是施乐开发的&lt;/li&gt;
      &lt;li&gt;封闭硬件系统，不允许兼容机&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;1985年，乔布斯与CEO产生矛盾，被董事会踢出公司&lt;/li&gt;
  &lt;li&gt;乔布斯买下Pixar动画工作室，最后被迪士尼收购&lt;/li&gt;
  &lt;li&gt;苹果公司市场不断萎缩，开始亏损&lt;/li&gt;
  &lt;li&gt;1997年乔布斯回归，开始打造性能和时尚
    &lt;ul&gt;
      &lt;li&gt;同时采用Intel通用处理器和FreeBSD系统内核，方便开发者&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;2001年推出iPod，很成功&lt;/li&gt;
  &lt;li&gt;2006年，推出Apple TV，但是不太兼容市场上的设备&lt;/li&gt;
  &lt;li&gt;2007年开始陆续推出iPhone，iPad，大获成功&lt;/li&gt;
  &lt;li&gt;擅长发现事物的价值，背后是长时间的思考沉淀，还有对品质的追求&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;信息产业的生态链&quot;&gt;信息产业的生态链&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Moore’s Law
    &lt;ul&gt;
      &lt;li&gt;每18个月，集成电路集成度翻一番，IT产品性能翻一番&lt;/li&gt;
      &lt;li&gt;技术公司基础架构升级要按目前计算能力和存储量的10倍来设计&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Andy and Bill’s Law
    &lt;ul&gt;
      &lt;li&gt;What Andy gives，Bill takes away。 Andy Grove是Intel CEO。Bill是Bill Gates。&lt;/li&gt;
      &lt;li&gt;微软等软件公司的新软件把硬件提示的好处几乎用光了，实际使用体验差别不大。
        &lt;ul&gt;
          &lt;li&gt;迫使用户更新机器，使硬件公司收益，形成WinTel产业格局。&lt;/li&gt;
          &lt;li&gt;安卓联盟也类似&lt;/li&gt;
          &lt;li&gt;同时因为Windows很久没更新，导致Intel等硬件厂商升级PC产品的动力不大&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Reverse Moore’s Law
    &lt;ul&gt;
      &lt;li&gt;Eric Schmidt：如果一个IT公司今天和18个月前卖掉同样多的同样产品，营业额会下降一半。&lt;/li&gt;
      &lt;li&gt;硬件公司生计比较艰难&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;奔腾的芯intel&quot;&gt;奔腾的芯，Intel&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;1968年，Gordon Moore和Robert Noyce创办，主打低端微处理器。&lt;/li&gt;
  &lt;li&gt;1981年，IBM PC采用Intel 8086处理器。大量兼容机厂商都选用Intel处理器&lt;/li&gt;
  &lt;li&gt;80年代开发80386和80486，坐上半导体行业头把交椅。
    &lt;ul&gt;
      &lt;li&gt;期间和摩托罗拉竞争，技术上相对落后却占据更多市场份额
        &lt;ul&gt;
          &lt;li&gt;强援IBM、微软&lt;/li&gt;
          &lt;li&gt;管理层和公司激励制度优势&lt;/li&gt;
          &lt;li&gt;专注于处理器&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;指令集
    &lt;ul&gt;
      &lt;li&gt;复杂指令集CISC
        &lt;ul&gt;
          &lt;li&gt;设计复杂，需要很高集成度&lt;/li&gt;
          &lt;li&gt;指令执行时间不一样长，造成不必要等待&lt;/li&gt;
          &lt;li&gt;高功耗&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;精简指令集RISC
        &lt;ul&gt;
          &lt;li&gt;John Hennessy‘s MIPS， David Patterson&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Intel x86系列是CISC，后来产品选择继续兼容
        &lt;ul&gt;
          &lt;li&gt;研发投入大，提高处理器性能&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;6大其他坚持RISC的厂商的处理器做不下去&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;和AMD
    &lt;ul&gt;
      &lt;li&gt;AMD主要做兼容英特尔的便宜替代品&lt;/li&gt;
      &lt;li&gt;反垄断给AMD带来好处&lt;/li&gt;
      &lt;li&gt;AMD在高端服务器市场发起挑战&lt;/li&gt;
      &lt;li&gt;Intel推出酷睿系列，和AMD打价格战，夺回主动权&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;错失移动时代
    &lt;ul&gt;
      &lt;li&gt;在PC处理器以外的芯片研发一直失败，把移动和通信处理器业务卖给Marvell&lt;/li&gt;
      &lt;li&gt;商业模式是大投入大批量，所以新兴市场一开始很难盈利&lt;/li&gt;
      &lt;li&gt;ARM-based RISC芯片占据智能手机市场98%以上份额&lt;/li&gt;
      &lt;li&gt;PC市场逐渐萎缩，远景不容乐观&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;罗马帝国微软&quot;&gt;罗马帝国，微软&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;1981年乔布斯曾向盖茨展示过图形操作系统
    &lt;ul&gt;
      &lt;li&gt;给别的公司做报告的内容确保都是公开发表过的&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;垄断操作系统就间接垄断了整个PC行业&lt;/li&gt;
  &lt;li&gt;对苹果三管齐下
    &lt;ul&gt;
      &lt;li&gt;承诺为Macintosh开发应用软件&lt;/li&gt;
      &lt;li&gt;和IBM合作开发OS/2&lt;/li&gt;
      &lt;li&gt;悄悄开发Windows
        &lt;ul&gt;
          &lt;li&gt;利用DOS争取大概10年时间
            &lt;ul&gt;
              &lt;li&gt;近乎免费给IBM PC提供BASIC和DOS，麻痹IBM，使用户和开发者产生依赖&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;苹果的失误
        &lt;ul&gt;
          &lt;li&gt;封闭系统，放弃兼容机市场
            &lt;ul&gt;
              &lt;li&gt;摩尔定律/安迪比尔定律决定了一家公司吃不下整个PC市场
                &lt;ul&gt;
                  &lt;li&gt;软件更新带动硬件发展&lt;/li&gt;
                &lt;/ul&gt;
              &lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
          &lt;li&gt;少有第三方开发软件&lt;/li&gt;
          &lt;li&gt;各代之间不兼容&lt;/li&gt;
          &lt;li&gt;公司内部不稳定&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;1990年推出Windows 3.0成功
    &lt;ul&gt;
      &lt;li&gt;推出办公软件、浏览器等，打败Lotus，Netscape等应用软件公司
        &lt;ul&gt;
          &lt;li&gt;全力开发IE浏览器，捆绑销售&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;2000年被诉垄断，败诉然后共和党上台翻案&lt;/li&gt;
  &lt;li&gt;因为抄袭行为在知识产权上侵权案很多&lt;/li&gt;
  &lt;li&gt;从普通人身上赚钱，而不是狠宰富人&lt;/li&gt;
  &lt;li&gt;内部争端，操作系统派/toB vs 浏览器派/toC
    &lt;ul&gt;
      &lt;li&gt;操作系统派获胜，因为会平稳度过金融危机或互联网泡沫&lt;/li&gt;
      &lt;li&gt;IE部门大量核心员工离职，从此发展缓慢&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;苹果好比古希腊，微软好比罗马帝国
    &lt;ul&gt;
      &lt;li&gt;罗马帝国大军出征日耳曼，条顿堡之战被全歼，没有复仇&lt;/li&gt;
      &lt;li&gt;雅虎阻击了微软向互联网的扩张
        &lt;ul&gt;
          &lt;li&gt;免费向用户提供服务，向内容提供者和广告主收钱&lt;/li&gt;
          &lt;li&gt;华尔街看好，市盈率达到1000&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;互联网泡沫破裂时，也没有收入人才和技术
        &lt;ul&gt;
          &lt;li&gt;傲慢&lt;/li&gt;
          &lt;li&gt;反垄断限制&lt;/li&gt;
          &lt;li&gt;为了财报不愿搞长线投资&lt;/li&gt;
          &lt;li&gt;对互联网不看好&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;2011年Google发现Bing在抄其搜索结果。微软也发起对Google的反垄断诉求&lt;/li&gt;
      &lt;li&gt;搞智能家庭
        &lt;ul&gt;
          &lt;li&gt;游戏机业务长期亏损&lt;/li&gt;
          &lt;li&gt;Netflix在家庭娱乐中崛起，和Youtube，Chromecast分庭抗礼&lt;/li&gt;
          &lt;li&gt;Google Home，Nest，Amazon Alexa&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;互联网争夺
        &lt;ul&gt;
          &lt;li&gt;引入陆奇主管在线部门，加大研发投入，和雅虎百度在搜索上合作&lt;/li&gt;
          &lt;li&gt;开始Bing每年亏损20亿美元&lt;/li&gt;
          &lt;li&gt;Chrome崛起，IE市场份额只占5%&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;苹果动摇微软根基
        &lt;ul&gt;
          &lt;li&gt;苹果请回乔布斯，恳求盖茨，获得投资起死回生&lt;/li&gt;
          &lt;li&gt;互联网泡沫破裂后，持有现金却没有布局新业务，而是派发股息&lt;/li&gt;
          &lt;li&gt;企业部分利润做勾搭，失去开发优秀toC产品的能力&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;纳德拉扭转颓势
        &lt;ul&gt;
          &lt;li&gt;强化企业级业务，砍掉互联网，亚洲研究院，移动业务，即时通讯
            &lt;ul&gt;
              &lt;li&gt;利润80%以上的Office套件和数据库业务&lt;/li&gt;
              &lt;li&gt;大力发展Azure&lt;/li&gt;
              &lt;li&gt;Office转为Online subscription模式&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;纯软件先驱甲骨文&quot;&gt;纯软件先驱，甲骨文&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;1977年埃里森等人创办公司，推出关系型数据库Oracle
    &lt;ul&gt;
      &lt;li&gt;之间占统治地位的是Hierarchical model和Network model&lt;/li&gt;
      &lt;li&gt;关系型讲数据库的物理层和逻辑层完全分离
        &lt;ul&gt;
          &lt;li&gt;可以实现非常复杂的查询逻辑&lt;/li&gt;
          &lt;li&gt;实现大型复杂数据库&lt;/li&gt;
          &lt;li&gt;逻辑层开发难度较低&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;1981年Gupta加入，明确发展方向为开发通用关系型数据库系统&lt;/li&gt;
  &lt;li&gt;大量并购其他公司&lt;/li&gt;
  &lt;li&gt;2000年与微软，IBM在数据库系统三足鼎立，但此后发展速度远高于对手
    &lt;ul&gt;
      &lt;li&gt;专注于数据库市场，更容易获得用户认可&lt;/li&gt;
      &lt;li&gt;注重成本控制和利润&lt;/li&gt;
      &lt;li&gt;多次成功并购，Peoplesoft, Siebel, Hyperion, BEA, Sun&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;2010年并购Sun，专利诉讼谷歌，败诉&lt;/li&gt;
  &lt;li&gt;2011年开始进入云计算领域&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;golden-gate-bridge思科&quot;&gt;Golden gate bridge，思科&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;斯坦福Leonard Bosack和Sandy Lerner发明了多协议路由器，可以支持各种网络服务器和协议。&lt;/li&gt;
  &lt;li&gt;1984年创办思科，1986年推出第一款产品，顺应了互联网刚起步的需求&lt;/li&gt;
  &lt;li&gt;CEO钱伯斯培育了健康的公司文化
    &lt;ul&gt;
      &lt;li&gt;曾在IBM和王安电脑工作，总结企业文化上失败的教训&lt;/li&gt;
      &lt;li&gt;对员工慷慨大度&lt;/li&gt;
      &lt;li&gt;无条件满足客户需求&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;宽容内部创业的政策&lt;/li&gt;
  &lt;li&gt;收购很多前员工创业的公司&lt;/li&gt;
  &lt;li&gt;毛利率高达60%
    &lt;ul&gt;
      &lt;li&gt;微软80%， 硬件商20%， 石油工业35%, 华为40%&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;竞争对手
    &lt;ul&gt;
      &lt;li&gt;Juniper Networks
        &lt;ul&gt;
          &lt;li&gt;规模小，定位高端&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;华为
        &lt;ul&gt;
          &lt;li&gt;请大批IBM顾问打造国际化企业&lt;/li&gt;
          &lt;li&gt;压榨整个行业的利润空间，思科没有胜算&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Peter Novig：当一家公司的 市场占有率超过50%以后,就不要再指望在市场占有率上翻番了
    &lt;ul&gt;
      &lt;li&gt;当公司占据大部分市场时，再进一步扩招也很难使公司再扩张一倍&lt;/li&gt;
      &lt;li&gt;需要开拓新市场
        &lt;ul&gt;
          &lt;li&gt;思科的VoIP （Voice over IP)&lt;/li&gt;
          &lt;li&gt;华为进军智能手机市场&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;英名不朽杨致远david-filoyahoo&quot;&gt;英名不朽，杨致远，David Filo，Yahoo！&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;制定游戏规则：开放，免费和盈利。&lt;/li&gt;
  &lt;li&gt;商业模式：用户和客户可以不是同一群体&lt;/li&gt;
  &lt;li&gt;三个斯坦福同学开发了一个门户网站，流量暴增
    &lt;ul&gt;
      &lt;li&gt;无条件，开发的为全世界网站建立索引&lt;/li&gt;
      &lt;li&gt;制止了AOL等公司把互联网办成另一个电话网的企图&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;软银投资，一度占近40%股份&lt;/li&gt;
  &lt;li&gt;杨致远想到打广告赚钱的法子
    &lt;ul&gt;
      &lt;li&gt;2014年美国广告市场规模大概$180B&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;流量第一，专心办互联网上最好的媒体
    &lt;ul&gt;
      &lt;li&gt;流量不平等，一流品牌在一流媒体做广告&lt;/li&gt;
      &lt;li&gt;对流量的片面重视，导致很多网站不重视内容，雅虎也不能免俗&lt;/li&gt;
      &lt;li&gt;互联网泡沫破裂，市值蒸发90%&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;复苏
    &lt;ul&gt;
      &lt;li&gt;裁撤亏损项目&lt;/li&gt;
      &lt;li&gt;Terry Semel和Overture合作，使用搜索结果中竞价排名的方法&lt;/li&gt;
      &lt;li&gt;买下搜索引擎Inktomi公司，后来买下被Google重击几次的Overture&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;收入主要靠
    &lt;ul&gt;
      &lt;li&gt;传统的品牌广告，是雅虎的强项&lt;/li&gt;
      &lt;li&gt;在线搜索广告，是技术竞争，Google占优势
        &lt;ul&gt;
          &lt;li&gt;为了夺回搜索之王，雅虎大力扩张，最后只搞出一个令人失望的Panama广告系统；在品牌广告方面无所作为&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;2004年开始盈利增长不及预期，靠大量抛售Google股票来创造虚高盈利欺骗散户&lt;/li&gt;
  &lt;li&gt;Semel下台后Decker接手，大局观和对互联网市场的了解都很差
    &lt;ul&gt;
      &lt;li&gt;在Google上市前以低于开盘价（￥82.62）出手了Google股票&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;一直使用手工分类目录系统，手工调整搜索结果&lt;/li&gt;
  &lt;li&gt;2006年开始5年迅速衰败
    &lt;ul&gt;
      &lt;li&gt;业绩下滑，核心员工离职&lt;/li&gt;
      &lt;li&gt;Google搅黄了微软的收购
        &lt;ul&gt;
          &lt;li&gt;Google提出雅虎可以使用自己的广告系统，这样雅虎可以精简人员；雅图提高对微软的报价；微软拒绝&lt;/li&gt;
          &lt;li&gt;二流人才也基本离开了&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;大批私募基金进入董事会，不再关注公司发展
        &lt;ul&gt;
          &lt;li&gt;选定Carol Bartz出任CEO，开始拆分卖出，减少投资人损失&lt;/li&gt;
          &lt;li&gt;放弃搜索引擎改用Bing，采用微软不成型的搜索广告系统&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;唯一价值是拥有日本雅虎和阿里巴巴的大量股份
        &lt;ul&gt;
          &lt;li&gt;Bartz对阿里巴巴支付宝事件也处理的不好，占股从43%降到15%一下&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;来自Google的Marissa Mayer出任CEO，也没有扭转颓势&lt;/li&gt;
      &lt;li&gt;2017年被Verizon以$4.8B收购&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;硅谷见证惠普&quot;&gt;硅谷见证，惠普&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;1939年Hewlett和Packard创办HP&lt;/li&gt;
  &lt;li&gt;二战后斯坦福出租土地创办Stanford Industrial Park，HP入驻&lt;/li&gt;
  &lt;li&gt;业务包括示波器，信号发生器，医疗仪器等&lt;/li&gt;
  &lt;li&gt;进入小型计算机，打印机行业&lt;/li&gt;
  &lt;li&gt;90年代后期开始转型
    &lt;ul&gt;
      &lt;li&gt;产品线太长，内部混乱，需要重组，剥离一些部门单独上市
        &lt;ul&gt;
          &lt;li&gt;董事会和CEO Fiona剥离赖以起家的仪器部门，合并亏损的康柏公司
            &lt;ul&gt;
              &lt;li&gt;拆分的安捷伦公司股价暴涨，同时HP股价也涨，是不理性的股市表现&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;工作站业务远远落后，个人电脑领域差距越来越大，打印机市场也不断萎缩&lt;/li&gt;
      &lt;li&gt;惠普资金周转不够快，一年一次，戴尔有两次以上&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;2002年出现首次巨额亏损&lt;/li&gt;
  &lt;li&gt;并购康柏后没有增加市场份额，反而勉强维持康柏原有的份额&lt;/li&gt;
  &lt;li&gt;亚洲制造冲击了惠普的打印机市场&lt;/li&gt;
  &lt;li&gt;新任CEO Mark Hurd
    &lt;ul&gt;
      &lt;li&gt;裁撤研究部门&lt;/li&gt;
      &lt;li&gt;三个主要部门：技术服务TSG，个人电脑PSG，打印设备ISG&lt;/li&gt;
      &lt;li&gt;强化PC代销模式，与Walmart和Costco等合作&lt;/li&gt;
      &lt;li&gt;恢复作为技术公司的形象&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Mark离职后HP陷入颓势
    &lt;ul&gt;
      &lt;li&gt;2015年拆分为两家公司&lt;/li&gt;
      &lt;li&gt;个人业务的HP公司手反摩尔定律制约，利润变薄，发展不稳定
        &lt;ul&gt;
          &lt;li&gt;大量人才流失，Alan Eustace和Sanjay Ghemawat去了Google&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;惠普企业执行力不高，被其他公司蚕食&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;没落贵族摩托罗拉&quot;&gt;没落贵族，摩托罗拉&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;1928年创立，原名Galvin Manufacturing Corp，制造Motorola品牌收音机&lt;/li&gt;
  &lt;li&gt;为军方开发无线步话机，对讲机，注重技术和品质&lt;/li&gt;
  &lt;li&gt;垄断无线双向通信市场直到90年代初&lt;/li&gt;
  &lt;li&gt;曾进军家电市场，生产彩电，不是很成功&lt;/li&gt;
  &lt;li&gt;80年代业务拓展至计算机的半导体芯片，数字信号处理芯片DSP，也发明了手机&lt;/li&gt;
  &lt;li&gt;90年代初在移动通信，数字信号处理和计算机处理器三个领域都是技术最强，不过后来三个市场都没发展好&lt;/li&gt;
  &lt;li&gt;第二代移动通信
    &lt;ul&gt;
      &lt;li&gt;在第一代移动通信没有敌手，第二代移动通信发展中，欧洲联合推出GSM技术标准(Group Special Mobile， 多用户共用一个信道TDMA)，战胜了美国的标准&lt;/li&gt;
      &lt;li&gt;因为第一代模拟手机的成功，在数字手机研发上进展缓慢&lt;/li&gt;
      &lt;li&gt;同时数字手机技术差异较小。功能，可操作性，外观反而比技术更重要
        &lt;ul&gt;
          &lt;li&gt;e.g. 音箱里数字设备不同品牌差异不大，不过模拟部分的喇叭，日本厂商做不过美国的Harman Kardon，INFINITY&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;管理层能力平庸，十几年积累的模拟技术无足轻重&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;铱星计划
    &lt;ul&gt;
      &lt;li&gt;77颗低轨道卫星覆盖全球，每颗有三千多个信道，可以和手机直接通信，无需基站，可以在地球任何地点通信&lt;/li&gt;
      &lt;li&gt;1996年第一颗星上天，1998年投入商业运营&lt;/li&gt;
      &lt;li&gt;成本高导致定价贵，手机$5000，每分钟通话$3&lt;/li&gt;
      &lt;li&gt;1999年铱星公司破产&lt;/li&gt;
      &lt;li&gt;目前还在运营&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;全线溃败
    &lt;ul&gt;
      &lt;li&gt;手机领域被诺基亚，三星，LG抢走市场
        &lt;ul&gt;
          &lt;li&gt;2001年专注手机市场，不过开发速度太慢，用Java打造的操作系统速度慢，基于Linux的平台开发进展不顺利。输给安卓&lt;/li&gt;
          &lt;li&gt;Sanjay Jha力主加入安卓联盟，全力支持安卓手机开发。推出的手机大获好评&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;计算机处理器上输给英特尔&lt;/li&gt;
      &lt;li&gt;数字信号处理器上没竞争过德州仪器
        &lt;ul&gt;
          &lt;li&gt;一直做24位处理器，不方便使用&lt;/li&gt;
          &lt;li&gt;3G手机普及时，高通一月成为芯片最大提供商&lt;/li&gt;
          &lt;li&gt;半导体业务后来剥离成Freescale&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;2011年拆分为两个公司
    &lt;ul&gt;
      &lt;li&gt;摩托罗拉移动：手机业务和电视机顶盒
        &lt;ul&gt;
          &lt;li&gt;苹果和微软联手挑起和安卓联盟的手机专利之战
            &lt;ul&gt;
              &lt;li&gt;苹果和微软联合收购Nortel的移动通信专利，企图阻挡安卓联盟进入智能手机领域&lt;/li&gt;
              &lt;li&gt;Google收购摩托罗拉移动，反制
                &lt;ul&gt;
                  &lt;li&gt;陆续出手资产和裁撤员工&lt;/li&gt;
                &lt;/ul&gt;
              &lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;企业级通信和其他业务：没有任何影响力&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;硅谷奇迹探秘&quot;&gt;硅谷奇迹探秘&lt;/h2&gt;

&lt;p&gt;硅谷为什么成功？&lt;/p&gt;

&lt;p&gt;宛若似真的理由：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;气候独特舒适，地中海气候
    &lt;ul&gt;
      &lt;li&gt;Eric Schmit&lt;/li&gt;
      &lt;li&gt;其他类似气候地区没发展起来&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;斯坦福的存在
    &lt;ul&gt;
      &lt;li&gt;反而硅谷带动了斯坦福的发展&lt;/li&gt;
      &lt;li&gt;波士顿周边科研水平更高&lt;/li&gt;
      &lt;li&gt;特拉维夫，深圳附近没什么好大学，创业却很活跃
        &lt;ul&gt;
          &lt;li&gt;香港好大学多，没有拿得出手的科技成就&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;重视知识产权
    &lt;ul&gt;
      &lt;li&gt;硅谷相较美国没有特殊性&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;风险投资
    &lt;ul&gt;
      &lt;li&gt;是催化剂但不是决定性因素&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;成王败寇&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;硅谷创业成功率很低，每年大概4000起投资，IPO公司一般不到30家&lt;/li&gt;
  &lt;li&gt;好区划分，一共不到4万户，不到硅谷地区家庭数量的5%
    &lt;ul&gt;
      &lt;li&gt;Atherton, Hillsborough, Woodside, Los Altos Hills&lt;/li&gt;
      &lt;li&gt;Palo Alto, Saratoga, Los Altos&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;创业成功必要因素
    &lt;ul&gt;
      &lt;li&gt;创始团队，领袖人物，精力过人&lt;/li&gt;
      &lt;li&gt;小而精的团队，技术壁垒&lt;/li&gt;
      &lt;li&gt;商业头脑，盈利模式&lt;/li&gt;
      &lt;li&gt;及时纠错&lt;/li&gt;
      &lt;li&gt;外部环境，时机不早不晚&lt;/li&gt;
      &lt;li&gt;运气好&lt;/li&gt;
      &lt;li&gt;饥渴感&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;失败的出路
    &lt;ul&gt;
      &lt;li&gt;找工作，离开硅谷，重新再来&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;嗜血的地方&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;硅谷科技公司平均工作时间较长&lt;/li&gt;
  &lt;li&gt;失业压力大&lt;/li&gt;
  &lt;li&gt;文化沙漠，娱乐文化生活贫瘠&lt;/li&gt;
  &lt;li&gt;换工作很常见，赌 SV lottery&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;机会均等&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;权威众多，不迷信权威&lt;/li&gt;
  &lt;li&gt;招聘时不太注重过往经历&lt;/li&gt;
  &lt;li&gt;其他行业比如房地产，律师，银行，装修发展也很好&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;半导体行业在硅谷逐渐衰退&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;反摩尔定律，硅谷费用高昂
    &lt;ul&gt;
      &lt;li&gt;软件业不受影响&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;亚洲制造&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;真正的奥秘&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;叛逆的文化，会建设的颠覆者&lt;/li&gt;
  &lt;li&gt;对叛逆和失败的宽容
    &lt;ul&gt;
      &lt;li&gt;加州基本不honor竞业禁止
        &lt;ul&gt;
          &lt;li&gt;如必须使用某种技能才能生存时，可以使用&lt;/li&gt;
          &lt;li&gt;不能明确描述过去工作细节&lt;/li&gt;
          &lt;li&gt;不得使用原公司知识产权&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;司法部和加州起诉Apple，Intel，Google，Adobe公司，因为他们彼此员工跳槽很少，破幻了竞争&lt;/li&gt;
      &lt;li&gt;华盛顿州有竞业禁止限制&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;多元文化，人口组成多元
    &lt;ul&gt;
      &lt;li&gt;产品设计面向全球&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;创新的灵魂
    &lt;ul&gt;
      &lt;li&gt;Genetech以IT公司模式经营，不断创新，业务增长快&lt;/li&gt;
      &lt;li&gt;辉瑞发展停滞，依赖购买小公司获得新药&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;短暂的春秋与机会失之交臂的公司&quot;&gt;短暂的春秋:与机会失之交臂的公司&lt;/h2&gt;
</description>
      </item>
    
      <item>
        <title>Public speaking course notes</title>
        <link>/2021/09/11/public-speaking-uw.html</link>
        <guid isPermaLink="true">/2021/09/11/public-speaking-uw.html</guid>
        <pubDate>Sat, 11 Sep 2021 00:00:00 +0000</pubDate>
        <description>&lt;p&gt;This is the notes while taking Public speaking course from University of Washington, instructed by Dr. Matt McGarrity.&lt;/p&gt;

&lt;h2 id=&quot;a-rhetorical-approach&quot;&gt;A rhetorical approach&lt;/h2&gt;

&lt;p&gt;Rhetoric is the art of identifying communication needs and strategically responding to them.&lt;/p&gt;

&lt;p&gt;While public speaking, we need to find the best or most appropriate response to current rhetoric situations, including topic, setting, audience, occasion and credibility.&lt;/p&gt;

&lt;p&gt;Rhetorical canons are tools for preparing and performing speeches, including:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Invention: Coming up with contents.&lt;/li&gt;
  &lt;li&gt;Arrangement: Putting it in order for the audience.&lt;/li&gt;
  &lt;li&gt;Style: Finding the most effective language.&lt;/li&gt;
  &lt;li&gt;Memory: Getting your speech into your head to support good delivery.&lt;/li&gt;
  &lt;li&gt;Delivery: Performing the content effectively for this audience.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Speeches should be optimized for ears not eyes. The listeners needs cues to decode the talk. Contextual cues provide situational information, eliminating other irrelevant situations. Prosodic cues (pitch, rate, pause, stress etc) provide auditory information. e.g., We break the sentence into functional units.&lt;/p&gt;

&lt;h2 id=&quot;inventing-and-arranging-main-points&quot;&gt;Inventing and arranging main points&lt;/h2&gt;

&lt;p&gt;Key point speeches:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Determine key points we want audience to remember.&lt;/li&gt;
  &lt;li&gt;Discuss each points with concrete and interesting examples.&lt;/li&gt;
  &lt;li&gt;Deliver clearly with confidence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A model of arguments by Stephen Toulmin can help us write clearer speeches.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Claim: an assertion you wanna audience to take as valid.&lt;/li&gt;
  &lt;li&gt;Support: evidence used to validate your claim.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Warrant: what links the support to the claim, helping understand the relationship.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Outlining: Preparing a speech in a hierarchical structure. Outlines allow you to plan and refine the speech’s logic. We can outline a few points then develop the speech hierarchically.&lt;/li&gt;
  &lt;li&gt;Flowing: Taking notes on a speech in an outline format. Flows allow you to better understand a speech.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;inventing-key-points&quot;&gt;Inventing key points&lt;/h3&gt;

&lt;p&gt;Developing key points for topics, can start with:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Short term/long term&lt;/li&gt;
  &lt;li&gt;Past/present/future&lt;/li&gt;
  &lt;li&gt;Increase/decrease
    &lt;ul&gt;
      &lt;li&gt;Some types of qualitative/quantitative changes going on.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Cause/effect&lt;/li&gt;
  &lt;li&gt;Division
    &lt;ul&gt;
      &lt;li&gt;Two component in the topic can be broken out, not mutually exclusive.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Definition&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For how many key points to include in a speech, try 2-5 for a start; break up larger presentations into “chunks” of 2-5 key points.&lt;/p&gt;

&lt;h3 id=&quot;arranging-key-points&quot;&gt;Arranging key points&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Subordination: All key points are related to the topic.&lt;/li&gt;
  &lt;li&gt;Coordination: Work well together.
    &lt;ul&gt;
      &lt;li&gt;Having a clear rationale driving the arrangement.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Discreteness: Don’t overlap with each other.&lt;/li&gt;
  &lt;li&gt;Phrasing key points
    &lt;ul&gt;
      &lt;li&gt;Use shorter phrases&lt;/li&gt;
      &lt;li&gt;Use evocative words&lt;/li&gt;
      &lt;li&gt;Put the key terms in important positions, starts or ends&lt;/li&gt;
      &lt;li&gt;Use parallel phrasing, if possible
        &lt;ul&gt;
          &lt;li&gt;Having repeating parts in each key points, e.g., “I do developing work; I do testing work; I do operational work”&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;handling-qa-session&quot;&gt;Handling Q&amp;amp;A session&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Key is ethos (credibility of the speaker). The speaker should be and sound like an expert, in control of the content.&lt;/li&gt;
  &lt;li&gt;Prepare for questions
    &lt;ul&gt;
      &lt;li&gt;Identify places that may get clarification or push back questions.&lt;/li&gt;
      &lt;li&gt;Prepare basic answers, top 5 questions, evidences.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Structure the answer
    &lt;ul&gt;
      &lt;li&gt;Keep it brief.&lt;/li&gt;
      &lt;li&gt;Stay on point.
        &lt;ul&gt;
          &lt;li&gt;State it: yes or no.&lt;/li&gt;
          &lt;li&gt;Explain it.&lt;/li&gt;
          &lt;li&gt;Show it.&lt;/li&gt;
          &lt;li&gt;Conclude it.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;For tough questions
        &lt;ul&gt;
          &lt;li&gt;Reject loaded questions and words like “So the company is getting rid of that unfair policy?”&lt;/li&gt;
          &lt;li&gt;Avoid matching hostility with hostility.
            &lt;ul&gt;
              &lt;li&gt;Can break the contact with the questioner and come back to the entire audience.
                &lt;ul&gt;
                  &lt;li&gt;“I get what he’s concerned with. I do. I want to be very clear about this issue …”&lt;/li&gt;
                &lt;/ul&gt;
              &lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
          &lt;li&gt;Push it to a post Q&amp;amp;A.
            &lt;ul&gt;
              &lt;li&gt;“I understand what you are asking here. I don’t think we have time to hash it all out here. Let’s tak more offline.”&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
          &lt;li&gt;Q&amp;amp;A is still part of the presentation. The speaker is still held accountable.&lt;/li&gt;
          &lt;li&gt;Just say no if don’t know.
            &lt;ul&gt;
              &lt;li&gt;“I actually don’t have that answer right now. I will find out and get back to you”&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;inventing-and-arranging-support&quot;&gt;Inventing and arranging support&lt;/h2&gt;

&lt;h3 id=&quot;support-and-explanation&quot;&gt;Support and explanation&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Good support:
    &lt;ul&gt;
      &lt;li&gt;shows validity and provides details.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Types of support
    &lt;ul&gt;
      &lt;li&gt;Facts, statistics, testimony&lt;/li&gt;
      &lt;li&gt;Example and illustrations&lt;/li&gt;
      &lt;li&gt;Metaphors and analogies&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When discussing your support:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Focus on relevant details. Come back if it’s too detail.&lt;/li&gt;
  &lt;li&gt;Focus on clarity over comprehensiveness.&lt;/li&gt;
  &lt;li&gt;Help the audience craft a mental image.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To perform a key point:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;State it: give the claims&lt;/li&gt;
  &lt;li&gt;Explain it: unpack the claim and prime for the support&lt;/li&gt;
  &lt;li&gt;Show it: explain the support and how it relates to the claim&lt;/li&gt;
  &lt;li&gt;Conclude it: touch on the key claim again to wrap up&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;making-your-speech-easy-to-follow&quot;&gt;Making your speech easy to follow&lt;/h3&gt;

&lt;p&gt;Speech structure:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Introductions
    &lt;ul&gt;
      &lt;li&gt;Core functions:
        &lt;ul&gt;
          &lt;li&gt;Open the speech, like a pause then a clap.&lt;/li&gt;
          &lt;li&gt;Orient the audience. Let them know the matter quickly.&lt;/li&gt;
          &lt;li&gt;Provide a preview. Main key points; how the time is spent.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Transitions
    &lt;ul&gt;
      &lt;li&gt;demonstrate the distinctness of each point.&lt;/li&gt;
      &lt;li&gt;help the audience know where you are.&lt;/li&gt;
      &lt;li&gt;give the audience just a little break.&lt;/li&gt;
      &lt;li&gt;E.g., state the previous key point then state the next key point.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Conclusion
    &lt;ul&gt;
      &lt;li&gt;reinforce the key points.&lt;/li&gt;
      &lt;li&gt;provide a sense of closure.&lt;/li&gt;
      &lt;li&gt;should sound like a final line (usually slower and more deliberate)&lt;/li&gt;
      &lt;li&gt;E.g., So in conclusion, …&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;revising-practicing-and-remembering-the-speech&quot;&gt;Revising, practicing and remembering the speech&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;Revise for fit between claims and support.&lt;/li&gt;
  &lt;li&gt;Look for rearrangement opportunities.&lt;/li&gt;
  &lt;li&gt;Try a couple of different models.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;List the structure, top down:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Topic
    &lt;ul&gt;
      &lt;li&gt;Key point 1
        &lt;ul&gt;
          &lt;li&gt;Support 1&lt;/li&gt;
          &lt;li&gt;Support 2&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Key point 2
        &lt;ul&gt;
          &lt;li&gt;Support 3&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then do bottom up to see if the child point relates to the parent point.&lt;/p&gt;

&lt;h2 id=&quot;fear-of-public-speaking-and-good-delivery&quot;&gt;Fear of public speaking and good delivery&lt;/h2&gt;

</description>
      </item>
    
      <item>
        <title>MacOS bluetooth connectivity issues</title>
        <link>/2020/09/05/macos-bluetooth-disconnecting.html</link>
        <guid isPermaLink="true">/2020/09/05/macos-bluetooth-disconnecting.html</guid>
        <pubDate>Sat, 05 Sep 2020 00:00:00 +0000</pubDate>
        <description>&lt;h2 id=&quot;what&quot;&gt;What?&lt;/h2&gt;

&lt;p&gt;Somehow both my two Macbook Pro (2018 13-inch with High Sierra and 2019 13-inch with Catalina) have been experiencing bluetooth connectivity issues for several months. All of a sudden, all bluetooth devices disconnect for a few seconds then recover. This could happen dozens of times a day and really disturbs productivity. I have tried numerous solution mentioned online like restarting SMC, reset bluetooth module, etc and none of them works. Finally, found this &lt;a href=&quot;https://www.forbes.com/sites/bradmoon/2017/07/13/this-trick-may-solve-your-mac-bluetooth-connectivity-issues/#625ab2fc5196&quot;&gt;article&lt;/a&gt;. Turning of “Handoff” feature works for me.. (System preferences -&amp;gt; General -&amp;gt; uncheck “Allow Handoff between this Mac and your iCloud devices”) You can read more in the article. Basically “Handeoff” allows you to coordinate between your iCloud devices, which I have never tried.&lt;/p&gt;
</description>
      </item>
    
      <item>
        <title>Read &quot;Dynamo, Amazon’s Highly Available Key-value Store&quot;</title>
        <link>/2020/06/21/dynamo-paper.html</link>
        <guid isPermaLink="true">/2020/06/21/dynamo-paper.html</guid>
        <pubDate>Sun, 21 Jun 2020 00:00:00 +0000</pubDate>
        <description>&lt;h2 id=&quot;reference&quot;&gt;Reference&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf&quot;&gt;Link to paper&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;abstract&quot;&gt;Abstract&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;K-V store.&lt;/li&gt;
  &lt;li&gt;Highly available, scalable.&lt;/li&gt;
  &lt;li&gt;Always on for reads and writes.&lt;/li&gt;
  &lt;li&gt;Eventual consistency.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;1-introduction&quot;&gt;1 Introduction&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Amazon architecture
    &lt;ul&gt;
      &lt;li&gt;Highly decentralized, loosely coupled SOA consisting hundreds of services.&lt;/li&gt;
      &lt;li&gt;Failures are the norm of daily operations.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Dynamo uses techniques:
    &lt;ul&gt;
      &lt;li&gt;Consistent hashing for partition and hashing.&lt;/li&gt;
      &lt;li&gt;Consistency is facilitated with object versioning.&lt;/li&gt;
      &lt;li&gt;Quorum-like technique and a decentralized replica synchronization protocol for consistency among replicas during updates.&lt;/li&gt;
      &lt;li&gt;A gossip based distributed failure detection and membership protocol.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;2-background&quot;&gt;2 Background&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Relational DBs are complex and inefficient for simple KV use cases.&lt;/li&gt;
  &lt;li&gt;System assumptions and requirements
    &lt;ul&gt;
      &lt;li&gt;Query model
        &lt;ul&gt;
          &lt;li&gt;Simple reads and writes to a single data item.&lt;/li&gt;
          &lt;li&gt;Values are binary objects.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Doesn’t need ACID transactions.&lt;/li&gt;
      &lt;li&gt;Efficiency
        &lt;ul&gt;
          &lt;li&gt;SLAs on 99.9% percentile.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;No internal hostiles thus no security related requirements.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;SLAs
    &lt;ul&gt;
      &lt;li&gt;Uses 99.9% for better client experience.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Design considerations
    &lt;ul&gt;
      &lt;li&gt;Use optimistic replication techniques -&amp;gt; conflict resolution
        &lt;ul&gt;
          &lt;li&gt;When to resolve, read/write?
            &lt;ul&gt;
              &lt;li&gt;Resolving during writes will reject some writes.&lt;/li&gt;
              &lt;li&gt;(Accepted) Resolving during reads to have an always-writable system.&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
          &lt;li&gt;Who resolves
            &lt;ul&gt;
              &lt;li&gt;Data store: Choices are limited, like last-write-wins.&lt;/li&gt;
              &lt;li&gt;Application: More flexible.&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Incremental scalability&lt;/li&gt;
      &lt;li&gt;Symmetry
        &lt;ul&gt;
          &lt;li&gt;All nodes should have the same responsibilities.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Decentralization
        &lt;ul&gt;
          &lt;li&gt;Favors decentralized peer-to-peer techniques over centralized control.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Heterogeneity
        &lt;ul&gt;
          &lt;li&gt;e.g. work distribution must be proportional to the individual server capabilities.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;3-related-work&quot;&gt;3 Related work&lt;/h2&gt;

&lt;p&gt;Dynamo differs from some other projects as follows.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Always writable as no writes should be rejected.&lt;/li&gt;
  &lt;li&gt;All nodes are trusted since it’s used internally.&lt;/li&gt;
  &lt;li&gt;Doesn’t require hierarchical namespaces or complex schemas.&lt;/li&gt;
  &lt;li&gt;For latency-sensitive applications, targeting at 99.9% percentile.
    &lt;ul&gt;
      &lt;li&gt;Multi-hop routing is not acceptable.&lt;/li&gt;
      &lt;li&gt;Dynamo is zero-hop DHT that each node maintains enough routing info locally to route a request to an appropriate node directly.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;4-system-architecture&quot;&gt;4 System architecture&lt;/h2&gt;

&lt;p&gt;General considerations for a scalable and robust distributed system:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Data persistent component&lt;/li&gt;
  &lt;li&gt;Load balancing&lt;/li&gt;
  &lt;li&gt;Membership and failure detection&lt;/li&gt;
  &lt;li&gt;Failure recovery&lt;/li&gt;
  &lt;li&gt;Replica synchronization&lt;/li&gt;
  &lt;li&gt;Overload handling&lt;/li&gt;
  &lt;li&gt;State transfer&lt;/li&gt;
  &lt;li&gt;Concurrency and job scheduling&lt;/li&gt;
  &lt;li&gt;Request marshalling&lt;/li&gt;
  &lt;li&gt;Request routing&lt;/li&gt;
  &lt;li&gt;System monitoring and alarming&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Core techniques used by Dynamo:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Problem&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Technique&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Advantage&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Partitioning&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Consistent hashing&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Incremental scalability&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;High Availability for writes&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Vector clocks with reconciliation during reads&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Version size is decoupled from update rates&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Handling temporary failures&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Sloppy quorum and hinted handoff&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Provides high availability and durability guarantee when some of the replicas are unavailable&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Recovering from permanent failures&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Anti-entropy using Merkle trees&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Synchronizes divergent replicas in the background&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Membership and failure detection&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Gossip-based membership protocol and failure detection&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Preserves symmetry and avoids having a centralized registry for storing membership and node liveness information&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h3 id=&quot;system-interface&quot;&gt;System interface&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;get(key)&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;put(key, context, object)&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;context&lt;/code&gt; is some system metadata such as versions of objects.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;partition-algorithm&quot;&gt;Partition algorithm&lt;/h3&gt;

&lt;p&gt;Dynamo uses consistent hashing. On a ring, a node is assigned a random value representing the position on the ring. For an example ring &lt;code class=&quot;highlighter-rouge&quot;&gt;A -&amp;gt; B -&amp;gt; C -&amp;gt; D -&amp;gt; A&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;B&lt;/code&gt; is the coordinator node for data with key in range &lt;code class=&quot;highlighter-rouge&quot;&gt;(A, B]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This setting have two problems:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Random assignment leads to non-uniform data and load distribution.&lt;/li&gt;
  &lt;li&gt;Oblivious to the heterogeneity in the performance and capacity of nodes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Therefore, Dynamo uses “virtual node” concept. Virtual nodes are nodes on the ring. A physical node can be responsible for one or more virtual nodes. Advantages are as follows:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;If a node becomes unavailable, its load is evenly dispersed across remaining nodes.&lt;/li&gt;
  &lt;li&gt;If a node becomes available again or is added, it roughly accepts equivalent amount of load from the remaining ones.&lt;/li&gt;
  &lt;li&gt;The number of virtual nodes for a physical node can be decided considering the performance and capacity.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;replication&quot;&gt;Replication&lt;/h3&gt;

&lt;p&gt;Each data is replicated across &lt;code class=&quot;highlighter-rouge&quot;&gt;N&lt;/code&gt; nodes. Starting from the coordinator node, data are replicated to the &lt;code class=&quot;highlighter-rouge&quot;&gt;N-1&lt;/code&gt; successor nodes. For an example ring &lt;code class=&quot;highlighter-rouge&quot;&gt;A -&amp;gt; B -&amp;gt; C -&amp;gt; D -&amp;gt; A&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;N=3&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;D&lt;/code&gt; is responsible for data in range &lt;code class=&quot;highlighter-rouge&quot;&gt;(A, B]&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;(B, C]&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;(C, D]&lt;/code&gt;. For a particular key, the list of nodes storing it is called preference list. In order to make sure data is replicated across &lt;code class=&quot;highlighter-rouge&quot;&gt;N&lt;/code&gt; &lt;strong&gt;physical&lt;/strong&gt; nodes, preference list is chosen by skipping virtual nodes on the same physical node.&lt;/p&gt;

&lt;h3 id=&quot;data-versioning&quot;&gt;Data versioning&lt;/h3&gt;

&lt;p&gt;To ensure the system is always writable, conflicting writes are accepted and the conflicts can be resolved during reads, e.g., merging different versions of a shopping cart. Vector clock is used to capture the causality of an object. It’s a list of &lt;code class=&quot;highlighter-rouge&quot;&gt;(node, counter)&lt;/code&gt; pairs. For a &lt;code class=&quot;highlighter-rouge&quot;&gt;put()&lt;/code&gt; operation, client must supply the version it’s updating in &lt;code class=&quot;highlighter-rouge&quot;&gt;context&lt;/code&gt;, it could be obtained from an earlier read.&lt;/p&gt;

&lt;p&gt;The size of a vector clock is usually limited since preference list contains only &lt;code class=&quot;highlighter-rouge&quot;&gt;N&lt;/code&gt; nodes. In the cases of network partitions or multiple server failures, the request may be served by other nodes. Dynamo limits the size of vector clocks by associating timestamp to each pair. If the size reaches the threshold, discard the oldest ones.&lt;/p&gt;

&lt;h3 id=&quot;execution-of-get-and-put-operations&quot;&gt;Execution of get() and put() operations&lt;/h3&gt;

&lt;p&gt;Any storage node in Dynamo is eligible to receive client get and put operations for any key. Two strategies for a client to select the node performing operations:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Routes its request through a generic load balancer that will select a node based on load information.
    &lt;ul&gt;
      &lt;li&gt;Clients don’t need links to Dynamo library.&lt;/li&gt;
      &lt;li&gt;The random chosen node will forward the request to the top N healthy nodes in the preference list.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Uses a partition-aware client library that routes the request to the coordinator node directly.
    &lt;ul&gt;
      &lt;li&gt;Lower latency.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dynamo uses consistency protocol &lt;code class=&quot;highlighter-rouge&quot;&gt;R + W &amp;gt; N&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;R&lt;/code&gt; is the minimum number of nodes fore a successful read.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;W&lt;/code&gt; is the minimum number of nodes fore a successful write.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Upon a read, the coordinator requests all existing versions of data for that key from the &lt;code class=&quot;highlighter-rouge&quot;&gt;N&lt;/code&gt; highest-ranked nodes in the preference list. Once receiving at least &lt;code class=&quot;highlighter-rouge&quot;&gt;R&lt;/code&gt; responses, reconcile the versions so the final versions are casually unrelated. Then send the response to the client and write the final versions back.&lt;/p&gt;

&lt;h3 id=&quot;handling-failures-hinted-handoff&quot;&gt;Handling failures: Hinted handoff&lt;/h3&gt;

&lt;p&gt;To improve availability, Dynamo uses sloppy quorum: all reads and writes are performed on the first &lt;code class=&quot;highlighter-rouge&quot;&gt;N&lt;/code&gt; &lt;strong&gt;healthy&lt;/strong&gt; nodes in the preference list.&lt;/p&gt;

&lt;p&gt;For an example ring &lt;code class=&quot;highlighter-rouge&quot;&gt;A -&amp;gt; B -&amp;gt; C -&amp;gt; D -&amp;gt; A&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;N=3&lt;/code&gt;, if &lt;code class=&quot;highlighter-rouge&quot;&gt;A&lt;/code&gt; is unavailable, &lt;code class=&quot;highlighter-rouge&quot;&gt;D&lt;/code&gt; will temporarily be hinted to receive the corresponding replica . Once &lt;code class=&quot;highlighter-rouge&quot;&gt;A&lt;/code&gt; is recovered, &lt;code class=&quot;highlighter-rouge&quot;&gt;D&lt;/code&gt; will transfer the replica back.&lt;/p&gt;

&lt;p&gt;The preference list in constructed in a way that its storage nodes are spread across multiple data centers, in order to tackle data-center-level failures.&lt;/p&gt;

&lt;h3 id=&quot;handling-permanent-failures-replica-synchronization&quot;&gt;Handling permanent failures: replica synchronization&lt;/h3&gt;

&lt;p&gt;Dynamo uses an anti-entropy protocol with Merkle trees to keep replica synchronized.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Merkle tree
    &lt;ul&gt;
      &lt;li&gt;A hash tree where leaves are hashes of the values of individual keys.&lt;/li&gt;
      &lt;li&gt;Parent nodes higher in the tree are hashes of their respective children.&lt;/li&gt;
      &lt;li&gt;It can quickly compare two trees to know which keys are out of sync.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;In Dynamo
    &lt;ul&gt;
      &lt;li&gt;Each node maintain a separate Merkle tree for each key range.&lt;/li&gt;
      &lt;li&gt;A disadvantage is the tree needs to be recalculated if a node joins or leaves the system.
        &lt;ul&gt;
          &lt;li&gt;Will be addressed later.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;membership-and-failure-detection&quot;&gt;Membership and failure detection&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;To add/remove a node to a ring,
    &lt;ul&gt;
      &lt;li&gt;An admin connects to a node and issue membership changes.&lt;/li&gt;
      &lt;li&gt;Change history is persisted.&lt;/li&gt;
      &lt;li&gt;A gossip-based protocol propagates change history between nodes.
        &lt;ul&gt;
          &lt;li&gt;Also exchange and reconcile mapping of local nodes and token sets (key ranges).&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;A ring may be logically partitioned.
    &lt;ul&gt;
      &lt;li&gt;e.g., connect node A to join A into the ring; connect node B to join B. In this case, A and B don’t know each other.&lt;/li&gt;
      &lt;li&gt;To solve this, some nodes play the role of seeds, which is known by all nodes.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Failure detection
    &lt;ul&gt;
      &lt;li&gt;To avoid attempt to communicate with unreachable nodes during operations like &lt;code class=&quot;highlighter-rouge&quot;&gt;get()&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;put()&lt;/code&gt;, transferring partitions and hinted replicas.&lt;/li&gt;
      &lt;li&gt;Local notion is sufficient: A pings B; if B doesn’t respond, A thinks B is unreachable. A can use B’s alternative nodes.&lt;/li&gt;
      &lt;li&gt;Decentralized failure detection is unnecessary.
        &lt;ul&gt;
          &lt;li&gt;It uses a gossip protocol enabling each node to know arrival/departure of other nodes.&lt;/li&gt;
          &lt;li&gt;This obviates Dynamo’s node joining/leaving mechanism.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;addingremoving-storage-nodes&quot;&gt;Adding/Removing storage nodes&lt;/h3&gt;

&lt;p&gt;When a new node joins the ring, following operations happen. Operational experience shows it distributes the load uniformly across storage nodes.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;It gets assigned a number of random tokens (key ranges) from the ring.&lt;/li&gt;
  &lt;li&gt;The nodes currently in charge of these key ranges will transfer data to the new node upon its confirmation.
    &lt;ul&gt;
      &lt;li&gt;Avoids duplicate transfers.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;5-implementation&quot;&gt;5 Implementation&lt;/h2&gt;

&lt;p&gt;Each Dynamo node contains 3 components:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Local persistence component
    &lt;ul&gt;
      &lt;li&gt;Different storage engine can be plugged in: Berkeley DB, MySQL, etc. for different use cases.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Request coordination
    &lt;ul&gt;
      &lt;li&gt;built on top of an event-driven messaging substrate where message processing pipeline is split into stages similar to SEDA architecture.&lt;/li&gt;
      &lt;li&gt;Each client request triggers the creation of a state machine on the node handling:
        &lt;ul&gt;
          &lt;li&gt;identifying nodes for this key;&lt;/li&gt;
          &lt;li&gt;sending requests;&lt;/li&gt;
          &lt;li&gt;waiting for responses;&lt;/li&gt;
          &lt;li&gt;potentially doing retries;&lt;/li&gt;
          &lt;li&gt;processing and packaging responses.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;For read requests:
        &lt;ul&gt;
          &lt;li&gt;may performing read repair to fix stale data.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;For write requests:
        &lt;ul&gt;
          &lt;li&gt;Any node in the preference list can be the coordinator.
            &lt;ul&gt;
              &lt;li&gt;If using timestamp-based reconciliation, any node in the system can do the job.&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
          &lt;li&gt;This means writes for a key cannot be serialized at a single location.&lt;/li&gt;
          &lt;li&gt;Better load balancing.&lt;/li&gt;
          &lt;li&gt;Usually a write follows a read, thus use the node which replied fastest the the previous read, as write coordinator.
            &lt;ul&gt;
              &lt;li&gt;Better chances getting read-your-write consistency.&lt;/li&gt;
              &lt;li&gt;Reduce variability in the performance, improve 99.9% performance.&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Membership and failure detection&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;6-experience-and-lessons-learned&quot;&gt;6 Experience and lessons learned&lt;/h2&gt;

&lt;p&gt;Main patterns in which Dynamo uses are as follows. &lt;code class=&quot;highlighter-rouge&quot;&gt;W&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;R&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;N&lt;/code&gt; values can be tuned to achieve desired level of performance, availability and durability. Typically, &lt;code class=&quot;highlighter-rouge&quot;&gt;N = 3&lt;/code&gt;. Common combination is &lt;code class=&quot;highlighter-rouge&quot;&gt;N = 3; R = 2; W = 2&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Business logic specific reconciliation&lt;/li&gt;
  &lt;li&gt;Timestamp based reconciliation
    &lt;ul&gt;
      &lt;li&gt;Last writes wins.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;High performance read engine
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;R = 1; W = N&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;balancing-performance-and-durability&quot;&gt;Balancing performance and durability&lt;/h3&gt;

&lt;p&gt;Write latencies are usually higher than reads since a disk accesses are required. However, we can trade-off durability guarantees for performance. Write operations can be buffered at memory, which gets periodically written to storage. To reduce durability risk of this approach, the coordinator can choose 1 out of &lt;code class=&quot;highlighter-rouge&quot;&gt;N&lt;/code&gt; node performing “durable write”. As the coordinator only waits for &lt;code class=&quot;highlighter-rouge&quot;&gt;W&lt;/code&gt; responses, the write performance won’t be impacted.&lt;/p&gt;

&lt;h3 id=&quot;ensuring-uniform-load-distribution&quot;&gt;Ensuring uniform load distribution&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Dynamo assumes that when significant skews of access distribution happen, there are enough keys for popular end of the distribution thus load can be distributed uniformly.&lt;/li&gt;
  &lt;li&gt;Experiments show that imbalance ratio decrease with increase load.
    &lt;ul&gt;
      &lt;li&gt;With high loads, a large number of popular keys are distributed uniformly.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The evolution of partitioning schemes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Strategy 1: T random tokens per node and partition by token value
    &lt;ul&gt;
      &lt;li&gt;Two consecutive tokens define a range.&lt;/li&gt;
      &lt;li&gt;Cons:
        &lt;ul&gt;
          &lt;li&gt;When a new node joins, it needs to steal tokens from others.
            &lt;ul&gt;
              &lt;li&gt;Partitioning would be affected.&lt;/li&gt;
              &lt;li&gt;This needs scanning, which is inefficient.&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
          &lt;li&gt;When nodes join/leave, key ranges of many nodes change and Merkel tree need to be recalculated.&lt;/li&gt;
          &lt;li&gt;No easy way to snapshot entire key space.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Strategy 2: T random tokens per node and equal-sized partitions
    &lt;ul&gt;
      &lt;li&gt;Hash space is divided into &lt;code class=&quot;highlighter-rouge&quot;&gt;Q&lt;/code&gt; equally sized partitions/ranges and each node is assigned &lt;code class=&quot;highlighter-rouge&quot;&gt;T&lt;/code&gt; random tokens.&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;Q &amp;gt;&amp;gt; N&lt;/code&gt;; &lt;code class=&quot;highlighter-rouge&quot;&gt;Q &amp;gt;&amp;gt; S*T&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;S&lt;/code&gt; is the number of nodes.&lt;/li&gt;
      &lt;li&gt;Partitioning and partitioning placement are decoupled.&lt;/li&gt;
      &lt;li&gt;This is an intermediate state migrating from 1 to 3.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Strategy 3: &lt;code class=&quot;highlighter-rouge&quot;&gt;Q/S&lt;/code&gt; tokens per node, equal-sized partitions
    &lt;ul&gt;
      &lt;li&gt;Each node handles &lt;code class=&quot;highlighter-rouge&quot;&gt;Q/S&lt;/code&gt; tokens.&lt;/li&gt;
      &lt;li&gt;When nodes join/leave, tokens are re-arranged to satisfy the invariant.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Evaluation:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Load balancing efficiency: ratio of average number of requests of all nodes to the maximum number of requests of the hottest node.&lt;/li&gt;
  &lt;li&gt;Experiment result of efficiency: 3 &amp;gt; 2 &amp;gt; 1.&lt;/li&gt;
  &lt;li&gt;Strategy 3
    &lt;ul&gt;
      &lt;li&gt;Pros:
        &lt;ul&gt;
          &lt;li&gt;Size of membership information at each node is greatly reduced. (&amp;gt;1000X)&lt;/li&gt;
          &lt;li&gt;Faster bootstrapping/recovery: Partition ranges are fixed and stored as files, which can be transferred easily.&lt;/li&gt;
          &lt;li&gt;Easy archival: Entire dataset can be archived by archiving those partition files separately.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Cons:
        &lt;ul&gt;
          &lt;li&gt;Changing node membership requires coordination in order to preserve the invariant.
            &lt;ul&gt;
              &lt;li&gt;(ST): Strategy 1 requires coordination for tokens too?&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;divergent-versions&quot;&gt;Divergent versions&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Divergent versions happen in case of:
    &lt;ul&gt;
      &lt;li&gt;failure scenarios;&lt;/li&gt;
      &lt;li&gt;large number of concurrent writes to a single data item.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Experiments show that divergent versions are rarely created.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;client-driven-or-server-driven-coordination&quot;&gt;Client-driven or server-driven coordination&lt;/h3&gt;

&lt;p&gt;State machine can be move to client side. Advantages:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Load balancer is not needed.
    &lt;ul&gt;
      &lt;li&gt;This also avoids the extra network hop for the load balancer.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Clients poll any Dynamo node for membership updates every 10 seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;balancing-background-tasks&quot;&gt;Balancing background tasks&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Background tasks such as replica synchronization and data handoff should run only when the regular critical operations are not affected significantly.&lt;/li&gt;
  &lt;li&gt;An admission control mechanism and resource monitoring are integrated to schedule background tasks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;discussion&quot;&gt;Discussion&lt;/h3&gt;

&lt;p&gt;Note that Dynamo works for a system of couple of hundreds of nodes. If running with tens of thousands of nodes, the routing table (&lt;code class=&quot;highlighter-rouge&quot;&gt;O(n)&lt;/code&gt; to system size) is hard to maintain. This may be overcome by introducing hierarchical extensions or DHT systems.&lt;/p&gt;
</description>
      </item>
    
      <item>
        <title>Read &quot;Bigtable, A Distributed Storage System for Structured Data&quot;</title>
        <link>/2020/05/05/bigtable-paper.html</link>
        <guid isPermaLink="true">/2020/05/05/bigtable-paper.html</guid>
        <pubDate>Tue, 05 May 2020 00:00:00 +0000</pubDate>
        <description>&lt;h2 id=&quot;reference&quot;&gt;Reference&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://static.googleusercontent.com/media/research.google.com/en//archive/bigtable-osdi06.pdf&quot;&gt;Link to paper&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;abstract&quot;&gt;Abstract&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Distributed storage for managing structured data.&lt;/li&gt;
  &lt;li&gt;Scale to petabytes of data across thousands of servers.&lt;/li&gt;
  &lt;li&gt;Satisfying different client demands such as data size, latency etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;1-introduction&quot;&gt;1 Introduction&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Goals:
    &lt;ul&gt;
      &lt;li&gt;Wide applicability, scalability, high performance and high availability.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Simple data model, not a full relational data model.
    &lt;ul&gt;
      &lt;li&gt;Dynamic control over data layout and format.&lt;/li&gt;
      &lt;li&gt;Clients can reason about locality properties.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Indexed using row and column names.&lt;/li&gt;
  &lt;li&gt;Data are treated as uninterpreted strings.
    &lt;ul&gt;
      &lt;li&gt;Clients can serialize various data types into them.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Clients can control whether to serve data out of memory or from disk.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;2-data-model&quot;&gt;2 Data model&lt;/h2&gt;

&lt;p&gt;Bigtable is a sparse, distributed, persistent multi-dimensional sorted map, indexed by a row key, column key and a timestamp. The value is an uninterpreted string. &lt;code class=&quot;highlighter-rouge&quot;&gt;(row:string, column:string, time:int64) -&amp;gt; string&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;A sample piece of data for web page is as follows. Row key is url; column key is &lt;code class=&quot;highlighter-rouge&quot;&gt;content&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;anchor:cnnsi.com&lt;/code&gt;, etc.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/system/bigtable/data-model-eg.png&quot; alt=&quot;Data model example&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;21-row&quot;&gt;2.1 Row&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Size: up to 64 KB.&lt;/li&gt;
  &lt;li&gt;Each read/write under a single row key is atomic.
    &lt;ul&gt;
      &lt;li&gt;No matter how many columns are involved.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Data are lexicographic ordered by row key.&lt;/li&gt;
  &lt;li&gt;Tablet: dynamically partitioned row range.
    &lt;ul&gt;
      &lt;li&gt;Unit of distribution and load balancing.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Data access can gain good locality.
    &lt;ul&gt;
      &lt;li&gt;i.e., use reversed URL.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;22-column-families&quot;&gt;2.2 Column families&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Column families: grouped sets of column keys.
    &lt;ul&gt;
      &lt;li&gt;Basic unit of access control: different user can read/write different groups individually.&lt;/li&gt;
      &lt;li&gt;Basic unit of disk and memory accounting.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Data in a family are usually of the same type.&lt;/li&gt;
  &lt;li&gt;Number of column families should be small (up to hundreds) and rarely changed during operations.&lt;/li&gt;
  &lt;li&gt;Column key: &lt;code class=&quot;highlighter-rouge&quot;&gt;family:qualifier&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;In the example of web page data, &lt;code class=&quot;highlighter-rouge&quot;&gt;anchor&lt;/code&gt; is a family.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;23-timestamps&quot;&gt;2.3 Timestamps&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Represents multiple versions of the same data.&lt;/li&gt;
  &lt;li&gt;Can be assigned by Bigtable or clients.&lt;/li&gt;
  &lt;li&gt;Decreasing ordered.&lt;/li&gt;
  &lt;li&gt;Versions can be garbage collected automatically.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;3-api&quot;&gt;3 API&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Table-related
    &lt;ul&gt;
      &lt;li&gt;Creates/Deletes tables and column families.&lt;/li&gt;
      &lt;li&gt;Changes cluster, table and column family metadata, e.g., access control.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Values
    &lt;ul&gt;
      &lt;li&gt;Writes/Deletes values.&lt;/li&gt;
      &lt;li&gt;Looks up values from individual rows.&lt;/li&gt;
      &lt;li&gt;Iterates over a subset of data in a table.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Other
    &lt;ul&gt;
      &lt;li&gt;Single-row transactions.
        &lt;ul&gt;
          &lt;li&gt;e.g., read-modify-write.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Batching writes across row keys.&lt;/li&gt;
      &lt;li&gt;Cells can be used as integer counters.&lt;/li&gt;
      &lt;li&gt;Execution of client-supplied scripts.&lt;/li&gt;
      &lt;li&gt;Can be used with MapReduce, as inputs/outputs.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;4-building-blocks&quot;&gt;4 Building blocks&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;GFS: stores logs and data files.&lt;/li&gt;
  &lt;li&gt;Google SSTable is used to store data.
    &lt;ul&gt;
      &lt;li&gt;Persistent, ordered, immutable map from key to values.&lt;/li&gt;
      &lt;li&gt;A SSTable contains a sequence of blocks.
        &lt;ul&gt;
          &lt;li&gt;Block indexes are used to locate blocks. (Stored at the end of SSTable)&lt;/li&gt;
          &lt;li&gt;Data lookup: Load index into memory -&amp;gt; Find the block by binary search -&amp;gt; Read the block.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Chubby
    &lt;ul&gt;
      &lt;li&gt;Highly available, persistent distributed lock service.&lt;/li&gt;
      &lt;li&gt;Usages for Bigtable:
        &lt;ul&gt;
          &lt;li&gt;Ensure at most one active master.&lt;/li&gt;
          &lt;li&gt;Store bootstrap location of data.&lt;/li&gt;
          &lt;li&gt;Discover tablet servers and finalize tablet server deaths.&lt;/li&gt;
          &lt;li&gt;Store Bigtable schema information.&lt;/li&gt;
          &lt;li&gt;Store access control lists.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;5-implementation&quot;&gt;5 Implementation&lt;/h2&gt;

&lt;p&gt;3 major components: a library linked into every clients, one master server and many tablet servers.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Master is responsible for
    &lt;ul&gt;
      &lt;li&gt;assigning tablets to tablet serves;&lt;/li&gt;
      &lt;li&gt;detecting addition and deletion of tablet servers;&lt;/li&gt;
      &lt;li&gt;load-balancing;&lt;/li&gt;
      &lt;li&gt;garbage collection;&lt;/li&gt;
      &lt;li&gt;schema changes.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Tablet server
    &lt;ul&gt;
      &lt;li&gt;managers a set of tablets (10 - ~1000);
        &lt;ul&gt;
          &lt;li&gt;A tablet is a row range in the table, of size 100-200 MB by default.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;handles read and writes operations;
        &lt;ul&gt;
          &lt;li&gt;Clients talk with it directly, not via the master.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;splits tablets.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;tablet-location&quot;&gt;Tablet location&lt;/h3&gt;

&lt;p&gt;3-level hierarchy to store tablet location information. Locations are also cached on client library.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;A Chubby file contains the location of a root tablet.
    &lt;ul&gt;
      &lt;li&gt;Root tablet contains the locations of all tablets in a special &lt;code class=&quot;highlighter-rouge&quot;&gt;METADATA&lt;/code&gt; table.&lt;/li&gt;
    &lt;/ul&gt;
    &lt;ul&gt;
      &lt;li&gt;Root tablet is the first tablet of &lt;code class=&quot;highlighter-rouge&quot;&gt;METADATA&lt;/code&gt; table, but never split.
        &lt;ul&gt;
          &lt;li&gt;So no more than 3 levels.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;METADATA&lt;/code&gt; table
    &lt;ul&gt;
      &lt;li&gt;Contains locations of user tablets.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;User tablets&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;tablet-assignment&quot;&gt;Tablet assignment&lt;/h3&gt;

&lt;p&gt;Master keeps tracks of:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;the set of live tablet servers
    &lt;ul&gt;
      &lt;li&gt;Uses Chubby exclusive locks.&lt;/li&gt;
      &lt;li&gt;If a tablet server is unavailable, the master can detect it and reassign its tablets.
        &lt;ul&gt;
          &lt;li&gt;By trying to acquire its lock.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;current assignment of tablets to tablet servers, including unassigned ones
    &lt;ul&gt;
      &lt;li&gt;Master needs to discover the assignments upon startup.
        &lt;ul&gt;
          &lt;li&gt;scans and communicates with all tablet servers.&lt;/li&gt;
          &lt;li&gt;scans &lt;code class=&quot;highlighter-rouge&quot;&gt;METADATA&lt;/code&gt; table for all tablets.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Master initiates the creation, deletion of table and merging two tablets, thus keeps tracks of these changes regarding tablet assignments. Besides them, tablet split is initialized by tablet server. This change would be known by the master upon change committing or reading the split tablet.&lt;/p&gt;

&lt;h3 id=&quot;tablet-serving&quot;&gt;Tablet serving&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;A commit log for redo records.&lt;/li&gt;
  &lt;li&gt;A memtable for recent updates.&lt;/li&gt;
  &lt;li&gt;A sequence of SSTable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Operations:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Recover tablet: reads the indices of SSTables into memory and reconstructs the memtable by applying all updates since redo points.&lt;/li&gt;
  &lt;li&gt;Writes:
    &lt;ul&gt;
      &lt;li&gt;Write to the commit log.&lt;/li&gt;
      &lt;li&gt;Write to the memtable.&lt;/li&gt;
      &lt;li&gt;Group commit is good for improving throughput of small mutations.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Reads: the server reads the merged view of the sequence of SSTables and memtable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;compactions&quot;&gt;Compactions&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Minor compaction
    &lt;ul&gt;
      &lt;li&gt;Write the reach-threshold memtable into SSTable.
        &lt;ul&gt;
          &lt;li&gt;Reduce memory usage.&lt;/li&gt;
          &lt;li&gt;Reduce amount of data to read during recovery.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Merging compaction
    &lt;ul&gt;
      &lt;li&gt;Merge a few SSTables and memtable into a new SSTable.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Major compaction
    &lt;ul&gt;
      &lt;li&gt;Merge all SSTables into a new SSTable.&lt;/li&gt;
      &lt;li&gt;Remove all deletion entries(tombstone) in old SSTables.
        &lt;ul&gt;
          &lt;li&gt;Tombstone of a record in a newer SSTable prevent the use of the record in a older SSTable.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;refinements&quot;&gt;Refinements&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Locality groups
    &lt;ul&gt;
      &lt;li&gt;Groups multiple column families to use a separate SSTable, in a tablet.
        &lt;ul&gt;
          &lt;li&gt;Accessed together frequently.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Can be declared to be in-memory.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Compression
    &lt;ul&gt;
      &lt;li&gt;Can specify whether to compress and compression format for locality groups.&lt;/li&gt;
      &lt;li&gt;Example compression format: 1st pass using Bently &amp;amp; McIlroy’s scheme; 2nd pass with a fast compression algorithm.
        &lt;ul&gt;
          &lt;li&gt;Often 10-to-1 reduction in space.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Caching for read performance
    &lt;ul&gt;
      &lt;li&gt;Scan cache: higher-level caching the k-v pairs returned by the SSTable interface.&lt;/li&gt;
      &lt;li&gt;Block cache: lower-level caching the SSTable blocks that were read from GFS.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Bloom filters
    &lt;ul&gt;
      &lt;li&gt;Whether a SSTable might contain any data for a specified row/column pair.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Commit-log implementation
    &lt;ul&gt;
      &lt;li&gt;Appends mutations to a single commit log per tablet server, for all tablets.
        &lt;ul&gt;
          &lt;li&gt;Avoids a large number of log file being written concurrently to GFS.&lt;/li&gt;
          &lt;li&gt;Recovery becomes complicated since tablets will be moved to many other tablet servers.
            &lt;ul&gt;
              &lt;li&gt;Master will initialize a sort of the log entries with respect with keys to tackle this.&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Tablet server will maintain two log writing threads. If one thread performs poorly, switches to the other one.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Speeding up tablet recovery
    &lt;ul&gt;
      &lt;li&gt;The source tablet server with do minor compaction on tablets and the log to speed up.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Exploiting immutability
    &lt;ul&gt;
      &lt;li&gt;All generated SSTables are immutable.
        &lt;ul&gt;
          &lt;li&gt;To delete data, use garbage collection on obsolete SSTable data.&lt;/li&gt;
          &lt;li&gt;Can split the tablet quickly. Child tablets share the SSTable of the parent tablet.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Memtables are mutable; we use copy-on-write to reduce contentions during reads and reads and writes can be proceeded in parallel.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;performance-evaluation&quot;&gt;Performance evaluation&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Performance doesn’t increase linearly with respect to the number of servers.
    &lt;ul&gt;
      &lt;li&gt;There is a significant drop in per-server throughput.
        &lt;ul&gt;
          &lt;li&gt;Imbalance in load in multiple server configurations.&lt;/li&gt;
          &lt;li&gt;Network links are saturated.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;lessons&quot;&gt;Lessons&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Systems are vulnerable to many types of failures, expected or unexpected.&lt;/li&gt;
  &lt;li&gt;Add new features until it’s clear how they would be used.&lt;/li&gt;
  &lt;li&gt;Proper system-level monitoring.&lt;/li&gt;
  &lt;li&gt;Value of simple design.&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
    
      <item>
        <title>Read &quot;Streaming Systems&quot; 3, Watermarks</title>
        <link>/2020/05/03/streaming-systems-3.html</link>
        <guid isPermaLink="true">/2020/05/03/streaming-systems-3.html</guid>
        <pubDate>Sun, 03 May 2020 00:00:00 +0000</pubDate>
        <description>&lt;h2 id=&quot;watermarks&quot;&gt;Watermarks&lt;/h2&gt;

&lt;h3 id=&quot;definition&quot;&gt;Definition&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Assumption: Any event in the streaming data has an associated logical event timestamp.
    &lt;ul&gt;
      &lt;li&gt;Can use the time of the original event’s occurrence.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Definition: The watermark is a monotonically increasing timestamp of the oldest work not yet completed.
    &lt;ul&gt;
      &lt;li&gt;Completeness: Watermark allows to know when it’s correct to close a window.
        &lt;ul&gt;
          &lt;li&gt;If watermark has passed a time &lt;code class=&quot;highlighter-rouge&quot;&gt;T&lt;/code&gt;, we are guaranteed by its monotonic policy that no more processing would occur for an event with event time at or before &lt;code class=&quot;highlighter-rouge&quot;&gt;T&lt;/code&gt;.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Visibility
        &lt;ul&gt;
          &lt;li&gt;Watermark cannot advance if an event is being stuck in the pipeline.&lt;/li&gt;
          &lt;li&gt;We can find the source of problem if this happens.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;source-watermark-creation&quot;&gt;Source watermark creation&lt;/h3&gt;

&lt;p&gt;Watermarks can be perfect or heuristic.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Perfect watermarks account for all data.&lt;/li&gt;
  &lt;li&gt;Heuristic watermarks admit some late-data elements.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;perfect-watermark-creation&quot;&gt;Perfect watermark creation&lt;/h4&gt;

&lt;p&gt;This requires perfect knowledge of the input, thus is not impractical for many real-world problems. Following examples can utilize perfect watermarks.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Ingress timestamping
    &lt;ul&gt;
      &lt;li&gt;Use the ingress times as the event times fot data items.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Static sets of time-ordered logs.
    &lt;ul&gt;
      &lt;li&gt;Just the minimum timestamp of unprocessed records across all partitions.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;heuristic-watermark-creation&quot;&gt;Heuristic watermark creation&lt;/h4&gt;

&lt;p&gt;Using heuristic watermarks can lead to late data, but it’s still possible to build a highly accurate heuristic watermarks. For example,&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Dynamic sets of time-ordered logs
    &lt;ul&gt;
      &lt;li&gt;By tracking the minimum timestamp for unprocessed records in known set, growth rates, external knowledge like network topology and bandwidth.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Google Cloud Pub/Sub
    &lt;ul&gt;
      &lt;li&gt;No guarantee on in-order delivery.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is no one-fits-all solution. At least, we simplify the problem of tracking completeness in a pipeline, into the problem of creating a watermark at the source.&lt;/p&gt;

&lt;h3 id=&quot;watermark-propagation&quot;&gt;Watermark propagation&lt;/h3&gt;

&lt;p&gt;A pipeline may have multiple independent stages. It’s meaningful to track individual watermarks for these stages. Note that for stages come later, their watermark is older than those of prior stages, since they have seen less records.&lt;/p&gt;

&lt;p&gt;For a stage, defining watermarks at boundaries. We can calculate the amount of event-time latency/lag introduced by a stage.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Input watermark:
    &lt;ul&gt;
      &lt;li&gt;minimum of the output watermarks of its upstream input/sources/stages.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Output watermark:
    &lt;ul&gt;
      &lt;li&gt;minimum of its input watermark and event times of all non-late active messages within the stage.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Within a stage, processing is not monolithic, as different components/buffer may exist and they can have their own watermarks as well. Therefore, the output watermark of the stage may be the minimum of:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Per-source watermark: for each sending stage.&lt;/li&gt;
  &lt;li&gt;Per-external input watermark.&lt;/li&gt;
  &lt;li&gt;Per-state component watermark: for each type of state that can be written.&lt;/li&gt;
  &lt;li&gt;Per-output buffer watermark: for each receiving stage.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;watermark-propagation-and-output-timestamps&quot;&gt;Watermark propagation and output timestamps&lt;/h4&gt;

&lt;p&gt;Within a stage, processing can be divided into windows in event-time domain. The output timestamp of each window advances the output watermark of this stage. We have several choice for the output timestamp for a window:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;End of the window
    &lt;ul&gt;
      &lt;li&gt;allows the smoothest watermark progression.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Timestamp of the first non-late element
    &lt;ul&gt;
      &lt;li&gt;Most conservative&lt;/li&gt;
      &lt;li&gt;Watermark progression may be likely delayed.
        &lt;ul&gt;
          &lt;li&gt;Output watermark is held until that window processing is complete.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Timestamp of a specific element
    &lt;ul&gt;
      &lt;li&gt;For some special use cases, it may make sense.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;the-tricky-case-of-overlapping-windows&quot;&gt;The tricky case of overlapping windows&lt;/h4&gt;

&lt;p&gt;If an element is in 3 overlapping windows, when 1st stage of 1st window complete, the input watermark of the 2nd stage of the 1st window is held by the output watermark of the 1st stage of the 2nd and 3rd windows. This delay is unnecessary. Apache Beam has a special logic for this: output timestamp of &lt;code class=&quot;highlighter-rouge&quot;&gt;N+1&lt;/code&gt; window is always greater than that of &lt;code class=&quot;highlighter-rouge&quot;&gt;N&lt;/code&gt; window.&lt;/p&gt;

&lt;h3 id=&quot;percentile-watermarks&quot;&gt;Percentile Watermarks&lt;/h3&gt;

&lt;p&gt;Instead of using the minimum of the event timestamps of active messages, we can consider the entire distribution of event timestamps and use percentile watermark.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A 90-percentile watermark means we are guaranteed to have processed this percentage of all events with earlier timestamp.&lt;/li&gt;
  &lt;li&gt;Avoids being delay by outliers.&lt;/li&gt;
  &lt;li&gt;A good way to tune the trade-off between latency of materializing results and precision of results.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;processing-time-watermarks&quot;&gt;Processing-time watermarks&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Event-time based watermark is unable to distinguish delays caused by old data or a delayed system (processing being stuck).&lt;/li&gt;
  &lt;li&gt;Processing-time watermark is the processing-time timestamp of the oldest active message.&lt;/li&gt;
  &lt;li&gt;Can be used at system-implementation level for tasks such as garbage collections.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;case-studies&quot;&gt;Case studies&lt;/h3&gt;

&lt;h4 id=&quot;watermarks-in-google-cloud-dataflow&quot;&gt;Watermarks in Google Cloud Dataflow&lt;/h4&gt;

&lt;h4 id=&quot;watermarks-in-apache-flink&quot;&gt;Watermarks in Apache Flink&lt;/h4&gt;

&lt;h4 id=&quot;source-watermarks-for-google-cloud-pubsub&quot;&gt;Source watermarks for Google Cloud Pub/Sub&lt;/h4&gt;

</description>
      </item>
    
      <item>
        <title>Read &quot;Streaming Systems&quot; 1&amp;2, Streaming 101</title>
        <link>/2019/12/07/streaming-systems-1-2.html</link>
        <guid isPermaLink="true">/2019/12/07/streaming-systems-1-2.html</guid>
        <pubDate>Sat, 07 Dec 2019 00:00:00 +0000</pubDate>
        <description>&lt;h2 id=&quot;streaming-101&quot;&gt;Streaming 101&lt;/h2&gt;

&lt;h3 id=&quot;what-is-streaming&quot;&gt;What is streaming?&lt;/h3&gt;

&lt;p&gt;Streaming system: A type of data processing engine that is designed with infinite datasets in mind.&lt;/p&gt;

&lt;p&gt;Two dimensions to describe a dataset:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Cardinality
    &lt;ul&gt;
      &lt;li&gt;Dictates the dataset size.&lt;/li&gt;
      &lt;li&gt;Bounded/unbounded.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Constitution
    &lt;ul&gt;
      &lt;li&gt;Dictates the physical manifestation: the ways one can interact with the data in question.
        &lt;ul&gt;
          &lt;li&gt;Table
            &lt;ul&gt;
              &lt;li&gt;A holistic view of a dataset at a time point.&lt;/li&gt;
              &lt;li&gt;SQL&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
          &lt;li&gt;Stream
            &lt;ul&gt;
              &lt;li&gt;Element-by-element view of the evolution of a dataset over time.&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;greatly-exaggerated-limitations-of-streaming&quot;&gt;Greatly exaggerated limitations of streaming&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;Streaming systems have historically been relegated to a somewhat niche market of providing low-latency, inaccurate or speculative results. (Lambda architecture)&lt;/li&gt;
  &lt;li&gt;Kappa architecture: Run a single pipeline that can replay.&lt;/li&gt;
  &lt;li&gt;A well-designed streaming system actually provide a strict superset of batch functionality. (Apache Flink)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Streaming systems need two things to beat batch ones:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Correctness
    &lt;ul&gt;
      &lt;li&gt;Boils down to consistent storage.&lt;/li&gt;
      &lt;li&gt;Streaming systems need a method for checkpointing persistent state over time, which should remain consistent in light of failures.
        &lt;ul&gt;
          &lt;li&gt;Strong consistency is required for exact-once processing.
            &lt;ul&gt;
              &lt;li&gt;(ST) Strong consistency -&amp;gt; unique ID -&amp;gt; exact-once -&amp;gt; correctness.&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Tools for reasoning about time
    &lt;ul&gt;
      &lt;li&gt;Essential for dealing with unbounded, unordered data of varying event-time skew.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;event-time-vs-processing-time&quot;&gt;Event time vs. processing time&lt;/h4&gt;

&lt;p&gt;Two domains of time:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Event time
    &lt;ul&gt;
      &lt;li&gt;When the event actually occurred.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Processing time
    &lt;ul&gt;
      &lt;li&gt;When the event is observed in the system.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The skews between event time and processing time are often highly variable.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/system/streaming/event-processing-time.png&quot; alt=&quot;Event Time vs Processing Time&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Processing-time lag is always equal to event-time skew.&lt;/p&gt;

&lt;p&gt;Windowing:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;By processing time: not quite make sense if we care about event time, since some events may fall into wrong processing-time window due to skew.&lt;/li&gt;
  &lt;li&gt;By event time: Need a way to reason the completeness, how we can determine when we have observed all events in a window.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;data-processing-patterns&quot;&gt;Data processing patterns&lt;/h3&gt;

&lt;h4 id=&quot;bounded-data&quot;&gt;Bounded data&lt;/h4&gt;

&lt;p&gt;The overall model is quite simple, using engines like MapReduce.&lt;/p&gt;

&lt;h4 id=&quot;unbounded-data-batch&quot;&gt;Unbounded data: batch&lt;/h4&gt;

&lt;p&gt;Batch engines can be used to process unbounded data by windowing.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Fixed windows
    &lt;ul&gt;
      &lt;li&gt;Process each window as a separate, bounded data source.&lt;/li&gt;
      &lt;li&gt;Completeness problem: Some events may be delayed.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Sessions
    &lt;ul&gt;
      &lt;li&gt;A period of activity terminated by a gap of inactivity.&lt;/li&gt;
      &lt;li&gt;Not ideal since a session may be split across batches.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;unbounded-data-streaming&quot;&gt;Unbounded data: streaming&lt;/h4&gt;

&lt;p&gt;Unbounded data sources in reality may be high unordered with respect to event times, or of varying event-time skew. 4 groups of approaches can help:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Time-agnostic
    &lt;ul&gt;
      &lt;li&gt;Used when time is essentially irrelevant.&lt;/li&gt;
      &lt;li&gt;Engines just need to support basic data delivery.&lt;/li&gt;
      &lt;li&gt;Examples
        &lt;ul&gt;
          &lt;li&gt;Filtering, e.g., web log for a specific domain.&lt;/li&gt;
          &lt;li&gt;Inner joins: buffer the inner source and check the events from the other source.
            &lt;ul&gt;
              &lt;li&gt;May be time-related if we want garbage collection.&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Approximation
    &lt;ul&gt;
      &lt;li&gt;Algorithms: approximate Top-N, streaming k-means etc.&lt;/li&gt;
      &lt;li&gt;Designed to be low overhead but limited and often complicated.&lt;/li&gt;
      &lt;li&gt;Usually processing-time based and provides some provable error bounds on the approximations.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;(Windowing basics)
    &lt;ul&gt;
      &lt;li&gt;Fixed windows, tumbling, no overlap&lt;/li&gt;
      &lt;li&gt;Sliding windows, hopping, with overlap&lt;/li&gt;
      &lt;li&gt;Sessions&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Windowing by processing time
    &lt;ul&gt;
      &lt;li&gt;Nice things
        &lt;ul&gt;
          &lt;li&gt;Simple.&lt;/li&gt;
          &lt;li&gt;Judging window completeness is straightforward.&lt;/li&gt;
          &lt;li&gt;Exact what we want if we want to infer information as the data is &lt;strong&gt;observed&lt;/strong&gt;. e.g., monitoring.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Downside
        &lt;ul&gt;
          &lt;li&gt;Cannot reflect the reality in event time domain. Processing-time order doesn’t respect event-time order.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Windowing by event time
    &lt;ul&gt;
      &lt;li&gt;Supports for it has been evolving: Flink -&amp;gt; Spark -&amp;gt; Storm -&amp;gt; Apex.&lt;/li&gt;
      &lt;li&gt;Advantages
        &lt;ul&gt;
          &lt;li&gt;Gold standard of windowing.&lt;/li&gt;
          &lt;li&gt;Correctness&lt;/li&gt;
          &lt;li&gt;Dynamically sized windows like sessions.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Problems
        &lt;ul&gt;
          &lt;li&gt;Buffering: more buffering is required
            &lt;ul&gt;
              &lt;li&gt;Good things
                &lt;ul&gt;
                  &lt;li&gt;Persistent storage is cheaper now.&lt;/li&gt;
                  &lt;li&gt;Update can be incremental, without buffering entire input set.&lt;/li&gt;
                &lt;/ul&gt;
              &lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
          &lt;li&gt;Completeness
            &lt;ul&gt;
              &lt;li&gt;No good way of knowing when we’ve seen all of data for a given window.&lt;/li&gt;
              &lt;li&gt;Solution: Use heuristic estimate like watermarks (MillWheel, Cloud Dataflow, Flink).
                &lt;ul&gt;
                  &lt;li&gt;If we need absolute correctness, The only real option is let the pipeline builder to express when to materialize.&lt;/li&gt;
                &lt;/ul&gt;
              &lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-what-where-when-and-how-of-data-processing&quot;&gt;The What, Where, When and How of data processing&lt;/h2&gt;

&lt;h3 id=&quot;roadmap&quot;&gt;Roadmap&lt;/h3&gt;

&lt;p&gt;Five main concepts for this chapter:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Processing time vs. event time
    &lt;ul&gt;
      &lt;li&gt;Use event time if we care about correctness and when things actually occur.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Windowing
    &lt;ul&gt;
      &lt;li&gt;Fixed, sliding, sessions.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Triggers
    &lt;ul&gt;
      &lt;li&gt;A mechanism for declaring when the output for a window should be materialized relative to some external signal.&lt;/li&gt;
      &lt;li&gt;Can have multiple triggers to observe the output for a window multiple times as it evolves. (early update, processing late data)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Watermarks
    &lt;ul&gt;
      &lt;li&gt;A notion of input completeness with respect to event times.&lt;/li&gt;
      &lt;li&gt;Statement for a watermark with value of time X: All input data with event times less than X have been observed.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Accumulation
    &lt;ul&gt;
      &lt;li&gt;Specify the relationship between multiple results that are observed for the same window.&lt;/li&gt;
      &lt;li&gt;Different accumulation modes are available to different use cases.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Critical questions to ask for every unbounded data processing problem:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;What&lt;/strong&gt; results are calculated?
    &lt;ul&gt;
      &lt;li&gt;e.g., sum, histograms, training ML models.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Where&lt;/strong&gt; in event time are results calculated?
    &lt;ul&gt;
      &lt;li&gt;Event-time windowing.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;When&lt;/strong&gt; in processing time are result materialized?
    &lt;ul&gt;
      &lt;li&gt;By the use of triggers and (optionally) watermarks.&lt;/li&gt;
      &lt;li&gt;Repeated update triggers vs watermarks.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;How&lt;/strong&gt; do refinement of results relate?
    &lt;ul&gt;
      &lt;li&gt;By the types of accumulation used: discarding, accumulating, accumulating &amp;amp; retracting.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;batch-foundations&quot;&gt;Batch foundations&lt;/h3&gt;

&lt;h4 id=&quot;what-transforming&quot;&gt;What: transforming&lt;/h4&gt;

&lt;p&gt;Some Apache Beam primitives:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;PCollections&lt;/code&gt;: Datasets across which parallel transformations can be performed.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;PTransforms&lt;/code&gt;: Can be applied on &lt;code class=&quot;highlighter-rouge&quot;&gt;PCollections&lt;/code&gt; to create new &lt;code class=&quot;highlighter-rouge&quot;&gt;PCollections&lt;/code&gt;.
    &lt;ul&gt;
      &lt;li&gt;Element-wise transformation.&lt;/li&gt;
      &lt;li&gt;Group/aggregate.&lt;/li&gt;
      &lt;li&gt;Composite combination of other &lt;code class=&quot;highlighter-rouge&quot;&gt;PTransformations&lt;/code&gt;.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;where-windowing&quot;&gt;Where: windowing&lt;/h4&gt;

&lt;p&gt;Example Beam code of windowed summation:&lt;/p&gt;

&lt;div class=&quot;language-java 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;n&quot;&gt;Pcollection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;KV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Team&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Integer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;totals&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Window&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;into&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FixedWindows&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TWO_MINUTES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;integersPerKey&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;going-streaming&quot;&gt;Going Streaming&lt;/h3&gt;

&lt;p&gt;We would like to have lower latency and natively handle unbounded data sources.&lt;/p&gt;

&lt;h4 id=&quot;when-triggers&quot;&gt;When: triggers&lt;/h4&gt;

&lt;p&gt;Triggers declare when output for a window should happen in processing time. Two useful types of triggers:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Repeated update triggers
    &lt;ul&gt;
      &lt;li&gt;Periodically generate updated panes for a window as its contents evolve.&lt;/li&gt;
      &lt;li&gt;Can be materialized with every new record or after some processing-time delays, like once a minute.&lt;/li&gt;
      &lt;li&gt;The most common, simple to implement and understand.&lt;/li&gt;
      &lt;li&gt;Choose processing-time delay:
        &lt;ul&gt;
          &lt;li&gt;Aligned delays
            &lt;ul&gt;
              &lt;li&gt;Processing time domain is spliced into fixed regions by the delays.&lt;/li&gt;
              &lt;li&gt;Get regular updates across all modified windows at the same time.
                &lt;ul&gt;
                  &lt;li&gt;Good for predictability.&lt;/li&gt;
                  &lt;li&gt;Bad for causing bursty workloads.&lt;/li&gt;
                &lt;/ul&gt;
              &lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
          &lt;li&gt;Unaligned delays
            &lt;ul&gt;
              &lt;li&gt;The delay is relative to the data observed within a given window.&lt;/li&gt;
              &lt;li&gt;Better for large-scale processing: Spread the load out more evenly across time.&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Completeness triggers
    &lt;ul&gt;
      &lt;li&gt;Output only after the input for that window is believed to be complete to some threshold.&lt;/li&gt;
      &lt;li&gt;Closely align with batch processing. We would need a way to reasoning about completeness, thus watermarks sound like a better idea.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;when-watermarks&quot;&gt;When: watermarks&lt;/h4&gt;

&lt;p&gt;Watermark are temporal notions of input completeness in the event-time domain, to better support answering “When in processing time are result materialized?” Watermark can be modeled as a function: &lt;code class=&quot;highlighter-rouge&quot;&gt;F(P) -&amp;gt; E&lt;/code&gt;, which takes a processing time &lt;code class=&quot;highlighter-rouge&quot;&gt;P&lt;/code&gt; then returns a event time &lt;code class=&quot;highlighter-rouge&quot;&gt;E&lt;/code&gt;. At this point, all events with event time less than &lt;code class=&quot;highlighter-rouge&quot;&gt;E&lt;/code&gt; have been observed. Watermarks can be perfect (if we have enough knowledge about the input source) or heuristic (could be remarkably accurate in many cases, but may cause late data sometimes). It forms the foundation of completeness triggers.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Advantages
    &lt;ul&gt;
      &lt;li&gt;A way to reason completeness. e.g., in outer joins, emit a partial join record instead of keep waiting.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Shortcomings
    &lt;ul&gt;
      &lt;li&gt;Too slow
        &lt;ul&gt;
          &lt;li&gt;A watermark could be delayed due to known unprocessed data.&lt;/li&gt;
          &lt;li&gt;Not ideal from a latency perspective.&lt;/li&gt;
          &lt;li&gt;Perfect watermarks still suffer from this.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Too fast
        &lt;ul&gt;
          &lt;li&gt;A heuristic watermark is incorrectly advanced earlier than it should be, creating late data.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Conclusion is we cannot get both low latency and correctness based on merely completeness trigger. Combination of repeated update triggers and watermarks sounds a better idea.&lt;/p&gt;

&lt;h4 id=&quot;when-earlyon-timelate-triggers&quot;&gt;When: early/on-time/late triggers&lt;/h4&gt;

&lt;p&gt;The combination of repeated update/watermark triggers partitions the panes to materialize into 3 categories:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Zero or more early panes
    &lt;ul&gt;
      &lt;li&gt;Repeatedly update until the watermark passes the end of window.&lt;/li&gt;
      &lt;li&gt;Prevent being too slow.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;A single on-time pane
    &lt;ul&gt;
      &lt;li&gt;Fire when the watermark passes the end of window.&lt;/li&gt;
      &lt;li&gt;Safe to reason about missing data.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Zero or more late panes
    &lt;ul&gt;
      &lt;li&gt;Fire for late data.&lt;/li&gt;
      &lt;li&gt;Compensate being too fast.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Window lifetime bounds: For heuristic watermarks, we need to keep the state of the window for some duration even after the watermark has passed. To determine how long we need to keep around for each window, &lt;strong&gt;allowed lateness&lt;/strong&gt; comes in.&lt;/p&gt;

&lt;h4 id=&quot;when-allowed-lateness-garbage-collection&quot;&gt;When: allowed lateness (garbage collection)&lt;/h4&gt;

&lt;p&gt;A real-world system needs to bound the lifetime of the windows, defining how late (relative to watermark) a piece of data could be. It would drop data arriving too late since no one cares about it. It’s a kind of garbage collection.&lt;/p&gt;

&lt;p&gt;Using processing time is easy but vulnerable to issues within the pipeline itself (e.g., worker crashing). We should specify the horizon in event-time domain, which directly ties with the actual progress of the pipeline.&lt;/p&gt;

&lt;p&gt;Different types of watermarks:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Low watermarks
    &lt;ul&gt;
      &lt;li&gt;Pessimistically attempt to capture the event time of the oldest unprocessed record the system is aware.&lt;/li&gt;
      &lt;li&gt;Resilient to changes in event-time skew.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;High watermarks
    &lt;ul&gt;
      &lt;li&gt;Optimistically track the event time of the newest record the system is aware of. (maximum event-time skew)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(ST) e.g., We have a event-time window [0, 3] and unprocessed event 1, 2, 4. Low watermark would be 1, thus 1 and 2 will be processed for the window. High watermark is 4, which passes the end of window thus causes missing 1 and 2.&lt;/p&gt;

&lt;p&gt;If we have perfect watermarks, no need to care about late data sine there will be none. For cases that we do global aggregations over a finite number of keys, we don’t need to specify lateness horizon; no need to do garbage collection.&lt;/p&gt;

&lt;h4 id=&quot;how-accumulation&quot;&gt;How: accumulation&lt;/h4&gt;

&lt;p&gt;3 modes of accumulation:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Discarding
    &lt;ul&gt;
      &lt;li&gt;Every time a pane is materialized, any stored state is discarded. Panes are independent.&lt;/li&gt;
      &lt;li&gt;e.g., each pane represents delta. Downstream is required to do their own summation.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Accumulating
    &lt;ul&gt;
      &lt;li&gt;Future inputs are accumulated into the existing state.&lt;/li&gt;
      &lt;li&gt;e.g., Pipeline does the sum itself.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Accumulating and retracting
    &lt;ul&gt;
      &lt;li&gt;When produce a new pane, also produce an independent retraction for previous panes.&lt;/li&gt;
      &lt;li&gt;Meaning “I previously told you X, but I was wrong. Get rid of the X I told you last time, and replace it with Y”.&lt;/li&gt;
      &lt;li&gt;Two cases when it’s useful:
        &lt;ul&gt;
          &lt;li&gt;Consumers downstream are regrouping data by a different dimension, thus a new value for a key may be put in a different group.&lt;/li&gt;
          &lt;li&gt;Dynamic windows: the new value might be replacing more than one previous window.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
    
      <item>
        <title>Home network, media center setup</title>
        <link>/2019/11/13/nas.html</link>
        <guid isPermaLink="true">/2019/11/13/nas.html</guid>
        <pubDate>Wed, 13 Nov 2019 00:00:00 +0000</pubDate>
        <description>&lt;h2 id=&quot;background&quot;&gt;Background&lt;/h2&gt;

&lt;p&gt;Recently, I set up my home network for digital content sharing. I will take some notes here for future reference.&lt;/p&gt;

&lt;h2 id=&quot;devices&quot;&gt;Devices&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Router: &lt;a href=&quot;https://www.amazon.com/gp/product/B01MQDZXA4/ref=ppx_yo_dt_b_asin_title_o01_s00?ie=UTF8&amp;amp;psc=1&quot;&gt;Netgear Nighthawk AX8 AX6000&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;Supports Wifi 6, MU-MIMO, link aggregation (802.3ad).&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;NAS: &lt;a href=&quot;https://www.amazon.com/Synology-DS418play-Station-4-bay-Diskless/dp/B075ZNKCK4/ref=sr_1_7?crid=1I6LVHQYH405I&amp;amp;keywords=ds418play&amp;amp;qid=1573714006&amp;amp;sprefix=ds41%2Caps%2C206&amp;amp;sr=8-7&quot;&gt;Synology DS418play&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;4-bay, 2GB RAM, 1Gbps ports, supports 4K transcoding.&lt;/li&gt;
      &lt;li&gt;But doesn’t support Dock natively.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;HDD:
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://www.amazon.com/Red-4TB-NAS-Hard-Drive/dp/B00EHBERSE/ref=sr_1_2?keywords=wd+red+4tb&amp;amp;qid=1573711578&amp;amp;smid=ATVPDKIKX0DER&amp;amp;sr=8-2&quot;&gt;WD Red 4TB&lt;/a&gt; * 3&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://www.westerndigital.com/products/outlet/internal-drives/wd-red-plus-sata-3-5-hdd?ef_id=Cj0KCQjwr-SSBhC9ARIsANhzu15PHYNy56_rRQ2sEtDazOF8HD0ST6HccK2cIy0BlTpmP5sqofq5qIwaAlNDEALw_wcB:G:s&amp;amp;s_kwcid=AL!15012!3!383412283172!!!u!873862296940!!6515920533!80822013760&amp;amp;utm_medium=pdsh2&amp;amp;utm_source=gads&amp;amp;utm_campaign=WD-NA-US-PLA&amp;amp;utm_content=873862296940&amp;amp;utm_term=WD140EFFX#WD140EFFX&quot;&gt;WD Red 14TB&lt;/a&gt; * 1&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;UPS: &lt;a href=&quot;https://www.dell.com/en-us/member/shop/accessories/apd/a5547002&quot;&gt;APC Back-UPS 650VA UPS&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;4K player for TV: &lt;a href=&quot;https://www.nvidia.com/en-us/shield/shield-tv-pro/&quot;&gt;Nvidia shield pro&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;upgrades-in-2022&quot;&gt;Upgrades in 2022&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://store.ui.com/collections/unifi-network-unifi-os-consoles/products/udm-pro&quot;&gt;Unifi Dream Machine Pro&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;Gateway, NVR&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://store.ui.com/collections/unifi-network-switching/products/usw-pro-24-poe&quot;&gt;Unifi Switch Pro 24 PoE&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;POE&lt;/li&gt;
      &lt;li&gt;Level 3 switching&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;A bunch of Unifi G4 cameras for surveilliance.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.zidoo.tv/Product/index/model/Z9X/target/VEMg6VRC2%2B9KKmVViAFMcQ%3D%3D.html&quot;&gt;Ziddo Z9X player&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Router and NAS setup are pretty straightforward.
    &lt;ul&gt;
      &lt;li&gt;One RAID 1 (4TB) to store documents I can’t lose, photos etc. Can use HyperBackup to sync it to a cloud drive as well.&lt;/li&gt;
      &lt;li&gt;One RAID 0 (18TB) to store downloaded BT contents.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Link aggregation
    &lt;ul&gt;
      &lt;li&gt;Needs to configure this on both router and NAS.&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://www.synology.com/en-global/knowledgebase/DSM/help/DSM/AdminCenter/connection_network_linkaggr&quot;&gt;Synology doc&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Time machine backup for macOS
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://www.synology.com/en-us/knowledgebase/DSM/tutorial/Backup/How_to_back_up_files_from_Mac_to_Synology_NAS_with_Time_Machine&quot;&gt;Synology doc&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;The default file transfer protocol between macOS and NAS is SMB. Here are some tips to optimize it.
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://support.apple.com/en-us/HT208209&quot;&gt;Apple support doc&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://support.apple.com/en-us/HT205926&quot;&gt;Turn off packet signing&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;Result: Read speed of a 1.48GB file increased from 58 MB/s to 95 MB/s.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;UPS: just connect then enable it in Hardware settings.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;synology-nas&quot;&gt;Synology NAS&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;I tried to manually configure DNS server to &lt;code class=&quot;highlighter-rouge&quot;&gt;8.8.8.8&lt;/code&gt; in Control Panel -&amp;gt; Network for external access. But this setting seemed to cause some interruptions for DSM connection. Also, transmission jobs experienced frequent 0-speed time. It may not be a good idea.&lt;/li&gt;
  &lt;li&gt;Move installed packages between volume: &lt;a href=&quot;https://veducate.co.uk/synology-moving-a-package-between-volumes/&quot;&gt;unofficial tricks&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;bt&quot;&gt;BT&lt;/h2&gt;

&lt;p&gt;I found the official Download station package in DSM is not quite optimized for BT downloading. Transmission is a better choice. Here are steps to install and setup in Synology DSM.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Add “synocommunity” in Package Center -&amp;gt; Settings -&amp;gt; Package Sources.
    &lt;ul&gt;
      &lt;li&gt;Location: &lt;a href=&quot;http://packages.synocommunity.com&quot;&gt;http://packages.synocommunity.com&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Set Trust Level to “Synology Inc. and trusted publishers” in Package Center -&amp;gt; Settings -&amp;gt; General.&lt;/li&gt;
  &lt;li&gt;Install “Transmission” in Package Center -&amp;gt; Community.&lt;/li&gt;
  &lt;li&gt;Create folders to be used.
    &lt;ul&gt;
      &lt;li&gt;“download” for completed downloads.&lt;/li&gt;
      &lt;li&gt;“watch”: Transmission will start a download task automatically once a torrent file is added here.&lt;/li&gt;
      &lt;li&gt;“incomplete” for downloading files.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Start the installation in Package Center; fill in all the folder information and credentials.&lt;/li&gt;
  &lt;li&gt;Set up Read/Write permission for Group “sc-download” for those folders in Control Panel -&amp;gt; Group -&amp;gt; sc-download -&amp;gt; edit -&amp;gt; Permissions.&lt;/li&gt;
  &lt;li&gt;All done! View the web UI at &lt;a href=&quot;http://your_nas_ip:9091&quot;&gt;http://your_nas_ip:9091&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;The package can be started or stopped in the Package Center.&lt;/li&gt;
      &lt;li&gt;Available GUI: &lt;a href=&quot;https://github.com/transmission-remote-gui/transgui/releases&quot;&gt;transgui&lt;/a&gt;.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;kodi--emby&quot;&gt;Kodi &amp;amp; Emby&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Install emby-next-gen add-on following &lt;a href=&quot;https://github.com/MediaBrowser/plugin.video.emby/wiki/Emby-Repository&quot;&gt;Emby doc&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Use Kodi native play mode instead of add-on mode:
    &lt;ul&gt;
      &lt;li&gt;Set up optional shared network folder in emby.
        &lt;ul&gt;
          &lt;li&gt;e.g., map &lt;code class=&quot;highlighter-rouge&quot;&gt;volume1/video&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;smb://&amp;lt;nas_ip&amp;gt;/video&lt;/code&gt; thus network devices can recognize the path.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Input your credentials at kodi: File manager -&amp;gt; Add source -&amp;gt; Add a network location.&lt;/li&gt;
      &lt;li&gt;Change the emby settings in kodi.
        &lt;ul&gt;
          &lt;li&gt;Need to turn off forced HTTP playback as well.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Cannot import external subtitles
    &lt;ul&gt;
      &lt;li&gt;Make sure the subtitle file has the same name as the video file.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Garbled Chinese subtitles
    &lt;ul&gt;
      &lt;li&gt;Settings -&amp;gt; Player -&amp;gt; Language -&amp;gt; Subtitles: Change the language, font and the Character set.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Download subtitles automatically
    &lt;ul&gt;
      &lt;li&gt;Settings -&amp;gt; Player -&amp;gt; Language -&amp;gt; Download services: Use OpenSubtitles.org for both default services. Input your credentials for it.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;If weird things happened (e.g., no playback), you may wanna reset local database.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;M&lt;/code&gt; is the shortcut for subtitle menu, etc.&lt;/li&gt;
  &lt;li&gt;For Zidoo player, need to install ZDMC (a Kodi fork) for this setup. (&lt;a href=&quot;https://www.zidoo.tv/Support/release_apk.html&quot;&gt;apk download&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;zidoo&quot;&gt;Zidoo&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;While playing some videos (perhaps Dolby Vision/Atmos), I experienced some stutters every a few minutes. Found a solution on &lt;a href=&quot;http://forum.zidoo.tv/index.php?threads/z9x-smb-playback-issues-while-streaming-from-nas.84784/page-6&quot;&gt;zidoo forum&lt;/a&gt;:&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Settings -&amp;gt; advanced settings -&amp;gt; Realtek developer options&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;Switch “Playback with less reserved buffers” off.&lt;/li&gt;
      &lt;li&gt;Enable “performance mode”&lt;/li&gt;
      &lt;li&gt;Enable “playback performance mode”&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
    
      <item>
        <title>Read &quot;F1, a distributed SQL database that scales&quot;</title>
        <link>/2019/08/05/f1-paper.html</link>
        <guid isPermaLink="true">/2019/08/05/f1-paper.html</guid>
        <pubDate>Mon, 05 Aug 2019 00:00:00 +0000</pubDate>
        <description>&lt;h2 id=&quot;reference&quot;&gt;Reference&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/41344.pdf&quot;&gt;Link to paper&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;abstract&quot;&gt;Abstract&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Distributed relational database&lt;/li&gt;
  &lt;li&gt;Filial 1 hybrid, of
    &lt;ul&gt;
      &lt;li&gt;System community: high availability, scalability.&lt;/li&gt;
      &lt;li&gt;Database community: consistency and usability.
        &lt;ul&gt;
          &lt;li&gt;SQL query, automatic change tracking and publishing.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;On Spanner: synchronous replication and strong consistency.
    &lt;ul&gt;
      &lt;li&gt;Higher commit latency&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Mitigate high latency
    &lt;ul&gt;
      &lt;li&gt;Hierarchical schema model with structured types.&lt;/li&gt;
      &lt;li&gt;Smart application design.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Both OLTP and OLAP database for AdWords system.
    &lt;ul&gt;
      &lt;li&gt;Adwords as of 2013:
        &lt;ul&gt;
          &lt;li&gt;100s applications; 1,000s users&lt;/li&gt;
          &lt;li&gt;100TB data&lt;/li&gt;
          &lt;li&gt;~1M QPS&lt;/li&gt;
          &lt;li&gt;SQL queries scan O(10^13) rows per day.&lt;/li&gt;
          &lt;li&gt;Availability: 99.999%&lt;/li&gt;
          &lt;li&gt;Not higher latency compared with the old MySQL backend.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Some other applications use it as well.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Built to replace old MySQL backend.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key goals of F1’s design are as below. These goals are mutually exclusive, but F1 achieved them with trade-offs and sacrifices.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Scalability
    &lt;ul&gt;
      &lt;li&gt;Scale up trivially and transparently.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Availability
    &lt;ul&gt;
      &lt;li&gt;Must never go down for any reason.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Consistency
    &lt;ul&gt;
      &lt;li&gt;ACID transactions.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Usability
    &lt;ul&gt;
      &lt;li&gt;SQL query and other SQL features like indexes and ad hoc query.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;F1 inherits features from Spanner and adds more:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Distributed SQL queries&lt;/li&gt;
  &lt;li&gt;Transactionally consistent 2nd indexes&lt;/li&gt;
  &lt;li&gt;Asynchronous schema changes&lt;/li&gt;
  &lt;li&gt;Optimistic transactions&lt;/li&gt;
  &lt;li&gt;Automatic change recording and publishing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To hide the high latency brought by the design, some techniques are developed:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;F1 schema makes data clustering explicit.
    &lt;ul&gt;
      &lt;li&gt;Using hierarchical relationships and columns with structured data types.&lt;/li&gt;
      &lt;li&gt;Result: Improve data locality; reduce number of internal RPCs to read remote data.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;F1 users heavily use batching, parallelism and asynchronous reads.
    &lt;ul&gt;
      &lt;li&gt;A new ORM (object-relational mapping) library makes these explicit.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;basic-architecture&quot;&gt;Basic architecture&lt;/h2&gt;

&lt;p&gt;F1 architecture:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/system/f1/f1-arch.png&quot; alt=&quot;F1 architecture&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;F1 severs: receives clients’ read and write requests.
    &lt;ul&gt;
      &lt;li&gt;Load balancer may choose a server far away from clients in cases of high load or failures.&lt;/li&gt;
      &lt;li&gt;F1 servers usually co-locate with Spanner servers, but may contact other Spanner servers when necessary.&lt;/li&gt;
      &lt;li&gt;F1 servers are usually stateless, unless a pessimistic transaction is in process and server must hold locks.
        &lt;ul&gt;
          &lt;li&gt;A client can contact different servers for different requests.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Servers can be quickly added or removed and require no data movement.
        &lt;ul&gt;
          &lt;li&gt;Adding or removing Spanner servers requires data movement but the process is transparent to F1.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Slave pool: for distributed SQL queries.
    &lt;ul&gt;
      &lt;li&gt;Distributed execution is chosen when the query planner finds that increased parallelism will reduce latency.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;F1 master: manage the membership of slave pool.&lt;/li&gt;
  &lt;li&gt;Support MapReduce framework, talking to Spanner directly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this architecture, throughput can be scaled up by adding more Spanner servers, F1 servers or F1 slaves. Since the servers are widely distributed, the commit latencies are relatively high (50 - 150 ms).&lt;/p&gt;

&lt;h3 id=&quot;spanner&quot;&gt;Spanner&lt;/h3&gt;

&lt;p&gt;Check out this &lt;a href=&quot;/2019/07/06/spanner-paper.html&quot;&gt;note&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;data-model&quot;&gt;Data model&lt;/h2&gt;

&lt;h3 id=&quot;hierarchical-schema&quot;&gt;Hierarchical schema&lt;/h3&gt;

&lt;p&gt;Originally, Spanner used a Bigtable-like model; but later Spanner actually adopts the hierarchical logical data model of F1. (Directory table, child tables, etc) F1 schema supports explicit table hierarchy and columns with Protocol Buffer data types.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Child tables are clustered with and interleaved within the rows from its parent table.&lt;/li&gt;
  &lt;li&gt;Child and grand child table share the same primary key prefix with the root table row.&lt;/li&gt;
  &lt;li&gt;A root row in root table and its hierarchy form a Spanner directory.
    &lt;ul&gt;
      &lt;li&gt;In F1, make Customer (Advertiser) a root table.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Child rows are stored under their parent row ordered by primary key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hierarchy example:&lt;/p&gt;

&lt;div class=&quot;language-sql 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;n&quot;&gt;Customer&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Campaign&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Ads&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; 
    &lt;span class=&quot;n&quot;&gt;Ads&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Campaign&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interleaved&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doesn&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'t stay next to Campaign 1 1)
    Ads 1 2 1
Customer 2
  ...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Advantages:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Can fetch Campaign and Ads records (without knowing the Campaign ID) in parallel.&lt;/li&gt;
  &lt;li&gt;Use a single range read to get all Ads under a Customer.
    &lt;ul&gt;
      &lt;li&gt;Don’t need indexes.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Since records are ordered, can join two tables with a simple ordered merge.&lt;/li&gt;
  &lt;li&gt;Reduce the number of Spanner groups involved in a transaction.
    &lt;ul&gt;
      &lt;li&gt;Application developers should try to use single-root transaction as much as possible.
        &lt;ul&gt;
          &lt;li&gt;If must use multiple roots, we should limit the number of roots involved to reduce 2PC cost.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;protocol-buffers&quot;&gt;Protocol buffers&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Columns can be Protocol buffers, a structured data type.&lt;/li&gt;
  &lt;li&gt;Can use it across storage and code.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;repeated&lt;/code&gt; fields can be used to replace child tables.
    &lt;ul&gt;
      &lt;li&gt;Number of records in a such field is limited.&lt;/li&gt;
      &lt;li&gt;Reduce overhead and complexity to store and join child tables.&lt;/li&gt;
      &lt;li&gt;Easier for users to use the object as an atomic unit.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A single protobuf column or multiple columns?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Many tables consist of a single protobuf column.&lt;/li&gt;
  &lt;li&gt;Others has multiple columns.
    &lt;ul&gt;
      &lt;li&gt;Split by:
        &lt;ul&gt;
          &lt;li&gt;grouping fields usually accessed together.&lt;/li&gt;
          &lt;li&gt;static vs. frequently updated data.&lt;/li&gt;
          &lt;li&gt;different read/write permissions.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Allows concurrent updates to different columns.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Using fewer columns generally reduces performance overhead.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;indexing&quot;&gt;Indexing&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;All indexes are transactional and fully consistent.&lt;/li&gt;
  &lt;li&gt;Store: index key -&amp;gt; primary key of the indexed table.
    &lt;ul&gt;
      &lt;li&gt;Type:
        &lt;ul&gt;
          &lt;li&gt;Local
            &lt;ul&gt;
              &lt;li&gt;The index key contains the root row primary key as a prefix.&lt;/li&gt;
              &lt;li&gt;Stored in the same directory as the root row.&lt;/li&gt;
              &lt;li&gt;Updating cost is little.&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
          &lt;li&gt;Global
            &lt;ul&gt;
              &lt;li&gt;The index key doesn’t contain the root row primary key.&lt;/li&gt;
              &lt;li&gt;Updating is often large and rate is high.
                &lt;ul&gt;
                  &lt;li&gt;Thus sharded into many directories.&lt;/li&gt;
                &lt;/ul&gt;
              &lt;/li&gt;
              &lt;li&gt;Use it sparingly due to its cost and try to use small transaction if must do it.&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;schema-changes&quot;&gt;Schema changes&lt;/h2&gt;

&lt;p&gt;AdWords system requires F1 to be highly available; schema changes should not lead to downtime or table locking.&lt;/p&gt;

&lt;p&gt;Challenges:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Servers distributed in multiple geographic regions.&lt;/li&gt;
  &lt;li&gt;F1 servers have schema loaded in memory; not practical to update atomically across all servers.&lt;/li&gt;
  &lt;li&gt;Queries and transactions must continue on all tables even with ongoing schema changes.&lt;/li&gt;
  &lt;li&gt;Schema changes should not impact availability and latency.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;F1 chooses to do schema changes asynchronously. Servers may update the database using different schema. Note: Why not using Spanner style? Assign a future timestamp to the change. Maybe because it will block some transactions requiring the new change.&lt;/p&gt;

&lt;p&gt;Problem: If two F1 servers update the database with different schemas (not compatible), it will lead to anomalies like data corruption.&lt;/p&gt;

&lt;p&gt;Example of data corruption: A schema change from schema S1 to S2, adding a new index I on table T.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Server M1 uses S1; M2 uses S2.&lt;/li&gt;
  &lt;li&gt;M2 inserts a new row r, and adding index Ir.&lt;/li&gt;
  &lt;li&gt;M1 deletes row r, leaving index Ir alone since it is not aware of it.&lt;/li&gt;
  &lt;li&gt;Index scan on I will return spurious data on r.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Algorithm to prevent such anomalies:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Enforce that at most two schemas are active across all servers.&lt;/li&gt;
  &lt;li&gt;Subdividing each schema change into multiple phases where consecutive ones are mutually compatible and cannot cause anomalies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The example can be divided as:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Add index I and only allows delete operations on it.&lt;/li&gt;
  &lt;li&gt;Upgrade I to allow write operations on it.&lt;/li&gt;
  &lt;li&gt;Perform Offline job to backfill index entries to all rows.
    &lt;ul&gt;
      &lt;li&gt;Need to carefully handle concurrent writes.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Once completed, make I visible to all read operations.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Full details are in this paper (&lt;a href=&quot;https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/41376.pdf&quot;&gt;Online, asynchronous schema change in F1&lt;/a&gt;).&lt;/p&gt;

&lt;h2 id=&quot;transactions&quot;&gt;Transactions&lt;/h2&gt;

&lt;p&gt;F1 must provide ACID transaction feature. In contrast, eventual consistent systems add a lot of burden on application developers. We should support full transactional consistency at database level.&lt;/p&gt;

&lt;p&gt;3 types of F1 transactions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Snapshot transaction
    &lt;ul&gt;
      &lt;li&gt;Read-only&lt;/li&gt;
      &lt;li&gt;Use Spanner snapshot timestamp.&lt;/li&gt;
      &lt;li&gt;Default current (when timestamp is not provided)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Pessimistic transaction
    &lt;ul&gt;
      &lt;li&gt;Map to Spanner transactions,&lt;/li&gt;
      &lt;li&gt;Can use shared or exclusive locks.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Optimistic transaction
    &lt;ul&gt;
      &lt;li&gt;Use last modification timestamp (LMT) on each row, stored in a hidden lock column.
        &lt;ul&gt;
          &lt;li&gt;Updated in every F1 writes.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Check the LMT of all already read rows while trying to commit.&lt;/li&gt;
      &lt;li&gt;Default in F1.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Advantages of optimistic transactions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Tolerate misbehaved clients since not holding locks.&lt;/li&gt;
  &lt;li&gt;Support long-lasting transactions, e.g., with user interactions.&lt;/li&gt;
  &lt;li&gt;Easy to retry transparently on server-side.&lt;/li&gt;
  &lt;li&gt;Client can retry on different F1 servers since optimistic transactions are server-stateless.
    &lt;ul&gt;
      &lt;li&gt;When servers failed or needs load balancing.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Speculative writes.
    &lt;ul&gt;
      &lt;li&gt;Read values from outside; also requires their LMT.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Disadvantages of optimistic transactions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Insertion phantoms
    &lt;ul&gt;
      &lt;li&gt;LMT only exists on existing rows.&lt;/li&gt;
      &lt;li&gt;Can use parent-table locks to avoid this.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Low throughput under high contention
    &lt;ul&gt;
      &lt;li&gt;When many clients update concurrently.&lt;/li&gt;
      &lt;li&gt;Use pessimistic ones or do batching updates.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;flexible-locking-granularity&quot;&gt;Flexible locking granularity&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Row-level locking by default.&lt;/li&gt;
  &lt;li&gt;Support column-level locking per row.
    &lt;ul&gt;
      &lt;li&gt;Can update different columns on one row concurrently.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Can also selectively reduce concurrency.
    &lt;ul&gt;
      &lt;li&gt;Use a lock column in a parent table to cover columns in a child table.
        &lt;ul&gt;
          &lt;li&gt;Avoid insertion phantoms.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;change-history&quot;&gt;Change history&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Change history is a first-class feature and guaranteed full coverage.&lt;/li&gt;
  &lt;li&gt;Enabled by default, but can opt out some tables or columns.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Every transaction creates one or more &lt;code class=&quot;highlighter-rouge&quot;&gt;ChangeBatch&lt;/code&gt; protobuf.
    &lt;ul&gt;
      &lt;li&gt;Primary key is the root table key + transaction commit timestamp.
        &lt;ul&gt;
          &lt;li&gt;Thus is a child table of the root row, stored in commit order.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Stores the before and after values for each updated row.&lt;/li&gt;
      &lt;li&gt;If multiple root rows are involved, create the protobuf for each root row.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Applications:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;For pubsub.&lt;/li&gt;
  &lt;li&gt;For cache.
    &lt;ul&gt;
      &lt;li&gt;If cache is stale, do incremental updating starting from the checkpoint using change history.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;client-design&quot;&gt;Client design&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Simplified ORM
    &lt;ul&gt;
      &lt;li&gt;Expose APIs for parallel and asynchronous read access.&lt;/li&gt;
      &lt;li&gt;Avoid anti-patterns:
        &lt;ul&gt;
          &lt;li&gt;Serial reads, implicit traversals etc.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;NoSQL interface
    &lt;ul&gt;
      &lt;li&gt;A simple KV based interface for reads/writes.&lt;/li&gt;
      &lt;li&gt;Can batch retrieval of rows from multiple tables in a single call.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;SQL interface
    &lt;ul&gt;
      &lt;li&gt;Supports from low-latency OLTP to large OLAP.&lt;/li&gt;
      &lt;li&gt;Can join data from outside sources, like Bigtable, CSV files, etc.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;query-processing&quot;&gt;Query processing&lt;/h2&gt;

&lt;p&gt;Some key properties of the query processing system:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Queries are executed as either low-latency centrally executed ones or distributed ones with high parallelism.
    &lt;ul&gt;
      &lt;li&gt;Centrally executed queries: OLTP-style.&lt;/li&gt;
      &lt;li&gt;Distributed queries: OLAP-style.
        &lt;ul&gt;
          &lt;li&gt;Use snapshot transactions (read-only).&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Data is remote and batching is used heavily to mitigate network latency.
    &lt;ul&gt;
      &lt;li&gt;Example: Lookup join
        &lt;ul&gt;
          &lt;li&gt;Load 50MB data from one table then lookup in the other table.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;All input and internal data is arbitrarily partitioned and has &lt;strong&gt;few&lt;/strong&gt; ordering properties.&lt;/li&gt;
  &lt;li&gt;Many hash-based repartitioning steps.&lt;/li&gt;
  &lt;li&gt;Individual query plan operators are designed to stream data to later operators as soon as possible.
    &lt;ul&gt;
      &lt;li&gt;Reduce pipeline stalls.&lt;/li&gt;
      &lt;li&gt;This decision limits operators’ ability to preserve interesting data orders.&lt;/li&gt;
      &lt;li&gt;Maximize pipelining, read request concurrency.&lt;/li&gt;
      &lt;li&gt;Reduce memory usage for buffering temporary data.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Optimized access on hierarchically clustered tables.&lt;/li&gt;
  &lt;li&gt;Query data can be consumed in parallel.&lt;/li&gt;
  &lt;li&gt;First-class support for structured data types, by protobuf-type columns.&lt;/li&gt;
  &lt;li&gt;Snapshot consistency provided by Spanner.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;distributed-query-example&quot;&gt;Distributed query example&lt;/h3&gt;

&lt;div class=&quot;language-sql 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;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;agcr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CampaignId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Region&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;cr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Language&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SUM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Clicks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AdClick&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;click&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;JOIN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AdGroupCreative&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;agcr&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;USING&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AdGroupId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CreativeId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;JOIN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Creative&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cr&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;USING&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CustomerId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CreativeId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'2013-03-23'&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;GROUP&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;agcr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CampaignId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Region&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;cr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Language&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;AdGroup&lt;/code&gt;: a collection of ads with some shared configuration.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;Creative&lt;/code&gt;: actual ad text.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;AdGroupCreative&lt;/code&gt;: a table of foreign keys linking &lt;code class=&quot;highlighter-rouge&quot;&gt;AdGroup&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;Creative&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;AdClick&lt;/code&gt;: records the &lt;code class=&quot;highlighter-rouge&quot;&gt;AdGroup&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;Creative&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A possible query plan:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/system/f1/query-plan.png&quot; alt=&quot;Query plan&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Scan &lt;code class=&quot;highlighter-rouge&quot;&gt;AdClick&lt;/code&gt; into a &lt;code class=&quot;highlighter-rouge&quot;&gt;lookup join&lt;/code&gt; operator and do the join.
    &lt;ul&gt;
      &lt;li&gt;The operator looks up &lt;code class=&quot;highlighter-rouge&quot;&gt;AdGroupCreative&lt;/code&gt; using secondary index key.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Repartition data stream by hashing with &lt;code class=&quot;highlighter-rouge&quot;&gt;CustomerId&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;CreativeId&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Distributed hash join with &lt;code class=&quot;highlighter-rouge&quot;&gt;Creative&lt;/code&gt; using the same keys.&lt;/li&gt;
  &lt;li&gt;Repartition again by hashing with &lt;code class=&quot;highlighter-rouge&quot;&gt;GROUP BY&lt;/code&gt; keys (&lt;code class=&quot;highlighter-rouge&quot;&gt;CampaignId&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;Region&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;Language&lt;/code&gt;).&lt;/li&gt;
  &lt;li&gt;Aggregate using aggregation operator.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;distributed-execution-overview&quot;&gt;Distributed execution overview&lt;/h3&gt;

&lt;p&gt;A distributed query plan may consist of tens of plan parts, forming a directed acyclic graph. The data flows up from the leaves to a single root node (query coordinator). Query coordinator is the server which received the initial request; it plans the execution and processes results to return to the client.&lt;/p&gt;

&lt;p&gt;Co-partitioning of the stored data is helpful to push down large amount of query processing to nodes hosting the partitions. F1 cannot utilize this since all data are remote and Spanner does random partitioning. To allow efficient processing, F1 re-partitions data (hash partition). It requires heavy network traffic and hence limits the size of F1 cluster due to the network switch hardware. However, both are not causing problems.&lt;/p&gt;

&lt;p&gt;F1 operators execute in memory without checkpointing, stream results as much as possible. Therefore, a single server failure will fail entire query.&lt;/p&gt;

&lt;h3 id=&quot;hierarchical-table-joins&quot;&gt;Hierarchical table joins&lt;/h3&gt;

&lt;p&gt;Child table entries are interleaved in the parent table; thus a single Spanner request can work to join a parent table with its child table. Cluster join (like merge join) is efficient, which buffers one parent entry and one child entry.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Parent(3)
  Child1(3, 1)
  Child1(3, 2)
Parent(4)
  Child1(4, 1)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However, a single Spanner request doesn’t work to join two sibling child tables. (Note: How are sibling child tables interleaved in parent table?) Need to perform one cluster join first (Parent, Child1), then another join (join1 result, Child2? What primary key to use? parent root key?).&lt;/p&gt;

&lt;h3 id=&quot;partitioned-customers&quot;&gt;Partitioned customers&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;A single query coordinator or a single client process may be a bottleneck.
    &lt;ul&gt;
      &lt;li&gt;It may receive results from many servers in parallel.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Clients can ask F1 for distributed data retrieval.
    &lt;ul&gt;
      &lt;li&gt;F1 returns a set of endpoints to connect to.&lt;/li&gt;
      &lt;li&gt;A slow reader may block entire processing.
        &lt;ul&gt;
          &lt;li&gt;F1 processes results for all readers in lock-step.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;queries-with-protobuf&quot;&gt;Queries with protobuf&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;protobuf can be used in F1 SQL path expressions like &lt;code class=&quot;highlighter-rouge&quot;&gt;WHERE c.Info.country_code = 'US'&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;F1 can query and pass entire protobuf like &lt;code class=&quot;highlighter-rouge&quot;&gt;SELECT c.Info&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Can access repeated fields with implicit join &lt;code class=&quot;highlighter-rouge&quot;&gt;PROTO JOIN&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Disadvantages:
    &lt;ul&gt;
      &lt;li&gt;Performance implications due to fetching and parsing entire protobuf, even if we only need one field.
        &lt;ul&gt;
          &lt;li&gt;Can improve by pushing the parsing and field selection to Spanner.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;deployment&quot;&gt;Deployment&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;5 datacenters across mainland US.
    &lt;ul&gt;
      &lt;li&gt;5-way Paxos replication.
        &lt;ul&gt;
          &lt;li&gt;3-way is not enough: If one failed, a single machine failure may fail the second one then the system is unavailable.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Additional read-only replicas for snapshot reads.&lt;/li&gt;
  &lt;li&gt;Put clients with heavy modifications near leaders.
    &lt;ul&gt;
      &lt;li&gt;User transactions require at least 2 round trips to the leader.
        &lt;ul&gt;
          &lt;li&gt;One for read, one for commit.&lt;/li&gt;
          &lt;li&gt;Maybe another read as part of a transaction commit.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;2 at east coast; 2 at west coast; 1 centrally.
    &lt;ul&gt;
      &lt;li&gt;Leader at east cost.
        &lt;ul&gt;
          &lt;li&gt;Round trip to the other datacenter at east cost and central one accounts for 50 ms minimum latency.
            &lt;ul&gt;
              &lt;li&gt;Paxos voting process is improved since majority 3/5 is required.&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;latency-and-throughput&quot;&gt;Latency and throughput&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Read latencies: 5-10 ms.&lt;/li&gt;
  &lt;li&gt;Commit latencies: 50-150 ms.&lt;/li&gt;
  &lt;li&gt;Multi-group transaction latencies: 100-300 ms since requiring 2PC.&lt;/li&gt;
  &lt;li&gt;User-facing latencies for AdWords interactive application: 200 ms.
    &lt;ul&gt;
      &lt;li&gt;Achieved much by avoiding serial reads.&lt;/li&gt;
      &lt;li&gt;Tail latencies are much better than MySQL.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Non-interactive bulk updates:
    &lt;ul&gt;
      &lt;li&gt;Optimize for throughput instead of latency.&lt;/li&gt;
      &lt;li&gt;Do small transactions (only one directory involved) in parallel.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Query processing can be speeded up linearly with more resources.&lt;/li&gt;
  &lt;li&gt;Resource cost: CPU 1 order higher than MySQL
    &lt;ul&gt;
      &lt;li&gt;Need to decompress disk data, process then recompress and send over the network.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;related-work&quot;&gt;Related work&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Hybrid of relational and NoSQL.&lt;/li&gt;
  &lt;li&gt;Optimistic transactions.&lt;/li&gt;
  &lt;li&gt;Asynchrony in query processing.&lt;/li&gt;
  &lt;li&gt;MDCC (Multi-datacenter consistency) Paxos optimizations.&lt;/li&gt;
  &lt;li&gt;Protocol Buffers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Highly scalable, available.&lt;/li&gt;
  &lt;li&gt;High throughput.&lt;/li&gt;
  &lt;li&gt;ACID transactional guarantee.&lt;/li&gt;
  &lt;li&gt;SQL query.&lt;/li&gt;
  &lt;li&gt;Rich column types (protobuf).&lt;/li&gt;
&lt;/ul&gt;

</description>
      </item>
    
      <item>
        <title>Read &quot;Zanzibar, Google’s Consistent, Global Authorization System&quot;</title>
        <link>/2019/07/28/zanzibar-paper.html</link>
        <guid isPermaLink="true">/2019/07/28/zanzibar-paper.html</guid>
        <pubDate>Sun, 28 Jul 2019 00:00:00 +0000</pubDate>
        <description>&lt;h2 id=&quot;reference&quot;&gt;Reference&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.usenix.org/conference/atc19/presentation/pang&quot;&gt;Link to paper, slides&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;abstract&quot;&gt;Abstract&lt;/h2&gt;

&lt;p&gt;Zanzibar is a consistent, global authorization systems used by Google Calendar, Cloud, Drive, Maps, Photos and Youtube. It scales to billions of users, trillions of ACLs (access control list) and millions of QPS. It maintains 95th latency of less than 10 milliseconds and 5-9s availability over 3 years of production use.&lt;/p&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;Zanzibar is a unified system that allows inter-application usages.&lt;/p&gt;

&lt;p&gt;Goals for Zanzibar:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Correctness
    &lt;ul&gt;
      &lt;li&gt;Consistency&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Flexibility
    &lt;ul&gt;
      &lt;li&gt;Support a rich set of access control policies.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Low latency&lt;/li&gt;
  &lt;li&gt;High availability&lt;/li&gt;
  &lt;li&gt;Large scale&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Zanzibar features:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A simple data model and a powerful configuration language
    &lt;ul&gt;
      &lt;li&gt;User can define arbitrary relations between users and objects, like owner.&lt;/li&gt;
      &lt;li&gt;Support set-algebraic operators such as intersection and union.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;ACL: user U has relation R to object O.
    &lt;ul&gt;
      &lt;li&gt;U can also be a user group, referring to another ACL.
        &lt;ul&gt;
          &lt;li&gt;Commenter is also viewer.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;User group can contains other user groups. Nested groups may lead to long chain for ACL checks.&lt;/li&gt;
      &lt;li&gt;An ACL check request may fan out to multiple servers.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;All ACLs are globally replicated to server large QPS quickly.&lt;/li&gt;
  &lt;li&gt;Global consistency enabled by Spanner.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For low latency and high availability:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Its consistency protocol allows the vast majority of requests to be served with locally replicated data, without requiring cross-region round trips.&lt;/li&gt;
  &lt;li&gt;Handle hot spots by caching final and intermediate results, deduping simultaneous requests.&lt;/li&gt;
  &lt;li&gt;Handle deeply nested sets by hedging request and optimizing computations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;model-language-and-api&quot;&gt;Model, language and API&lt;/h2&gt;

&lt;h3 id=&quot;relation-tuples&quot;&gt;Relation tuples&lt;/h3&gt;

&lt;p&gt;In Zanzibar, ACLs are represented as relation tuples.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;(tuple) ::= (object)#(relation)@(user)&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;(object) ::= (namespace):(object_id)&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;(user) ::= (user_id)|(userset)&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;(userset) ::= (object)#(relation)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;(userset)&lt;/code&gt; allows us to refer a group to support nested group membership.&lt;/p&gt;

&lt;p&gt;Examples of tuples:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;doc:readme#owner@10&lt;/li&gt;
  &lt;li&gt;group:eng#member@11&lt;/li&gt;
  &lt;li&gt;doc:readme#viewer@group:eng#member
    &lt;ul&gt;
      &lt;li&gt;Group eng’s members are viewers of readme.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;consistency-model&quot;&gt;Consistency model&lt;/h3&gt;

&lt;p&gt;“new enemy problem”, considering a scenario:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Alice removes Bob from the ACL of a folder.&lt;/li&gt;
  &lt;li&gt;Alice adds a new content into the folder.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Problems:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Fail to preserve ordering of ACL changes.
    &lt;ul&gt;
      &lt;li&gt;Wrong order will let Bob see the new content.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Misapply old ACL to new content.
    &lt;ul&gt;
      &lt;li&gt;If ACL check is evaluated on the old ACL, Bob will see the content.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Features Zanzibar provided to avoid such problems are as below. Both are enabled by Spanner (&lt;a href=&quot;/2019/07/06/spanner-paper.html&quot;&gt;my note&lt;/a&gt;).&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;External consistency
    &lt;ul&gt;
      &lt;li&gt;Ensure casual ordering.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Snapshot reads with bounded staleness
    &lt;ul&gt;
      &lt;li&gt;Won’t see stale results.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Zookie:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Zanzibar zookies are basically Spanner timestamp assigned to the ACL update.&lt;/li&gt;
  &lt;li&gt;Write path
    &lt;ul&gt;
      &lt;li&gt;When the content modification is about to be saved, the client requests a zookie for each content version.
        &lt;ul&gt;
          &lt;li&gt;Via a content-change ACL check.
            &lt;ul&gt;
              &lt;li&gt;Does not need to be in the same transaction as the content change. (Note: Why?)&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;The client stores the content change and the zookie in an atomic write.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Check path
    &lt;ul&gt;
      &lt;li&gt;The client sends this zookie in subsequent ACL check requests to get fresh results compared with the update.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Advantages of using zookies:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Most of checks use default staleness with already replicated data.
    &lt;ul&gt;
      &lt;li&gt;Low latency.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Free to choose even fresher snapshot.
    &lt;ul&gt;
      &lt;li&gt;To avoid hot spots.&lt;/li&gt;
      &lt;li&gt;High availability.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;namespace-configuration&quot;&gt;Namespace configuration&lt;/h3&gt;

&lt;p&gt;Namespace configuration specifies:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Relations
    &lt;ul&gt;
      &lt;li&gt;e.g., viewer, editor&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Storage parameters
    &lt;ul&gt;
      &lt;li&gt;Sharding setting&lt;/li&gt;
      &lt;li&gt;Encoding for object ID like string, integer.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;relation-configs-and-user-rewrites&quot;&gt;Relation configs and user rewrites&lt;/h4&gt;

&lt;p&gt;Clients can define object-agnostic relationships via userset rewrite rules in relation configs. The userset rewrite rules are defined per relation. It can be used to express this relation with other relations. The expressions can be union, intersection and exclusion.&lt;/p&gt;

&lt;p&gt;The userset rewrite rule specifies a function with an object ID as input and a userset expression tree as output. The leaf nodes of the tree can be:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;_this&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;All users from tuples for &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;object#relation&amp;gt;&lt;/code&gt; pair.&lt;/li&gt;
      &lt;li&gt;Including indirect ACLs by usersets from tuples.&lt;/li&gt;
      &lt;li&gt;Default when no rules specified.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;computed_userset&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Compute a new userset for the input object.&lt;/li&gt;
      &lt;li&gt;e.g., viewer relation can refer to editor relation.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;tuple_to_userset&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Compute a tupleset from the input object; fetch relation tuples matching the tupleset; then compute a userset from every fetched relation tuple.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An example of relation config, expressing that viewer contains editor and viewer from parent folder; editor contains owner.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;name: &quot;doc&quot;

relation { name: &quot;owner&quot; }

relation {
 name: &quot;editor&quot;
 userset_rewrite {
  union {
   child { _this {} }
   child { computed_userset { relation: &quot;owner&quot; } }
}}}

relation {
 name: &quot;viewer&quot;
 userset_rewrite {
  union {
   child { _this {} }
   child { computed_userset { relation: &quot;editor&quot; } }
   child { tuple_to_userset {
     tupleset { relation: &quot;parent&quot; }
     computed_userset {
       object: $TUPLE_USERSET_OBJECT  # parent folder
       relation: &quot;viewer&quot; 
    }}}
}}}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;api&quot;&gt;API&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Read
    &lt;ul&gt;
      &lt;li&gt;A request specifies one or more tuplesets and zookie.&lt;/li&gt;
      &lt;li&gt;tupleset:
        &lt;ul&gt;
          &lt;li&gt;A single tuple key or all tuples with a a given object ID or userset in a namespace.&lt;/li&gt;
          &lt;li&gt;Can be optionally constrained by a relation name.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Response
        &lt;ul&gt;
          &lt;li&gt;look up a specific membership entry;&lt;/li&gt;
          &lt;li&gt;read all entries in an ACL or group;&lt;/li&gt;
          &lt;li&gt;read all groups with a given user.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Note Read doesn’t reflect userset rewrite rules, thus only retrieve direct users or objects.
        &lt;ul&gt;
          &lt;li&gt;Use Expand to get effective ACLs.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Write
    &lt;ul&gt;
      &lt;li&gt;Can modify single relation tuple.&lt;/li&gt;
      &lt;li&gt;Can also modify all tuples related to an object via a read-modify-write cycle.
        &lt;ul&gt;
          &lt;li&gt;Steps:
            &lt;ol&gt;
              &lt;li&gt;Read all relation tuples of an object, including a per-object lock tuple.&lt;/li&gt;
              &lt;li&gt;Generate tuples to write or delete. Send the writes along with the lock tuple.&lt;/li&gt;
              &lt;li&gt;If the lock tuple is not modified, commit. Otherwise, back to step 1.&lt;/li&gt;
            &lt;/ol&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;A write issues a content-change check against the latest snapshot.
        &lt;ul&gt;
          &lt;li&gt;If authorized, Check will response with a zookie, to be sent back in the write response to the client.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Watch
    &lt;ul&gt;
      &lt;li&gt;Request: one or more namespaces, zookie representing the time starting to watch.&lt;/li&gt;
      &lt;li&gt;Response: all tuple modification events in time order and a heartbeat zookie (representing the end time).&lt;/li&gt;
      &lt;li&gt;Clients can use the heartbeat zookie to send a new request to resume watching.&lt;/li&gt;
      &lt;li&gt;Can be used to maintain secondary indexes on client side.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Check
    &lt;ul&gt;
      &lt;li&gt;Request: a userset &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;object#relation&amp;gt;&lt;/code&gt;, a putative user and optional zookie.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Expand
    &lt;ul&gt;
      &lt;li&gt;Get the effective userset given an &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;object#relation&amp;gt;&lt;/code&gt; pair and an optional zookie.&lt;/li&gt;
      &lt;li&gt;Follow indirect references expressed through userset rewrite rules.&lt;/li&gt;
      &lt;li&gt;Result: a userset tree
        &lt;ul&gt;
          &lt;li&gt;Leaf nodes: user IDs or usersets pointing to other &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;object#relation&amp;gt;&lt;/code&gt; pairs.&lt;/li&gt;
          &lt;li&gt;Intermediate nodes: expressions like union, intersection or exclusion.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;architecture-and-implementation&quot;&gt;Architecture and implementation&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/system/zanzibar/zanzibar-arch.png&quot; alt=&quot;Zanzibar architecture&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;aclservers
    &lt;ul&gt;
      &lt;li&gt;Serve Check, Read, Expand, Write requests.&lt;/li&gt;
      &lt;li&gt;Organized in clusters.&lt;/li&gt;
      &lt;li&gt;The initial server may fan out work to other servers; other server may contact another server as well.&lt;/li&gt;
      &lt;li&gt;The initial server gathers final result and sends it back to the client.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Storage
    &lt;ul&gt;
      &lt;li&gt;ACLs and metadata are stored in Spanner.&lt;/li&gt;
      &lt;li&gt;One database per namespace.&lt;/li&gt;
      &lt;li&gt;One database stores all namespace configurations.&lt;/li&gt;
      &lt;li&gt;One changelog database shared across all namespaces.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;watchservers
    &lt;ul&gt;
      &lt;li&gt;Serve Watch requests.&lt;/li&gt;
      &lt;li&gt;Tail the changelog and serve a stream of changes.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Offline pipelines
    &lt;ul&gt;
      &lt;li&gt;e.g., dumps, garbage collection on old versions.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Leopard indexing system
    &lt;ul&gt;
      &lt;li&gt;Used to optimize operations on large and deeply nested sets.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;storage&quot;&gt;Storage&lt;/h3&gt;

&lt;p&gt;Relation tuple storage:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;One database per namespace.&lt;/li&gt;
  &lt;li&gt;Primary key to identify a row:
    &lt;ul&gt;
      &lt;li&gt;shard ID, object ID, relation, user, commit timestamp.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Shard ID
    &lt;ul&gt;
      &lt;li&gt;Usually determined by object ID solely.
        &lt;ul&gt;
          &lt;li&gt;If a namespace stores groups with very large numbers of members, shard ID can be computed from object ID and user.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Changelog:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Primary key:
    &lt;ul&gt;
      &lt;li&gt;changelog shard ID, timestamp, unique update ID.&lt;/li&gt;
      &lt;li&gt;Shard is randomly selected for each write.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Relation tuple and changelog are both updated in a single transaction.&lt;/li&gt;
  &lt;li&gt;Use the Spanner server hosting changelog shard as the transaction manager.
    &lt;ul&gt;
      &lt;li&gt;To minimize blocking of changelog reads on pending transactions.
        &lt;ul&gt;
          &lt;li&gt;Note: Save the time for sending commit timestamp to non-coordinator participant leaders in 2PC.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Namespace config storage:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Two tables:
    &lt;ul&gt;
      &lt;li&gt;One stores the configs keyed by namespace IDs.&lt;/li&gt;
      &lt;li&gt;The other is a changelog of config updates, keyed by commit timestamps.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Zanzibar servers can load all configs upon startup and monitor the changelog to refresh configs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Replication:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Data is replicated to be close to clients.
    &lt;ul&gt;
      &lt;li&gt;Dozens of locations around the world.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;5 voting replicas in eastern and central US.
    &lt;ul&gt;
      &lt;li&gt;in 3 metropolitan areas to isolate failures;&lt;/li&gt;
      &lt;li&gt;within 25 ms of each other to allow Paxos transactions commit quickly.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;serving&quot;&gt;Serving&lt;/h3&gt;

&lt;h4 id=&quot;evaluation-timestamp&quot;&gt;Evaluation timestamp&lt;/h4&gt;

&lt;p&gt;Zanzibar always respects zookie if provided. Zanzibar also does statistics on out-of-zone reads probability. Default staleness bound will be updated to a safe value according to the result. Use default staleness for requests without zookies. The signal of whether it’s out-of-zone is sent back by Spanner.&lt;/p&gt;

&lt;h4 id=&quot;config-consistency&quot;&gt;Config consistency&lt;/h4&gt;

&lt;p&gt;Zanzibar chooses a single timestamp for the config to evaluate the same request on all servers. This timestamp is chosen from a range in which all timestamps are available to all servers.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;This range is maintained by a monitoring job.&lt;/li&gt;
  &lt;li&gt;Each server load config changes continuously.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;check-evaluation&quot;&gt;Check evaluation&lt;/h4&gt;

&lt;p&gt;Zanzibar converts check requests to boolean expressions. A simple example without userset rewrite rules:&lt;br /&gt;
&lt;script type=&quot;math/tex&quot;&gt;\\&lt;/script&gt;&lt;br /&gt;
&lt;script type=&quot;math/tex&quot;&gt;% &lt;![CDATA[
CHECK(U, &lt;object\#relation&gt;) = \\ \hspace{2cm} \exists tuple &lt;object\#relation@U&gt; \\ \hspace{1.9cm} \vee \exists tuple &lt;object\#relation@U'&gt;,  where \\ \hspace{4cm} U' = &lt;object'\#relation'&gt;  s.t.  CHECK(U, U') %]]&gt;&lt;/script&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A check request fans out on all indirect ACLs or groups, recursively.
    &lt;ul&gt;
      &lt;li&gt;Deep or write ACLs cases are optimized by Leopard indexing system.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;All leaf nodes of the boolean expression tree are evaluated concurrently.
    &lt;ul&gt;
      &lt;li&gt;Eager cancellation: If the outcome of one node determines the result of a subtree, evaluations on other nodes are cancelled.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Use pooling mechanism to group reads for the same ACL check to reduce the number of RPCs to Spanner.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;leopard-indexing-system&quot;&gt;Leopard indexing system&lt;/h4&gt;

&lt;p&gt;For namespaces with deeply nested groups or large number of child groups, they can be selected to use Leopard indexing system to reduce latency of checks. The idea is to flatten the group to group paths. A query to Leopard system is an expression of UNION, INTERSECTION or EXCLUSION of named sets (indexing tuples). Response is a set ordered by element ID up to a specified number of results.&lt;/p&gt;

&lt;p&gt;An indexing tuple &lt;code class=&quot;highlighter-rouge&quot;&gt;(T, s, e)&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;T&lt;/code&gt;: the set type.
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;GROUP2GROUP(s) -&amp;gt; {e}&lt;/code&gt;: For a group &lt;code class=&quot;highlighter-rouge&quot;&gt;s&lt;/code&gt;, return all directly or indirectly descendant groups &lt;code class=&quot;highlighter-rouge&quot;&gt;{e}&lt;/code&gt;.&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;MEMBER2GROUP(s) -&amp;gt; {e}&lt;/code&gt;: For a user &lt;code class=&quot;highlighter-rouge&quot;&gt;s&lt;/code&gt;, return all direct parent groups &lt;code class=&quot;highlighter-rouge&quot;&gt;{e}&lt;/code&gt;.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;s&lt;/code&gt;: set ID.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;e&lt;/code&gt; 64-bit element ID.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below is the check of user &lt;script type=&quot;math/tex&quot;&gt;U&lt;/script&gt; on group &lt;script type=&quot;math/tex&quot;&gt;G&lt;/script&gt;. &lt;br /&gt;
&lt;script type=&quot;math/tex&quot;&gt;\\&lt;/script&gt;&lt;br /&gt;
&lt;script type=&quot;math/tex&quot;&gt;MEMBER2GROUP(U) \cap GROUP2GROUP(G) \neq \emptyset&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;3 parts of Leopard system:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A serving system for consistent and low-latency operations across sets
    &lt;ul&gt;
      &lt;li&gt;Tuples are stored like a skip list, to perform operations (UNION, INTERSECTION) in &lt;script type=&quot;math/tex&quot;&gt;O(\min(\vert A \vert, \vert B \vert))&lt;/script&gt;.&lt;/li&gt;
      &lt;li&gt;Index is sharded by element IDs.
        &lt;ul&gt;
          &lt;li&gt;Note: Why? This way elements in the same set don’t stay together like a list.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;An offline periodic index building system
    &lt;ul&gt;
      &lt;li&gt;Generate index shards from a snapshot of relation tuples and configs; and replicate.&lt;/li&gt;
      &lt;li&gt;Respect the userset rewrite rules.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;An online layer for continuously updating the serving system as tuple changes occur
    &lt;ul&gt;
      &lt;li&gt;Incrementally update indexes since the offline snapshot.&lt;/li&gt;
      &lt;li&gt;An update is &lt;code class=&quot;highlighter-rouge&quot;&gt;(T, s, e, t, d)&lt;/code&gt;.
        &lt;ul&gt;
          &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;t&lt;/code&gt; is the timestamp of update.&lt;/li&gt;
          &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;d&lt;/code&gt; is deletion maker.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Implementation
        &lt;ul&gt;
          &lt;li&gt;Rely on Zanzibar Watch API.&lt;/li&gt;
          &lt;li&gt;A relation tuple update may trigger tens of thousands Leopard tuple events.&lt;/li&gt;
          &lt;li&gt;Every Leopard server receives the Watch update stream and do the update with minimal impact on serving.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;handling-hot-spots&quot;&gt;Handling hot spots&lt;/h4&gt;

&lt;p&gt;ACL reads and checks often lead to hot spots. 4 improvements:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Distributed cache
    &lt;ul&gt;
      &lt;li&gt;Distributed in a cluster of servers with consistent hashing.
        &lt;ul&gt;
          &lt;li&gt;Compute forwarding key with object ID.
            &lt;ul&gt;
              &lt;li&gt;Because a check on &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;object#relation&amp;gt;&lt;/code&gt; often involves checks on other relation of the same object. These can be processed on the same server to save number of internal RPCs.&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Both caller and callee of the internal RPCs cache the results.&lt;/li&gt;
      &lt;li&gt;Encode snapshot timestamp in cache key.
        &lt;ul&gt;
          &lt;li&gt;Avoid using caches of old snapshots.&lt;/li&gt;
          &lt;li&gt;Round up timestamps from the zookie.
            &lt;ul&gt;
              &lt;li&gt;Ensure freshness.&lt;/li&gt;
              &lt;li&gt;Most checks can share cached result at the same timestamp.&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Lock table
    &lt;ul&gt;
      &lt;li&gt;To handle “cache stampede” problem.
        &lt;ul&gt;
          &lt;li&gt;Concurrent requests create flash hot spots before the cache is populated with results.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;When receive concurrent requests of the same cache key, process one and block others until cache is ready.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Cache all relation tuples for hot check targets.
    &lt;ul&gt;
      &lt;li&gt;Many users may issue current requests on the same &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;object#relation&amp;gt;&lt;/code&gt; pair.&lt;/li&gt;
      &lt;li&gt;Cache all relation tuples for the pair.&lt;/li&gt;
      &lt;li&gt;Trade read bandwidth for cacheability.&lt;/li&gt;
      &lt;li&gt;Hot objects are determined dynamically by tracking the number of reads on each objects.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Delay eager cancellation
    &lt;ul&gt;
      &lt;li&gt;Eager cancellation: indirect ACL checks are often cancelled when parent check result is determined.&lt;/li&gt;
      &lt;li&gt;Problem: Checks are cancelled before cache keys are populated; thus concurrent requests are blocked on the lock table entry.
        &lt;ul&gt;
          &lt;li&gt;Note: The indirect ACL check is not cached. This request is the only one allowed to perform that check. Other concurrent requests are blocked on the check. Apparently, they need to wait longer if the check is cancelled.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Improvement: delay eager cancellation when there are waiters on the corresponding lock table entry.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;performance-isolation&quot;&gt;Performance isolation&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;Requirement: If one client fails to provision enough resources for an unexpected usage pattern, other clients won’t be affected.&lt;/li&gt;
  &lt;li&gt;Control
    &lt;ul&gt;
      &lt;li&gt;CPU capacity
        &lt;ul&gt;
          &lt;li&gt;Per client&lt;/li&gt;
          &lt;li&gt;Throttling if exceeding the limit.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Total number of outstanding RPCs for memory usage
        &lt;ul&gt;
          &lt;li&gt;On Zanzibar server&lt;/li&gt;
          &lt;li&gt;Per server&lt;/li&gt;
          &lt;li&gt;Per client&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Number of concurrent reads
        &lt;ul&gt;
          &lt;li&gt;On Spanner server&lt;/li&gt;
          &lt;li&gt;Per (object, client)&lt;/li&gt;
          &lt;li&gt;Per client&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Use different lock table keys for different clients.
    &lt;ul&gt;
      &lt;li&gt;Prevent throttling on one client affecting others.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;tail-latency-mitigation&quot;&gt;Tail latency mitigation&lt;/h4&gt;

&lt;p&gt;Zanzibar’s distributed processing needs to accommodate slow tasks.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;For calls to Spanner and Leopard servers
    &lt;ul&gt;
      &lt;li&gt;Request hedging: Send the same request to multiple servers; use the first response and cancel others.&lt;/li&gt;
      &lt;li&gt;Place at least 2 replicas of these backends in every geographical region.&lt;/li&gt;
      &lt;li&gt;Practice: Send the first request; defer sending hedged requests until the initial one is known to be slow.
        &lt;ul&gt;
          &lt;li&gt;Hedging delay threshold: dynamically calculate Nth percentile latency.&lt;/li&gt;
          &lt;li&gt;thus only hedge a small fraction of total traffic;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;For requests to Zanzibar servers
    &lt;ul&gt;
      &lt;li&gt;No hedging
        &lt;ul&gt;
          &lt;li&gt;Hedging is effective only when requests have similar costs.&lt;/li&gt;
          &lt;li&gt;Some Zanzibar checks are meant to be more time-consuming.&lt;/li&gt;
          &lt;li&gt;Therefore, hedging will worsen latency by duplicate expensive requests.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Rely on sharding and monitoring mechanisms.
        &lt;ul&gt;
          &lt;li&gt;Detect and avoid slow servers.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;experience&quot;&gt;Experience&lt;/h2&gt;

&lt;p&gt;Some statistics as of 2019:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Namespace: 1,500.&lt;/li&gt;
  &lt;li&gt;Relation tuples
    &lt;ul&gt;
      &lt;li&gt;2 trillion relation tuples, close to 100 terabytes.&lt;/li&gt;
      &lt;li&gt;Number of tuples per namespace: 10 to 1 trillion.
        &lt;ul&gt;
          &lt;li&gt;Median: 15,000.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Replication location: more than 30.&lt;/li&gt;
  &lt;li&gt;QPS: more than 10 million.
    &lt;ul&gt;
      &lt;li&gt;Example of a peak event:
        &lt;ul&gt;
          &lt;li&gt;Check: 4.2M.&lt;/li&gt;
          &lt;li&gt;Read: 8.2M.&lt;/li&gt;
          &lt;li&gt;Expand: 760K.&lt;/li&gt;
          &lt;li&gt;Write: 25K.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Server: more than 10,000.
    &lt;ul&gt;
      &lt;li&gt;Organized in several dozen clusters.&lt;/li&gt;
      &lt;li&gt;Number of servers per cluster: 100 to 1,000.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;requests&quot;&gt;Requests&lt;/h3&gt;

&lt;p&gt;Two categories of requests are as below based on zookie oldness. The number of safe requests is about two orders of magnitude higher than that of recent requests. (QPS: 1.2M vs 13K as of 12/2018)&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Safe
    &lt;ul&gt;
      &lt;li&gt;Zookies are more than 10 seconds old.&lt;/li&gt;
      &lt;li&gt;Requests can be served locally.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Recent
    &lt;ul&gt;
      &lt;li&gt;Zookies are less than 10 seconds old.&lt;/li&gt;
      &lt;li&gt;Requests need to be routed to leader replica, requiring inter-region round trips.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;latency&quot;&gt;Latency&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Measurement: server side, live traffic.&lt;/li&gt;
  &lt;li&gt;Check: 3ms at both safe and recent 50th.&lt;/li&gt;
  &lt;li&gt;Write: 127ms at the 50th.&lt;/li&gt;
  &lt;li&gt;Safe requests are much faster than recent ones.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;availability&quot;&gt;Availability&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Define an available request: succeed in 5s for safe, 15s for recent requests.&lt;/li&gt;
  &lt;li&gt;Measurement: replay some real requests with modified zookies and extended deadlines.&lt;/li&gt;
  &lt;li&gt;99.999% available for past 3 years.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;internals&quot;&gt;Internals&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Delegated RPCs: Zanzibar servers contact other servers, internally.
    &lt;ul&gt;
      &lt;li&gt;22 million QPS at peak, half for reads, half for checks.&lt;/li&gt;
      &lt;li&gt;Caching handles 200 million lookups per second at peak.
        &lt;ul&gt;
          &lt;li&gt;150M for checks, 50M for reads.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Cache hit and RPCs saved by lock table
        &lt;ul&gt;
          &lt;li&gt;Checks
            &lt;ul&gt;
              &lt;li&gt;Delegate side: 10% cache hit, 12% by lock table.&lt;/li&gt;
              &lt;li&gt;Delegator side: 2% cache hit, 3% by lock table.&lt;/li&gt;
              &lt;li&gt;Save 500K RPCs per second.&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
          &lt;li&gt;Reads
            &lt;ul&gt;
              &lt;li&gt;Delegate side: 24% cache hit, 9% by lock table.&lt;/li&gt;
              &lt;li&gt;Delegator side: less than 1% cache hit.&lt;/li&gt;
              &lt;li&gt;For super-hot groups(0.1%), cache full set of members in advance.&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Spanner side
    &lt;ul&gt;
      &lt;li&gt;20 million read RPCs to Spanner, thanks to caching and read request pooling.&lt;/li&gt;
      &lt;li&gt;Number of rows per RPC: 1.5 at the median, 1,000 at the 99th.&lt;/li&gt;
      &lt;li&gt;Latency: 0.5ms at the median, 2ms at the 95th.&lt;/li&gt;
      &lt;li&gt;1% of Spanner reads benefit from hedging.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Leopard system
    &lt;ul&gt;
      &lt;li&gt;1.56M QPS at the median, 2.22M at the 99th.&lt;/li&gt;
      &lt;li&gt;Latency: 150 microsec at the median, under 1ms at the 99th.&lt;/li&gt;
      &lt;li&gt;Index incremental updates: 500 updates per second at the median, 1,500 at the 99th.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;lessons-learned&quot;&gt;Lessons learned&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Flexibility to accommodate differences between clients.
    &lt;ul&gt;
      &lt;li&gt;Access control patterns vary widely.
        &lt;ul&gt;
          &lt;li&gt;Continuously add new features to support clients’ use cases.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Freshness requirements are often but not always loose.
        &lt;ul&gt;
          &lt;li&gt;Zookie ensures bounded staleness.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Performance optimization to support client behaviors observed in production.
    &lt;ul&gt;
      &lt;li&gt;Request hedging is the key to reduce tail latency.&lt;/li&gt;
      &lt;li&gt;Hot-spot mitigation is critical for high availability.
        &lt;ul&gt;
          &lt;li&gt;Distributed cache, lock table, cache prefetching for hot items, delay eager cancellation.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Performance isolation protects against misbehaving clients.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;related-work&quot;&gt;Related work&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Access control in multi-user OS
    &lt;ul&gt;
      &lt;li&gt;Multics, UNIX, POSIX ACLs, VMS.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Taos supports identity in distributed systems.&lt;/li&gt;
  &lt;li&gt;Role-based access control
    &lt;ul&gt;
      &lt;li&gt;Role is similar to relation in Zanzibar.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Identity and Access Management (IAM)
    &lt;ul&gt;
      &lt;li&gt;Amazon, Google, Microsoft’s cloud services.&lt;/li&gt;
      &lt;li&gt;Unified ACL storage and RPC-based API.&lt;/li&gt;
      &lt;li&gt;Google Cloud IAM is built on Zanzibar.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;TAO is a distributed storage for social graphs in Facebook.
    &lt;ul&gt;
      &lt;li&gt;No external consistency.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Chubby and Zookeeper don’t have features required to be Zanzibar’s storage.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Unified access control data and logic&lt;/li&gt;
  &lt;li&gt;Flexible data model and configuration&lt;/li&gt;
  &lt;li&gt;External consistency&lt;/li&gt;
  &lt;li&gt;Scalability, low latency and high availability&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
    
      <item>
        <title>Migrate blog from Github Pages to Gitlab Pages</title>
        <link>/2019/07/26/gitlab-page.html</link>
        <guid isPermaLink="true">/2019/07/26/gitlab-page.html</guid>
        <pubDate>Fri, 26 Jul 2019 00:00:00 +0000</pubDate>
        <description>&lt;h2 id=&quot;background&quot;&gt;Background&lt;/h2&gt;

&lt;p&gt;My Github Pro subscription expired a few days ago, which means although I can have private repo for my blog, it cannot publish new updates any more. Two choices for you from Github: either pay for Pro or change the repo to a public one.&lt;/p&gt;

&lt;p&gt;I am happy to contribute to open source world. However, the repo contains some sensitive information, like Google analytics ID, or perhaps some passwords pushed by mistake in commit history.. Therefore I decided to find a free alternative instead of going along with Github.&lt;/p&gt;

&lt;p&gt;Happy to find Gitlab Pages, which I think is a perfect replacement of Github Pages, or even better. However, there are still some caveats during migration. Here I will make a summary of this effort. Note that entire migration took me around 2 hours.&lt;/p&gt;

&lt;h2 id=&quot;where-to-push-my-code&quot;&gt;Where to push my code?&lt;/h2&gt;

&lt;p&gt;Gitlab provides an amazing CI/CD feature, which does CI/CD from external repo. So all you have to do is to create a new project in Gitlab by setting up the CI/CD from your Github repo. In this way, you don’t even have to change your local git settings like adding a new origin for Gitlab. But you can do it anyway.&lt;/p&gt;

&lt;p&gt;Depending on what you choose, you can either push to Github or Gitlab. Both repos can be private.&lt;/p&gt;

&lt;h2 id=&quot;how-to-generate-static-pages&quot;&gt;How to generate static pages?&lt;/h2&gt;

&lt;p&gt;Github does this step automatically once receiving a new push. Gitlab needs some configurations for CI/CD (changes -&amp;gt; pages, not Github repo -&amp;gt; Gitlab), but this doesn’t mean it’s not as good as Github. Actually, I was surprised by this feature. It’s much more configurable and thus powerful.&lt;/p&gt;

&lt;p&gt;For the example of Pages, add a new &lt;code class=&quot;highlighter-rouge&quot;&gt;.gitlab-ci.yml&lt;/code&gt; file under the root directory with following configs. You can learn more about the config settings &lt;a href=&quot;https://docs.gitlab.com/ee/user/project/pages/getting_started_part_four.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;image: ruby:2.3

before_script:
    - export LC_ALL=&quot;C.UTF-8&quot;
    - export LANG=&quot;en_US.UTF-8&quot;
    - export LANGUAGE=&quot;en_US.UTF-8&quot;

pages:
  stage: deploy
  script:
  - bundle install
  - bundle exec jekyll build -d public
  artifacts:
    paths:
    - public
  only:
  - master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Push the changes. In order to trigger the page generation pipeline, you need to manually run one in the project’s Pipelines page. The following changes will be generated automatically. You can even view the progress or download the generated html files.&lt;/p&gt;

&lt;h2 id=&quot;wait-whats-the-url&quot;&gt;Wait, what’s the url?&lt;/h2&gt;

&lt;p&gt;The default url will be &lt;code class=&quot;highlighter-rouge&quot;&gt;YOUR_USERNAME.gitlab.io/YOUR_PROJECT_NAME&lt;/code&gt;, which may cause trouble if you didn’t have correct prefix for your assets’ url (css, pictures, etc). I recommend to do following in Project setting -&amp;gt; Advanced. It enables us to use custom domain easily. Without this, the homepage url with custom domain is &lt;code class=&quot;highlighter-rouge&quot;&gt;yourcustom.domain/YOUT_PROJECT_NAME&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Rename your project to &lt;code class=&quot;highlighter-rouge&quot;&gt;YOUR_USERNAME.gitlab.io&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Update its path to https://gitlab.com/YOUR_USERNAME/&lt;code class=&quot;highlighter-rouge&quot;&gt;YOUR_USERNAME.gitlab.io&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After this, the url will be &lt;code class=&quot;highlighter-rouge&quot;&gt;YOUR_USERNAME.gitlab.io&lt;/code&gt;. Custom domain will work as well.&lt;/p&gt;

&lt;p&gt;With this setting, url prefix for all your assets in your project should be &lt;code class=&quot;highlighter-rouge&quot;&gt;&quot;&quot;&lt;/code&gt; in your &lt;code class=&quot;highlighter-rouge&quot;&gt;_config.yml&lt;/code&gt;. Otherwise, it has to be &lt;code class=&quot;highlighter-rouge&quot;&gt;/YOUR_PROJECT_NAME&lt;/code&gt;. An example of asset path suffix could be &lt;code class=&quot;highlighter-rouge&quot;&gt;/assets/web/web_design_workflow.png&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;custom-domain-is-fancy&quot;&gt;Custom domain is fancy&lt;/h2&gt;

&lt;p&gt;Easy to set up custom domain with HTTPS. Just follow instruction in Setting -&amp;gt; Pages. Server IP address is provided &lt;a href=&quot;https://docs.gitlab.com/ee/user/project/pages/custom_domains_ssl_tls_certification/&quot;&gt;here&lt;/a&gt;. HTTPS support is built-in or you can use your own certificate.&lt;/p&gt;

&lt;h2 id=&quot;other-caveats&quot;&gt;Other caveats&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;You shouldn’t name one of your top level directories to &lt;code class=&quot;highlighter-rouge&quot;&gt;public&lt;/code&gt;. This is a reserved name by Gitlab Page.&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
    
      <item>
        <title>Read &quot;Spanner, Google's Globally-Distributed Database&quot;</title>
        <link>/2019/07/06/spanner-paper.html</link>
        <guid isPermaLink="true">/2019/07/06/spanner-paper.html</guid>
        <pubDate>Sat, 06 Jul 2019 00:00:00 +0000</pubDate>
        <description>&lt;h2 id=&quot;reference&quot;&gt;Reference&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://static.googleusercontent.com/media/research.google.com/en//archive/spanner-osdi2012.pdf&quot;&gt;Link to paper&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.usenix.org/node/170855&quot;&gt;Link to presentation video&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.usenix.org/sites/default/files/conference/protected-files/corbett_osdi12_slides.pptx&quot;&gt;Link to presentation slides&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;Spanner is Google’s scalable, globally-distributed database. It shards data across many sets of Paxos state machines spread all over the world. Data is also replicated to support availability and geographic locality. To balance load or respond to failures, data can be re-sharded or migrated automatically according to data or server changes.&lt;/p&gt;

&lt;p&gt;Most applications favor lower latency over higher availability, thus they use less datacenters for replication (3 to 5 across US), as long as they can survive 1 to 2 datacenter failures.&lt;/p&gt;

&lt;p&gt;Comparison with other Google databases:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Bigtable
    &lt;ul&gt;
      &lt;li&gt;Difficult to use for some applications with complex, evolving schemas.&lt;/li&gt;
      &lt;li&gt;Doesn’t provide strong consistency in the presence of wide-area replication.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Megastore
    &lt;ul&gt;
      &lt;li&gt;Good to have semi-relational data model.&lt;/li&gt;
      &lt;li&gt;Support synchronous replication.&lt;/li&gt;
      &lt;li&gt;Write throughput is relatively poor.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Spanner
    &lt;ul&gt;
      &lt;li&gt;Schematized semi-relational tables.&lt;/li&gt;
      &lt;li&gt;Data is versioned and each version is timestamped with its commit time.&lt;/li&gt;
      &lt;li&gt;Applications can read data at old timestamps.&lt;/li&gt;
      &lt;li&gt;Garbage collections on old versions.&lt;/li&gt;
      &lt;li&gt;Support general transactions.&lt;/li&gt;
      &lt;li&gt;Support SQL-based queries.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other features:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Replication configurations for data can be dynamically controlled at a fine grain by applications.
    &lt;ul&gt;
      &lt;li&gt;Which datacenter contains which data.&lt;/li&gt;
      &lt;li&gt;How far data is from users.&lt;/li&gt;
      &lt;li&gt;How far replicas are from each other.&lt;/li&gt;
      &lt;li&gt;How many replicas.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Data can be dynamically and transparently moved across datacenters to balance.&lt;/li&gt;
  &lt;li&gt;Provide externally consistent reads and writes (linearizability).&lt;/li&gt;
  &lt;li&gt;Provide globally-consistent reads across database at a timestamp.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These features are enabled by the fact that Spanner assigns globally-meaningful commit timestamps to distributed transactions, which reflect serialization order. If a transaction T1 commits before another transaction T2, then T1’s timestamp is smaller than T2’s.&lt;/p&gt;

&lt;p&gt;TrueTime API:&lt;/p&gt;

&lt;p&gt;The key enabler is TrueTime API. It directly expose clock uncertainty (generally less than 10ms). If uncertainty is large, Spanner slows down to wait out that uncertainty. The API implementation is using both GPS and atomic clocks.&lt;/p&gt;

&lt;p&gt;Note: Example of how the TrueTime helps. Say we have 2 nodes A and B and 2 transaction T1 and T2.&lt;/p&gt;

&lt;p&gt;Without TrueTime:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;At true time 10, A time 15, A updates A’s value from “A1” to “A2”, T1 committed at timestamp 15.&lt;/li&gt;
  &lt;li&gt;At true time 15, B time 10, B updates B’s value from “B1” to “B2”, T2 committed at timestamp 10.&lt;/li&gt;
  &lt;li&gt;Client performs a read with timestamp 10, It sees “A1” and “B2”, which is inconsistent with actual true time order.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With TrueTime, uncertainty 15 (larger than the difference of server timestamps):&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;At true time 10, A time 15, A updates A’s value from “A1” to “A2”, T1 committed at timestamp 15.&lt;/li&gt;
  &lt;li&gt;Wait uncertainty 15, true time is 25.
    &lt;ul&gt;
      &lt;li&gt;Now true time 15 (which is T1’s timestamp) has passed.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;At true time 30, B time 25, B updates B’s value from “B1” to “B2”, T2 committed at timestamp 25.&lt;/li&gt;
  &lt;li&gt;Client performs a read with timestamp 25, It sees “A2” and “B2”.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Note: Vector clock is another method solving this. Now a clock is represented as a vector &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;ts1, ts2, ..., tsn&amp;gt;&lt;/code&gt;. &lt;code class=&quot;highlighter-rouge&quot;&gt;n&lt;/code&gt; is the number of nodes. In case of two nodes, the clock vector is &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;ts1, ts2&amp;gt;&lt;/code&gt;. The following example shows that the clock vectors reflect actual serialization order as well. However, we may have too many nodes in Spanner group, thus cost could be huge to store, write and transport the vectors. We can understand why it’s not used in Spanner. This vector clock may sound similar to Lamport timestamp, but better. Lamport timestamp can enforce total order, but cannot describe concurrent events well. Vector clock records timestamps on all nodes to represent such causality.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;At true time 10, A time 15, A updates A’s value from “A1” to “A2”, T1 committed at timestamp &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;15, 0&amp;gt;&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;This timestamp is broadcasted to other nodes, B updated its timestamp to &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;15, x&amp;gt;&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;At true time 15, B time 10, B updates B’s value from “B1” to “B2”, committed at timestamp &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;15, 10&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;implementation&quot;&gt;Implementation&lt;/h2&gt;

&lt;p&gt;A Spanner deployment is called universe, which can be global. Currently, there are 3 universes: test/playground, dev/prod and prod-only universes.&lt;/p&gt;

&lt;p&gt;Spanner is organized as a set of zones. Zone is the unit of administrative deployment; location across which data can be replicated; unit of physical isolation. For physical isolation, one datacenter may have multiple zones as different applications’ data must be partitioned across different sets of servers in the same datacenter. Zone can be added or removed, as datacenters added or turned off.&lt;/p&gt;

&lt;p&gt;The Spanner servers are organized as below.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/system/spanner/spanner-structure.png&quot; alt=&quot;Spanner server organization&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Universe level
    &lt;ul&gt;
      &lt;li&gt;universemaster
        &lt;ul&gt;
          &lt;li&gt;A console displaying status information about all zones for debugging.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;placement driver
        &lt;ul&gt;
          &lt;li&gt;Handle automated data movement across zones in minutes.&lt;/li&gt;
          &lt;li&gt;Communicate with spanservers periodically.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Zone level
    &lt;ul&gt;
      &lt;li&gt;zonemaster
        &lt;ul&gt;
          &lt;li&gt;Assign data to spanservers.&lt;/li&gt;
          &lt;li&gt;One per zone.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;location proxies
        &lt;ul&gt;
          &lt;li&gt;Used by clients to locate spanservers to serve their data.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;spanservers
        &lt;ul&gt;
          &lt;li&gt;Serve data to clients.&lt;/li&gt;
          &lt;li&gt;100 to several thousand per zone.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;spanserver-software-stack&quot;&gt;Spanserver software stack&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Each spanserver is responsible for 100 to 1000 tablets.&lt;/li&gt;
  &lt;li&gt;A tablet is a bag of mappings.
    &lt;ul&gt;
      &lt;li&gt;Stored in set of B-tree-like files and write-ahead log.
        &lt;ul&gt;
          &lt;li&gt;Both stored on Colossus.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Mapping: (key:string, timestamp:int64) -&amp;gt; string.
    &lt;ul&gt;
      &lt;li&gt;Thus Spanner is a multi-version k-v store.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The spanserver is organized as:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/system/spanner/spanserver-stack.png&quot; alt=&quot;spanserver organization&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A single Paxos state machine on top of each tablet.
    &lt;ul&gt;
      &lt;li&gt;Stores its metadata and log in the tablet.&lt;/li&gt;
      &lt;li&gt;Supports long-lived leaders with time-based lease (default 10s).&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;A set of replicas of a tablet is a Paxos group.
    &lt;ul&gt;
      &lt;li&gt;Writes must initiate Paxos protocol at leader.&lt;/li&gt;
      &lt;li&gt;Reads can access any replica.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;At leader replica, spanserver implements a lock table to have concurrency control. (Critical to have long-live leaders)
    &lt;ul&gt;
      &lt;li&gt;Contains state for 2PL: map key range to lock state.
        &lt;ul&gt;
          &lt;li&gt;In contrast, optimistic control will cause bad performance of long-lived transactions in case of conflicts.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Practice
        &lt;ul&gt;
          &lt;li&gt;Synchronized operations acquire locks.
            &lt;ul&gt;
              &lt;li&gt;e.g., transactional reads.&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
          &lt;li&gt;Other operations bypass the lock table.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Distributed transactions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;If a transaction involves only one Paxos group (most of them), lock table and Paxos can provide enough transactionality.&lt;/li&gt;
  &lt;li&gt;Otherwise, coordination across groups is needed.
    &lt;ul&gt;
      &lt;li&gt;Leader replica spanserver implements a transaction manager. The replica is a participant leader; others are participant slaves.&lt;/li&gt;
      &lt;li&gt;Those groups’ leaders coordinate to perform 2PC.
        &lt;ul&gt;
          &lt;li&gt;One group is chosen to be coordinator (with coordinator leader and slaves).&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;State of transaction manager is stored in the Paxos group and thus replicated.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;directories-and-placement&quot;&gt;Directories and placement&lt;/h3&gt;

&lt;p&gt;Directory is a bucketing abstraction of a set of contiguous keys that share a common prefix. Applications can use directories to control the locality of the data by choosing the keys carefully.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A directory is the unit of data placement.
    &lt;ul&gt;
      &lt;li&gt;All data in a directory has the same replication configuration.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;A Paxos group (tablet replicas) can have multiple directories.
    &lt;ul&gt;
      &lt;li&gt;Frequently accessed directories can be local to each other.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Movedir&lt;/em&gt; is used to move directories between Paxos groups; and add or remove replicas to Paxos groups.&lt;/li&gt;
  &lt;li&gt;A directory is the unit of specified geographic-replication properties.
    &lt;ul&gt;
      &lt;li&gt;e.g., Specify user group A has 3 replicas in US; group B has 2 replicas in EU.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Spanner shards a directory into multiple fragments if it grows too large.
    &lt;ul&gt;
      &lt;li&gt;Different fragments may be served from different Paxos groups.&lt;/li&gt;
      &lt;li&gt;&lt;em&gt;Movedir&lt;/em&gt; moves fragments.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: How to ensure locality of a directory if its fragments are in different Paxos groups? My thinking: If those fragments are in different Paxos groups, locality cannot be guaranteed and 2PC is required if a transaction involves multiple fragments. But data in a fragment always stays in the same Paxos group.&lt;/p&gt;

&lt;h3 id=&quot;data-model&quot;&gt;Data model&lt;/h3&gt;

&lt;p&gt;Spanner data features:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Schematized semi-relational tables, synchronous replication across datacenters.
    &lt;ul&gt;
      &lt;li&gt;Easy to manage, like Megastore.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Query language
    &lt;ul&gt;
      &lt;li&gt;To support Dremel.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;General-purpose transactions.
    &lt;ul&gt;
      &lt;li&gt;Although 2PC is expensive, Spanner still support cross-row transactions. Application developers is responsible to deal with low-performance problems.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Application data model is layered on top of Spanner’s directory-bucketed k-v mappings.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;An application creates one or more &lt;em&gt;databases&lt;/em&gt; in a universe.&lt;/li&gt;
  &lt;li&gt;A &lt;em&gt;database&lt;/em&gt; can contain unlimited number of schematized &lt;em&gt;tables&lt;/em&gt;.
    &lt;ul&gt;
      &lt;li&gt;A &lt;em&gt;database&lt;/em&gt; must be partitioned into one or more hierarchies of &lt;em&gt;tables&lt;/em&gt;.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;A &lt;em&gt;table&lt;/em&gt; looks like relational-database table, with rows, columns and versions.&lt;/li&gt;
  &lt;li&gt;A row must have one or more primary-key columns.
    &lt;ul&gt;
      &lt;li&gt;Application can use keys to control data locality.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example of a database schema:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;CREATE TABLE Users {
  uid INT64 NOT NULL, email STRING
} PRIMARY KEY (uid), DIRECTORY;

CREATE TABLE Albums {
  uid INT64 NOT NULL, aid INT64 NOT NULL,
  name STRING
} PRIMARY KEY (uid, aid),
  INTERLEAVE IN PARENT Users ON DELETE CASCADE;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;DIRECTORY&lt;/code&gt; declares a top-level directory table in the hierarchy.
    &lt;ul&gt;
      &lt;li&gt;A directory is formed with each row in directory table with key K, together with all rows in descendant tables that start with K in lexicographic order.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;INTERLEAVE IN&lt;/code&gt; declare descendant tables.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;ON DELETE CASCADE&lt;/code&gt; says deleting a directory table row will delete all associated rows in descendant tables.&lt;/li&gt;
  &lt;li&gt;With this directory concept, we can have a user row and its album rows stay together.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;truetime&quot;&gt;TrueTime&lt;/h2&gt;

&lt;p&gt;API:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Method&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Returns&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;TT.now()&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;TTinterval: &lt;code class=&quot;highlighter-rouge&quot;&gt;[earliest, latest]&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;TT.after(t)&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;true if &lt;code class=&quot;highlighter-rouge&quot;&gt;t&lt;/code&gt; has definitely passed&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;TT.before(t)&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;true if &lt;code class=&quot;highlighter-rouge&quot;&gt;t&lt;/code&gt; has definited not arrived&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;TrueTime uses both GPS and atomic clocks as time references. They have different failure modes; thus can compensate each other.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Organization:
    &lt;ul&gt;
      &lt;li&gt;TrueTime is implemented by a set of time master machines per datacenter and a timeslave daemon per machine.&lt;/li&gt;
      &lt;li&gt;The majority of masters have GPS receivers.
        &lt;ul&gt;
          &lt;li&gt;Advertising uncertainty is typically close to zero.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;The rest of masters use atom clocks. (Armageddon masters)
        &lt;ul&gt;
          &lt;li&gt;Advertising uncertainty slowly increases, derived from conservatively worst-case clock drift.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Mechanism:
    &lt;ul&gt;
      &lt;li&gt;Masters compare time references against each other.&lt;/li&gt;
      &lt;li&gt;Each master cross-checks the divergence rate.&lt;/li&gt;
      &lt;li&gt;Every daemons poll a variety of masters (some may be from farther datacenters).
        &lt;ul&gt;
          &lt;li&gt;Apply Marzullo’s algorithm to synchronize local clocks.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Define instantaneous error bound as &lt;script type=&quot;math/tex&quot;&gt;\epsilon&lt;/script&gt;, which is half of the interval’s width. Average error bound is &lt;script type=&quot;math/tex&quot;&gt;\bar{\epsilon}&lt;/script&gt;.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Before synchronizations, a daemon advertises a slowly increasing time uncertainty &lt;script type=&quot;math/tex&quot;&gt;\epsilon&lt;/script&gt;.
    &lt;ul&gt;
      &lt;li&gt;&lt;script type=&quot;math/tex&quot;&gt;\epsilon&lt;/script&gt; is derived from
        &lt;ul&gt;
          &lt;li&gt;conservatively applied worst-case local clock drift&lt;/li&gt;
          &lt;li&gt;time-master uncertainty&lt;/li&gt;
          &lt;li&gt;communication delay to the time masters.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;script type=&quot;math/tex&quot;&gt;\epsilon&lt;/script&gt; is a sawtooth function of time, varying from 1 to 7 ms over each poll interval (30s).
    &lt;ul&gt;
      &lt;li&gt;Applied drift 0 to 6 ms.
        &lt;ul&gt;
          &lt;li&gt;Rate 20 microsec/sec * 30 sec.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;1 ms is communication delay to the time masters.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;concurrency-control&quot;&gt;Concurrency control&lt;/h2&gt;

&lt;p&gt;TrueTime -&amp;gt; (enables) correctness properties around concurrency control -&amp;gt; features:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Externally consistent transactions&lt;/li&gt;
  &lt;li&gt;Lock-free read-only transactions&lt;/li&gt;
  &lt;li&gt;Non-blocking reads in the past.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These features enable a guarantee that a whole-database audit read at a timestamp t will see exactly the effects of every transaction that has committed as of t.&lt;/p&gt;

&lt;h3 id=&quot;timestamp-management&quot;&gt;Timestamp management&lt;/h3&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Operation&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Concurrency control&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Replica required&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Read-Write Transaction&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;pessimistic&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;leader&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Read-only transaction&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;lock-free&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;leader for timestamp; any for read&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Snapshot read with client-provided timestamp&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;lock-free&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;any&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Snapshot read with client-provided bound&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;lock-free&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;any&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;ul&gt;
  &lt;li&gt;Read-only transaction
    &lt;ul&gt;
      &lt;li&gt;Must be pre-declared first (not having any write).&lt;/li&gt;
      &lt;li&gt;System (leader) chooses a timestamp for it.&lt;/li&gt;
      &lt;li&gt;Can then be processed on any replica.&lt;/li&gt;
      &lt;li&gt;Incoming writes are not blocked.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Snapshot read
    &lt;ul&gt;
      &lt;li&gt;Client can specify a timestamp or provide an upper bound and let Spanner to choose one.&lt;/li&gt;
      &lt;li&gt;Processed on any replica.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;paxos-leader-leases&quot;&gt;Paxos leader leases&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;Spanner’s Paxos use time leases to make leadership long-lived (10 sec by default).&lt;/li&gt;
  &lt;li&gt;Lease can be extended when approaching expiration.&lt;/li&gt;
  &lt;li&gt;Leader can abdicate by releasing its slaves.
    &lt;ul&gt;
      &lt;li&gt;A leader must wait some time until it can abdicate to preserve the disjointness invariant.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Within a Paxos group, leaders’ lease intervals should be disjoint. (current leader’s and the subsequent leader’s)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;assigning-timestamps-to-rw-transactions&quot;&gt;Assigning timestamps to RW transactions&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;RW transactions use 2PL.&lt;/li&gt;
  &lt;li&gt;Spanner assigns a timestamp at any time when all locks have been acquired, but before any lock has been released.
    &lt;ul&gt;
      &lt;li&gt;The timestamp of the Paxos write representing transaction commit.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Invariant 1: Within each Paxos group, Spanner assigns timestamps to Paxos writes in monotonically increasing order, even across leaders (current and the subsequent ones within a group).
    &lt;ul&gt;
      &lt;li&gt;Enabled by making use of the disjointness invariant.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Invariant 2: if the start of a transaction &lt;script type=&quot;math/tex&quot;&gt;T_2&lt;/script&gt; occurs after the commit of a transaction &lt;script type=&quot;math/tex&quot;&gt;T_1&lt;/script&gt;, then the commit timestamp of &lt;script type=&quot;math/tex&quot;&gt;T_2&lt;/script&gt; must be greater than the commit timestamp of &lt;script type=&quot;math/tex&quot;&gt;T_1&lt;/script&gt;.
    &lt;ul&gt;
      &lt;li&gt;Enabled by commit wait.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;serving-reads-at-a-timestamp&quot;&gt;Serving reads at a timestamp&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;Every replica tracks a timestamp value called safe time &lt;script type=&quot;math/tex&quot;&gt;t_{safe}&lt;/script&gt;, to which it’s up to date. A replica can serve a read at a timestamp &lt;script type=&quot;math/tex&quot;&gt;t&lt;/script&gt; if &lt;script type=&quot;math/tex&quot;&gt;t \le t_{safe}&lt;/script&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;script type=&quot;math/tex&quot;&gt;t_{safe}&lt;/script&gt; is the minimum of:
    &lt;ul&gt;
      &lt;li&gt;&lt;script type=&quot;math/tex&quot;&gt;t^{Paxos}_{safe}&lt;/script&gt;: the timestamp of the highest-applied Paxos write.&lt;/li&gt;
      &lt;li&gt;For transaction manager, &lt;script type=&quot;math/tex&quot;&gt;t^{TM}_{safe}&lt;/script&gt;: &lt;script type=&quot;math/tex&quot;&gt;t^{TM}_{safe} = min_i(s_{i, g}^{prepare}) - 1&lt;/script&gt;.
        &lt;ul&gt;
          &lt;li&gt;&lt;script type=&quot;math/tex&quot;&gt;s_{i, g}^{prepare}&lt;/script&gt; is the prepared timestamps from a group &lt;script type=&quot;math/tex&quot;&gt;g&lt;/script&gt;, inferred from the prepared but not committed transactions (between two phases of 2PC).&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;assigning-timestamps-to-ro-transactions&quot;&gt;Assigning timestamps to RO transactions&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;Two steps:
    &lt;ul&gt;
      &lt;li&gt;Assign a timestamp.&lt;/li&gt;
      &lt;li&gt;Execute the reads as snapshot reads at this timestamp.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Spanner usually assigns the oldest timestamp that preserves external consistency.
    &lt;ul&gt;
      &lt;li&gt;A too fresh timestamp like &lt;code class=&quot;highlighter-rouge&quot;&gt;TT.now().latest&lt;/code&gt; make block if &lt;script type=&quot;math/tex&quot;&gt;t_{safe}&lt;/script&gt; has not advanced sufficiently.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;details&quot;&gt;Details&lt;/h3&gt;

&lt;h4 id=&quot;rw-transactions&quot;&gt;RW transactions&lt;/h4&gt;

&lt;p&gt;When multiple Paxos groups are involved:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Writes in a transaction are buffered at the client until commit.
    &lt;ul&gt;
      &lt;li&gt;Therefore, reads in the same transaction don’t see the effects of those writes.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Reads use wound-wait to avoid deadlocks.&lt;/li&gt;
  &lt;li&gt;Client sends keepalive messages to participant leaders when a transaction remains open.&lt;/li&gt;
  &lt;li&gt;Client begins 2PC when all reads are completed and all writes are buffered.
    &lt;ul&gt;
      &lt;li&gt;Choose a coordinator group.&lt;/li&gt;
      &lt;li&gt;Send a commit message to all participant leaders with the coordinator information and buffered writes.
        &lt;ul&gt;
          &lt;li&gt;Avoid sending data twice (if let the coordinator drive the 2PC).&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2PC:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Non-coordinator-participant leader
    &lt;ol&gt;
      &lt;li&gt;Acquire write locks.&lt;/li&gt;
      &lt;li&gt;Choose a prepare timestamp (greater than all assigned).&lt;/li&gt;
      &lt;li&gt;Log a prepare record through Paxos.&lt;/li&gt;
      &lt;li&gt;Send the prepare timestamp to the coordinator.&lt;/li&gt;
      &lt;li&gt;Receive commit timestamp from coordinator.&lt;/li&gt;
      &lt;li&gt;Log the transaction’s outcome through Paxos.&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;Coordinator
    &lt;ol&gt;
      &lt;li&gt;Acquire write locks.&lt;/li&gt;
      &lt;li&gt;Skip prepare phase.&lt;/li&gt;
      &lt;li&gt;Hear prepare timestamps from all participant leaders.&lt;/li&gt;
      &lt;li&gt;Choose a transaction timestamp s.
        &lt;ul&gt;
          &lt;li&gt;Greater than all prepare timestamps.&lt;/li&gt;
          &lt;li&gt;Greater than all assigned at itself.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Wait until s is definitely passed.&lt;/li&gt;
      &lt;li&gt;Concurrent with step 5, log a commit record through Paxos.&lt;/li&gt;
      &lt;li&gt;Send the commit timestamp to the client and all participant leaders.&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2PC adds an extra network round trip so it usually doubles observed commit latency. It scales well up to 10s of participants, but abort frequency and latency increase significantly with 100s of participants. (This is from &lt;a href=&quot;/2019/08/05/f1-paper.html&quot;&gt;F1 paper&lt;/a&gt;.)&lt;/p&gt;

&lt;h4 id=&quot;read-only-transactions&quot;&gt;Read-only transactions&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;Spanner requires a scope expression for every read-only transaction.
    &lt;ul&gt;
      &lt;li&gt;Scope: summarize the keys that will be read by the entry transaction.
        &lt;ul&gt;
          &lt;li&gt;To determine the Paxos groups to serve the request.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Cases:
    &lt;ul&gt;
      &lt;li&gt;If only one Paxos group is involved.
        &lt;ul&gt;
          &lt;li&gt;The leader maintains &lt;code class=&quot;highlighter-rouge&quot;&gt;LastTS()&lt;/code&gt; for the timestamp of the last committed write at this group.
            &lt;ul&gt;
              &lt;li&gt;Better than &lt;code class=&quot;highlighter-rouge&quot;&gt;TT.now().lastest()&lt;/code&gt;.&lt;/li&gt;
              &lt;li&gt;Use it for read timestamp if no prepared transactions.
                &lt;ul&gt;
                  &lt;li&gt;Note:
                    &lt;ul&gt;
                      &lt;li&gt;If prepared transactions exist and deal with the same data as the RO transaction, the RO transaction should be assigned &lt;script type=&quot;math/tex&quot;&gt;t&lt;/script&gt; equal to &lt;code class=&quot;highlighter-rouge&quot;&gt;TT.now().lastest()&lt;/code&gt;; then snapshot read will wait until &lt;script type=&quot;math/tex&quot;&gt;t \le t_{safe}&lt;/script&gt;.
                        &lt;ul&gt;
                          &lt;li&gt;When &lt;script type=&quot;math/tex&quot;&gt;t&lt;/script&gt; is less than the commit timestamps of those previously prepared transactions. (&lt;script type=&quot;math/tex&quot;&gt;t_{safe}&lt;/script&gt; advanced.)&lt;/li&gt;
                        &lt;/ul&gt;
                      &lt;/li&gt;
                      &lt;li&gt;If data to read is unrelated to the prepared transactions, is it safe to use &lt;code class=&quot;highlighter-rouge&quot;&gt;LastTS()&lt;/code&gt;?
                        &lt;ul&gt;
                          &lt;li&gt;Could be, see refinements.&lt;/li&gt;
                        &lt;/ul&gt;
                      &lt;/li&gt;
                    &lt;/ul&gt;
                  &lt;/li&gt;
                &lt;/ul&gt;
              &lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Multiple Paxos groups
        &lt;ul&gt;
          &lt;li&gt;Simple option (used by Spanner): use &lt;code class=&quot;highlighter-rouge&quot;&gt;TT.now().lastest()&lt;/code&gt;.&lt;/li&gt;
          &lt;li&gt;Complicated option: do a round of communication with all groups to negotiate based on their &lt;code class=&quot;highlighter-rouge&quot;&gt;LastTS()&lt;/code&gt;.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;schema-change-transactions&quot;&gt;Schema-change transactions&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;Spanner supports atomic schema changes.
    &lt;ul&gt;
      &lt;li&gt;Not a standard transaction, since millions of participants could be involved.&lt;/li&gt;
      &lt;li&gt;TrueTime is essential for this.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Bigtable supports atomic schema changes in one datacenter.
    &lt;ul&gt;
      &lt;li&gt;But changes block all operations.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Details:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The transaction is explicitly assigned a timestamp t in the future.
    &lt;ul&gt;
      &lt;li&gt;Registered in the prepared phase.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Operations relying on the new schema must wait until t is passed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;refinements&quot;&gt;Refinements&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;Problem of &lt;script type=&quot;math/tex&quot;&gt;t^{TM}_{safe}&lt;/script&gt;: A single prepared transaction prevents &lt;script type=&quot;math/tex&quot;&gt;t_{safe}&lt;/script&gt; from advancing.
    &lt;ul&gt;
      &lt;li&gt;Even if the read is unrelated to the prepared transaction.&lt;/li&gt;
      &lt;li&gt;Refinement: Use a mapping from key ranges to prepared transaction timestamps.
        &lt;ul&gt;
          &lt;li&gt;Can be stored in the lock table.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Schema change prepared transaction should block all.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Problem of &lt;code class=&quot;highlighter-rouge&quot;&gt;LastTS()&lt;/code&gt;: A read must be assigned a timestamp after the recent transaction, even if they are irrelevant.
    &lt;ul&gt;
      &lt;li&gt;Refinement: Use a mapping from key ranges to commit timestamps.
        &lt;ul&gt;
          &lt;li&gt;Not implemented in 2012.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Problem of &lt;script type=&quot;math/tex&quot;&gt;t^{Paxos}_{safe}&lt;/script&gt;: It cannot advance in the absence of Paxos writes.
    &lt;ul&gt;
      &lt;li&gt;A snapshot read at t cannot be executed at Paxos group whose last write happened before t.&lt;/li&gt;
      &lt;li&gt;Refinement: Paxos leader advances &lt;script type=&quot;math/tex&quot;&gt;t^{Paxos}_{safe}&lt;/script&gt;.
        &lt;ul&gt;
          &lt;li&gt;Set it based on &lt;code class=&quot;highlighter-rouge&quot;&gt;MinNextTS()&lt;/code&gt; within the lease interval.&lt;/li&gt;
          &lt;li&gt;Enabled by the disjointness of leader lease intervals.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;MinNextTS()&lt;/code&gt; is advanced every 8 seconds.
        &lt;ul&gt;
          &lt;li&gt;Thus an idle Paxos group may serve reads at timestamp greater than 8 seconds old in the worst case.
            &lt;ul&gt;
              &lt;li&gt;Note: This means a snapshot read may need to wait for 8 seconds to perform the read.
                &lt;ul&gt;
                  &lt;li&gt;When &lt;script type=&quot;math/tex&quot;&gt;t \le t_{safe}&lt;/script&gt;.&lt;/li&gt;
                &lt;/ul&gt;
              &lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;evaluation&quot;&gt;Evaluation&lt;/h2&gt;

&lt;h3 id=&quot;microbenchmarks&quot;&gt;Microbenchmarks&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Latency
    &lt;ul&gt;
      &lt;li&gt;For writes, latency stays roughly constant with less std, as number of replicas increases.
        &lt;ul&gt;
          &lt;li&gt;Because Paxos executes in parallel at a group’s replicas.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Throughput
    &lt;ul&gt;
      &lt;li&gt;Snapshot reads: increase almost linearly with the number of replicas.
        &lt;ul&gt;
          &lt;li&gt;Because they can be served from any up-to-date replicas.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;RO transactions: increases as number of replicas increases (corresponding number of spanservers also increases).
        &lt;ul&gt;
          &lt;li&gt;Timestamp must be assigned by leader.&lt;/li&gt;
          &lt;li&gt;Can then be served by other replicas.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Write: 1 replica &amp;gt; 5 replicas &amp;gt; 3 replicas.
        &lt;ul&gt;
          &lt;li&gt;Because 1 replica doesn’t need to do replication.&lt;/li&gt;
          &lt;li&gt;Number of spanservers increases when 3 replicas -&amp;gt; 5 replicas.
            &lt;ul&gt;
              &lt;li&gt;Also leaders are randomly distributed.&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;2PC
    &lt;ul&gt;
      &lt;li&gt;2PC can be scaled up to 100 participants with reasonable latency in the experiment.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;availability&quot;&gt;Availability&lt;/h3&gt;

&lt;p&gt;Failure mode:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Non-leader fail
    &lt;ul&gt;
      &lt;li&gt;No effect on read throughput.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Leader soft fail (but notify all servers to handoff leadership first)
    &lt;ul&gt;
      &lt;li&gt;Minor effect on read throughput (3% - 4%).&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Leader hard fail
    &lt;ul&gt;
      &lt;li&gt;Severe effect within failed leader lease window.&lt;/li&gt;
      &lt;li&gt;Re-elect leader; then catch up in next lease window.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;truetime-1&quot;&gt;TrueTime&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;The 200 us/sec clock drift is a reasonable assumption.
    &lt;ul&gt;
      &lt;li&gt;Bad CPU problem are 6 times more likely than bad clocks.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Uncertainty comes from:
    &lt;ul&gt;
      &lt;li&gt;Time master uncertainty (generally 0);&lt;/li&gt;
      &lt;li&gt;Communication delay to the time masters.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Experiment shows no significant problem.
    &lt;ul&gt;
      &lt;li&gt;To improve:
        &lt;ul&gt;
          &lt;li&gt;Improve network;&lt;/li&gt;
          &lt;li&gt;Reduce causes of TrueTime spikes.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;case-study-f1&quot;&gt;Case study: F1&lt;/h3&gt;

&lt;p&gt;Painful past:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Based on MySQL.&lt;/li&gt;
  &lt;li&gt;Manual re-sharding was costly and took long time (over two years).&lt;/li&gt;
  &lt;li&gt;Data growth was limited by the team.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reasons choosing Spanner:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;No need to manually re-shard.&lt;/li&gt;
  &lt;li&gt;Synchronous replication and automatic failover.&lt;/li&gt;
  &lt;li&gt;Transactions.
    &lt;ul&gt;
      &lt;li&gt;e.g., generating secondary indexes.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Practices:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Choose replica locations to cope with potential outrages and their frontend locations.&lt;/li&gt;
  &lt;li&gt;Spanner timestamp makes F1 easy to maintain its in-memory data structures.
    &lt;ul&gt;
      &lt;li&gt;Read a snapshot at a timestamp to construct;&lt;/li&gt;
      &lt;li&gt;Then incrementally update.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;A directory typically represents a client.
    &lt;ul&gt;
      &lt;li&gt;Most directories contains only 1 fragment.
        &lt;ul&gt;
          &lt;li&gt;Reads and writes are guarantees to happen on a single server. (Note: a Paxos group?)&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;As of 2012, 7 largest directories has 100 to 500 fragments.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Large std of write latencies: Caused by a fat tail due to lock conflicts.&lt;/li&gt;
  &lt;li&gt;Larger std of read latencies: Because Paxos leaders are spread across two data centers, one of them has SSDs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;related-work&quot;&gt;Related work&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Megastore
    &lt;ul&gt;
      &lt;li&gt;Consistent replication across datacenters globally.&lt;/li&gt;
      &lt;li&gt;Semi-relational data model.&lt;/li&gt;
      &lt;li&gt;Similar schema language as Spanner.&lt;/li&gt;
      &lt;li&gt;Not high performance.&lt;/li&gt;
      &lt;li&gt;On top of Bigtable with high communication costs.&lt;/li&gt;
      &lt;li&gt;Not support long-lived leaders.
        &lt;ul&gt;
          &lt;li&gt;Multiple replicas can initiate writes, which can cause unnecessary conflicts in Paxos protocol.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;DynamoDB
    &lt;ul&gt;
      &lt;li&gt;Consistent replication across datacenters within region.&lt;/li&gt;
      &lt;li&gt;Provide a key-value interface.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Database functionality layered on distributed k-v stores.
    &lt;ul&gt;
      &lt;li&gt;But Spanner integrates multiple layers.
        &lt;ul&gt;
          &lt;li&gt;e.g., integrating concurrency control with replication to reduce the cost of commit wait.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Scatter
    &lt;ul&gt;
      &lt;li&gt;A DHT-based k-v store layering transactions on top of consistent replication.&lt;/li&gt;
      &lt;li&gt;Spanner provides a higher-level interface.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Walter
    &lt;ul&gt;
      &lt;li&gt;Snapshot isolation within datacenter.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Calvin, HStroe, Granola
    &lt;ul&gt;
      &lt;li&gt;No external consistency.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;VoltDB
    &lt;ul&gt;
      &lt;li&gt;Not much general replication configurations.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Farsite
    &lt;ul&gt;
      &lt;li&gt;Bounds of clock uncertainty.&lt;/li&gt;
      &lt;li&gt;Much looser than TrueTime’s.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;future-work&quot;&gt;Future work&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Improve monitoring and support tools.&lt;/li&gt;
  &lt;li&gt;Tune performance.&lt;/li&gt;
  &lt;li&gt;Schema language.&lt;/li&gt;
  &lt;li&gt;Automatic maintenance of secondary indices.&lt;/li&gt;
  &lt;li&gt;Automatic load-based resharding.&lt;/li&gt;
  &lt;li&gt;May support optimistically doing reads in parallel.&lt;/li&gt;
  &lt;li&gt;Reduce TrueTime &lt;script type=&quot;math/tex&quot;&gt;\epsilon&lt;/script&gt;, below 1 ms.
    &lt;ul&gt;
      &lt;li&gt;Better clock crystals.&lt;/li&gt;
      &lt;li&gt;Better network.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Improve local data structure in single node to better support SQL queries.&lt;/li&gt;
  &lt;li&gt;Automatically move clients’ application processes between datacenters in response to load changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Combine and extend ideas from two communities:
    &lt;ul&gt;
      &lt;li&gt;Database
        &lt;ul&gt;
          &lt;li&gt;Semi-relational, transactions, SQL query.&lt;/li&gt;
          &lt;li&gt;Bigtable misses some database features.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;System
        &lt;ul&gt;
          &lt;li&gt;Scalability, Automatic sharding, fault tolerance, consistency, wide-area distribution.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;TrueTime
    &lt;ul&gt;
      &lt;li&gt;Enables to build distributed systems with much stronger time semantics.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
    
      <item>
        <title>记忆力抢救日更</title>
        <link>/2019/04/19/tang-poems-300.html</link>
        <guid isPermaLink="true">/2019/04/19/tang-poems-300.html</guid>
        <pubDate>Fri, 19 Apr 2019 00:00:00 +0000</pubDate>
        <description>&lt;p&gt;感觉记忆力有点下降，开一个日更背诗贴，欢迎抽查嘻嘻。&lt;/p&gt;

&lt;h2 id=&quot;20190418&quot;&gt;20190418&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;行宫&lt;/strong&gt;  &lt;br /&gt;
元稹  &lt;br /&gt;
寥落古行宫，&lt;br /&gt;
宫花寂寞红。&lt;br /&gt;
白头宫女在，&lt;br /&gt;
闲坐说玄宗。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;芙蓉楼送辛渐&lt;/strong&gt;&lt;br /&gt;
王昌龄&lt;br /&gt;
寒雨连江夜入吴，&lt;br /&gt;
平明送客楚山孤。&lt;br /&gt;
洛阳亲友如相问，&lt;br /&gt;
一片冰心在玉壶。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;送杜少府之任蜀州&lt;/strong&gt;&lt;br /&gt;
王勃&lt;br /&gt;
城阙辅三秦，风烟望五津。&lt;br /&gt;
与君离别意，同是宦游人。&lt;br /&gt;
海内存知己，天涯若比邻。&lt;br /&gt;
无为在歧路，儿女共沾巾。&lt;/p&gt;

&lt;h2 id=&quot;20190419&quot;&gt;20190419&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;登鹳雀楼&lt;/strong&gt;&lt;br /&gt;
王之涣&lt;br /&gt;
白日依山尽，&lt;br /&gt;
黄河入海流。&lt;br /&gt;
欲穷千里目，&lt;br /&gt;
更上一层楼。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;闺怨&lt;/strong&gt;&lt;br /&gt;
王昌龄&lt;br /&gt;
闺中少妇不知愁，&lt;br /&gt;
春日凝妆上翠楼。&lt;br /&gt;
忽见陌头杨柳色，&lt;br /&gt;
悔教夫婿觅封侯。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;送梓州李使君&lt;/strong&gt;&lt;br /&gt;
王维&lt;br /&gt;
万壑树参天，千山响杜鹃。&lt;br /&gt;
山中一夜雨，树杪百重泉。&lt;br /&gt;
汉女输橦布，巴人讼芋田。&lt;br /&gt;
文翁翻教授，不敢倚先贤。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;新嫁娘词&lt;/strong&gt;&lt;br /&gt;
王建&lt;br /&gt;
三日入厨下，&lt;br /&gt;
洗手作羹汤。&lt;br /&gt;
未谙姑食性，&lt;br /&gt;
先遣小姑尝。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;陋室铭&lt;/strong&gt;&lt;br /&gt;
刘禹锡&lt;br /&gt;
山不在高，有仙则名。水不在深，有龙则灵。斯是陋室，惟吾德馨。&lt;br /&gt;
苔痕上阶绿，草色入帘青。谈笑有鸿儒，往来无白丁。可以调素琴，阅金经。&lt;br /&gt;
无丝竹之乱耳，无案牍之劳形。南阳诸葛庐，西蜀子云亭。&lt;br /&gt;
孔子云，何陋之有？&lt;/p&gt;

&lt;h2 id=&quot;20190420&quot;&gt;20190420&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;相思&lt;/strong&gt;&lt;br /&gt;
王维&lt;br /&gt;
红豆生南国，&lt;br /&gt;
春来发几枝。&lt;br /&gt;
愿君多采撷，&lt;br /&gt;
此物最相思。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;春宫曲&lt;/strong&gt;&lt;br /&gt;
王昌龄&lt;br /&gt;
昨夜风开露井桃，&lt;br /&gt;
未央前殿月轮高。&lt;br /&gt;
平阳歌舞新承宠，&lt;br /&gt;
帘外春寒赐锦袍。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;汉江临眺&lt;/strong&gt;&lt;br /&gt;
王维&lt;br /&gt;
楚塞三湘接，荆门九派通。&lt;br /&gt;
江流天地外，山色有无中。&lt;br /&gt;
郡邑浮前浦，波澜动远空。&lt;br /&gt;
襄阳好风日，留醉与山翁。&lt;/p&gt;

&lt;h2 id=&quot;20190421&quot;&gt;20190421&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;杂诗三首，其二&lt;/strong&gt;&lt;br /&gt;
王维&lt;br /&gt;
君自故乡来，&lt;br /&gt;
应知故乡事。&lt;br /&gt;
来日绮窗前，&lt;br /&gt;
寒梅著花未？&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;九月九日忆山东兄弟&lt;/strong&gt;&lt;br /&gt;
王维&lt;br /&gt;
独在异乡为异客，&lt;br /&gt;
每逢佳节倍思亲。&lt;br /&gt;
遥知兄弟登高处，&lt;br /&gt;
遍插茱萸少一人。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;凉州词二首，其一&lt;/strong&gt;&lt;br /&gt;
王翰&lt;br /&gt;
葡萄美酒夜光杯，&lt;br /&gt;
欲饮琵琶马上催。&lt;br /&gt;
醉卧沙场君莫笑，&lt;br /&gt;
古来征战几人回？&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;终南别业&lt;/strong&gt;&lt;br /&gt;
王维&lt;br /&gt;
中岁颇好道，晚家南山陲。&lt;br /&gt;
兴来每独往，胜事空自知。&lt;br /&gt;
行到水穷处，坐看云起时。&lt;br /&gt;
偶然值林叟，谈笑无还期。&lt;/p&gt;

&lt;h2 id=&quot;20190422&quot;&gt;20190422&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;鹿柴&lt;/strong&gt;&lt;br /&gt;
王维&lt;br /&gt;
空山不见人，&lt;br /&gt;
但闻人语响。&lt;br /&gt;
返景入深林，&lt;br /&gt;
复照青苔上。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;后宫词&lt;/strong&gt;&lt;br /&gt;
白居易&lt;br /&gt;
泪湿罗巾梦不成，&lt;br /&gt;
夜半前殿按歌声。&lt;br /&gt;
红颜未老恩先断，&lt;br /&gt;
斜倚薰笼坐到明。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;终南山&lt;/strong&gt;&lt;br /&gt;
王维&lt;br /&gt;
太乙近天都，连山接海隅。&lt;br /&gt;
白云回望合，青霭入看无。&lt;br /&gt;
分野中峰变，阴晴万壑殊。&lt;br /&gt;
欲投人处宿，隔水问樵夫。&lt;/p&gt;

&lt;h2 id=&quot;20190423&quot;&gt;20190423&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;竹里馆&lt;/strong&gt;&lt;br /&gt;
王维&lt;br /&gt;
独坐幽篁里，&lt;br /&gt;
弹琴复长啸。&lt;br /&gt;
深林人不知，&lt;br /&gt;
明月来相照。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;宫词&lt;/strong&gt;&lt;br /&gt;
朱庆馀&lt;br /&gt;
寂寂花时闭院门，&lt;br /&gt;
美人相并立琼轩。&lt;br /&gt;
含情欲说宫中事，&lt;br /&gt;
鹦鹉前头不敢言。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;酬张少府&lt;/strong&gt;&lt;br /&gt;
王维&lt;br /&gt;
晚年唯好静，万事不关心。&lt;br /&gt;
自顾无长策，空知返旧林。&lt;br /&gt;
松风吹解带，山月照弹琴。&lt;br /&gt;
君问穷通理，渔歌入浦深。&lt;/p&gt;

&lt;h2 id=&quot;20190424&quot;&gt;20190424&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;送别&lt;/strong&gt;&lt;br /&gt;
王维&lt;br /&gt;
山中相送罢，&lt;br /&gt;
日暮掩柴扉。&lt;br /&gt;
春草明年绿，&lt;br /&gt;
王孙归不归？&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;近试上张水部&lt;/strong&gt;&lt;br /&gt;
朱庆馀&lt;br /&gt;
洞房昨夜停红烛，&lt;br /&gt;
待晓堂前拜舅姑。&lt;br /&gt;
妆罢低声问夫婿，&lt;br /&gt;
画眉深浅入时无。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;过香积寺&lt;/strong&gt;&lt;br /&gt;
王维&lt;br /&gt;
不知香积寺，数里入云峰。&lt;br /&gt;
古木无人径，深山何处钟。&lt;br /&gt;
泉声咽危石，日色冷青松。&lt;br /&gt;
薄暮空潭曲，安禅制毒龙。&lt;/p&gt;

&lt;h2 id=&quot;20190425&quot;&gt;20190425&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;问刘十九&lt;/strong&gt;&lt;br /&gt;
白居易&lt;br /&gt;
绿蚁新醅酒，&lt;br /&gt;
红泥小火炉。&lt;br /&gt;
晚来天欲雪，&lt;br /&gt;
能饮一杯无？&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;逢入京使&lt;/strong&gt;&lt;br /&gt;
岑参&lt;br /&gt;
故园东望路漫漫，&lt;br /&gt;
双袖龙钟泪不干。&lt;br /&gt;
马上相逢无纸笔，&lt;br /&gt;
凭君传语报平安。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;辋川闲居赠裴秀才迪&lt;/strong&gt;&lt;br /&gt;
王维&lt;br /&gt;
寒山转苍翠，秋水日潺湲。&lt;br /&gt;
倚杖柴门外，临风听暮蝉。&lt;br /&gt;
渡头馀落日，墟里上孤烟。&lt;br /&gt;
复值接舆醉，狂歌五柳前。&lt;/p&gt;

&lt;h2 id=&quot;20190426&quot;&gt;20190426&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;哥舒歌&lt;/strong&gt;&lt;br /&gt;
西鄙人&lt;br /&gt;
北斗七星高，&lt;br /&gt;
哥舒夜带刀。&lt;br /&gt;
至今窥牧马，&lt;br /&gt;
不敢过临洮。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;黄鹤楼送孟浩然之广陵&lt;/strong&gt;&lt;br /&gt;
李白&lt;br /&gt;
故人西辞黄鹤楼，&lt;br /&gt;
烟花三月下扬州。&lt;br /&gt;
孤帆远影碧空尽，&lt;br /&gt;
唯见长江天际流。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;山居秋暝&lt;/strong&gt;&lt;br /&gt;
王维&lt;br /&gt;
空山新雨后，天气晚来秋。&lt;br /&gt;
明月松间照，清泉石上流。&lt;br /&gt;
竹喧归浣女，莲动下渔舟。&lt;br /&gt;
随意春芳歇，王孙自可留。&lt;/p&gt;

&lt;h2 id=&quot;20190427&quot;&gt;20190427&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;静夜思&lt;/strong&gt;&lt;br /&gt;
李白&lt;br /&gt;
窗前明月光，&lt;br /&gt;
疑是地上霜。&lt;br /&gt;
举头望明月，&lt;br /&gt;
低头思故乡。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;怨情&lt;/strong&gt;&lt;br /&gt;
李白&lt;br /&gt;
美人卷珠帘，&lt;br /&gt;
深坐颦蛾眉。&lt;br /&gt;
但见泪痕湿，&lt;br /&gt;
不知心恨谁。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;早发白帝城&lt;/strong&gt;&lt;br /&gt;
李白&lt;br /&gt;
朝辞白帝彩云间，&lt;br /&gt;
千里江陵一日还。&lt;br /&gt;
两岸猿声啼不住，&lt;br /&gt;
轻舟已过万重山。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;夜上受降城闻笛&lt;/strong&gt;&lt;br /&gt;
李益&lt;br /&gt;
回乐峰前沙似雪，&lt;br /&gt;
受降城外月如霜。&lt;br /&gt;
不知何处吹芦管，&lt;br /&gt;
一夜征人尽望乡。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;归嵩山作&lt;/strong&gt;&lt;br /&gt;
王维&lt;br /&gt;
清川带长薄，车马去闲闲。&lt;br /&gt;
流水如有意，暮禽相与还。&lt;br /&gt;
荒城临古渡，落日满秋山。&lt;br /&gt;
迢递嵩高下，归来且闭关。&lt;/p&gt;

&lt;h2 id=&quot;20190428&quot;&gt;20190428&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;乐游原&lt;/strong&gt;&lt;br /&gt;
李商隐&lt;br /&gt;
向晚意不适，&lt;br /&gt;
驱车登古原。&lt;br /&gt;
夕阳无限好，&lt;br /&gt;
只是近黄昏。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;听筝&lt;/strong&gt;&lt;br /&gt;
李端&lt;br /&gt;
鸣筝金粟柱，&lt;br /&gt;
素手玉房前。&lt;br /&gt;
欲得周郎顾，&lt;br /&gt;
时时误拂弦。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;贾生&lt;/strong&gt;&lt;br /&gt;
李商隐&lt;br /&gt;
宣室求贤访逐臣，&lt;br /&gt;
贾生才调更无论。&lt;br /&gt;
可怜夜半虚前席，&lt;br /&gt;
不问苍生问鬼神。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;次北固山下&lt;/strong&gt;&lt;br /&gt;
王湾 &lt;br /&gt;
客路青山外，行舟绿水前。&lt;br /&gt;
潮平两岸阔，风正一帆悬。&lt;br /&gt;
海日生残夜，江春入旧年，&lt;br /&gt;
乡书何处达，归雁洛阳边。&lt;/p&gt;

&lt;h2 id=&quot;20190429&quot;&gt;20190429&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;渡汉江&lt;/strong&gt;&lt;br /&gt;
宋之问&lt;br /&gt;
岭外音书断，&lt;br /&gt;
经冬又复春。&lt;br /&gt;
近乡情更怯，&lt;br /&gt;
不敢问来人。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;隋宫&lt;/strong&gt;&lt;br /&gt;
李商隐&lt;br /&gt;
乘兴南游不戒严，&lt;br /&gt;
九重谁省谏书函。&lt;br /&gt;
春风举国裁宫锦，&lt;br /&gt;
半作障泥半作帆。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;云阳馆与韩绅宿别&lt;/strong&gt;&lt;br /&gt;
司空曙&lt;br /&gt;
故人江海别，几度隔山川。&lt;br /&gt;
乍见翻疑梦，相悲各问年。&lt;br /&gt;
孤灯寒照雨，深竹暗浮烟。&lt;br /&gt;
更有明朝恨，离杯惜共传。&lt;/p&gt;

&lt;h2 id=&quot;20190430&quot;&gt;20190430&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;八阵图&lt;/strong&gt;&lt;br /&gt;
杜甫&lt;br /&gt;
功盖三分国，&lt;br /&gt;
名成八阵图。&lt;br /&gt;
江流石不转，&lt;br /&gt;
遗恨失吞吴。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;瑶池&lt;/strong&gt;&lt;br /&gt;
李商隐&lt;br /&gt;
瑶池阿母绮窗开，&lt;br /&gt;
黄竹歌声动地哀。&lt;br /&gt;
八骏日行三万里，&lt;br /&gt;
穆王何事不重来。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;喜外弟卢纶见宿&lt;/strong&gt;&lt;br /&gt;
司空曙&lt;br /&gt;
静夜四无邻，荒居旧业贫。&lt;br /&gt;
雨中黄叶树，灯下白头人。&lt;br /&gt;
以我独沉久，愧君相见频。&lt;br /&gt;
平生自有分，况是蔡家亲。&lt;/p&gt;

&lt;h2 id=&quot;20190501&quot;&gt;20190501&lt;/h2&gt;

&lt;p&gt;宿建德江&lt;br /&gt;
孟浩然&lt;br /&gt;
移舟泊烟渚，&lt;br /&gt;
日暮客愁新。&lt;br /&gt;
野旷天低树，&lt;br /&gt;
江清月近人。&lt;/p&gt;

&lt;p&gt;嫦娥&lt;br /&gt;
李商隐&lt;br /&gt;
云母屏风烛影深，&lt;br /&gt;
长河渐落晓星沉。&lt;br /&gt;
嫦娥应悔偷灵药，&lt;br /&gt;
碧海青天夜夜心。&lt;/p&gt;

&lt;p&gt;贼平后送人北归&lt;br /&gt;
司空曙&lt;br /&gt;
世乱同南去，时清独北还。&lt;br /&gt;
他乡生白发，旧国见青山。&lt;br /&gt;
晓月过残垒，繁星宿故关。&lt;br /&gt;
寒禽与衰草，处处伴愁颜。&lt;/p&gt;

&lt;h2 id=&quot;20190502&quot;&gt;20190502&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;春晓&lt;/strong&gt;&lt;br /&gt;
孟浩然&lt;br /&gt;
春眠不觉晓，&lt;br /&gt;
处处闻啼鸟。&lt;br /&gt;
夜来风雨声，&lt;br /&gt;
花落知多少。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;春怨&lt;/strong&gt;&lt;br /&gt;
金昌绪&lt;br /&gt;
打起黄莺儿，&lt;br /&gt;
莫教枝上啼。&lt;br /&gt;
啼时惊妾梦，&lt;br /&gt;
不得到辽西。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;夜雨寄北&lt;/strong&gt;&lt;br /&gt;
李商隐&lt;br /&gt;
君问归期未有期，&lt;br /&gt;
巴山夜雨涨秋池。&lt;br /&gt;
何当共剪西窗烛，&lt;br /&gt;
却话巴山夜雨时。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;赋得古原草送别&lt;/strong&gt;&lt;br /&gt;
白居易&lt;br /&gt;
离离原上草，一岁一枯荣。&lt;br /&gt;
野火烧不尽，春风吹又生。&lt;br /&gt;
远芳侵古道，晴翠接荒城。&lt;br /&gt;
又送王孙去，萋萋满别情。&lt;/p&gt;

&lt;h2 id=&quot;20190503&quot;&gt;20190503&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;江雪&lt;/strong&gt;&lt;br /&gt;
柳宗元&lt;br /&gt;
千山鸟飞绝，&lt;br /&gt;
万径人踪灭。&lt;br /&gt;
孤舟蓑笠翁，&lt;br /&gt;
独钓寒江雪。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;秋夜寄邱员外&lt;/strong&gt;&lt;br /&gt;
韦应物&lt;br /&gt;
怀君属秋夜，&lt;br /&gt;
散步咏凉天。&lt;br /&gt;
空山松子落，&lt;br /&gt;
幽人应未眠。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;寄令狐郎中&lt;/strong&gt;&lt;br /&gt;
李商隐&lt;br /&gt;
嵩云秦树久离居，&lt;br /&gt;
双鲤迢迢一纸书。&lt;br /&gt;
莫问梁园旧宾客，&lt;br /&gt;
茂陵秋雨病相如。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;题大庾岭北驿&lt;/strong&gt;&lt;br /&gt;
宋之问&lt;br /&gt;
阳月南飞雁，传闻至此回。&lt;br /&gt;
我行殊未已，何日复归来。&lt;br /&gt;
江静潮初落，林昏瘴未开。&lt;br /&gt;
明朝望乡处，应见陇头梅。&lt;/p&gt;

&lt;h2 id=&quot;20190504&quot;&gt;20190504&lt;/h2&gt;

&lt;p&gt;终南望余雪&lt;br /&gt;
祖咏&lt;br /&gt;
终南阴岭秀，&lt;br /&gt;
积雪浮云端。&lt;br /&gt;
林表明霁色，&lt;br /&gt;
城中增暮寒。&lt;/p&gt;

&lt;p&gt;为有&lt;br /&gt;
李商隐&lt;br /&gt;
为有云屏无限娇，&lt;br /&gt;
凤城寒尽怕春宵。&lt;br /&gt;
无端嫁得金龟婿，&lt;br /&gt;
辜负香衾事早朝。&lt;/p&gt;

&lt;p&gt;寄左省杜拾遗&lt;br /&gt;
岑参&lt;br /&gt;
联步趋丹陛，分曹限紫微。&lt;br /&gt;
晓随天仗入，暮惹御香归。&lt;br /&gt;
白发悲花落，青云羡鸟飞。&lt;br /&gt;
圣朝无阙事，自觉谏书稀。&lt;/p&gt;

&lt;h2 id=&quot;20190505&quot;&gt;20190505&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;宫词&lt;/strong&gt;&lt;br /&gt;
张祜&lt;br /&gt;
故国三千里，&lt;br /&gt;
深宫二十年。&lt;br /&gt;
一声何满子，&lt;br /&gt;
双泪落君前。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;江南逢李龟年&lt;/strong&gt;&lt;br /&gt;
杜甫&lt;br /&gt;
岐王宅里寻常见，&lt;br /&gt;
崔九堂前几度闻。&lt;br /&gt;
正是江南好风景，&lt;br /&gt;
落花时节又逢君。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;赠别&lt;/strong&gt;&lt;br /&gt;
杜牧&lt;br /&gt;
多情却似总无情，&lt;br /&gt;
唯觉樽前笑不成。&lt;br /&gt;
蜡烛有心还惜别，&lt;br /&gt;
替人垂泪到天明。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;听蜀僧濬弹琴&lt;/strong&gt;&lt;br /&gt;
李白&lt;br /&gt;
蜀僧抱绿绮，西下峨眉峰。&lt;br /&gt;
为我一挥手，如听万壑松。&lt;br /&gt;
客心洗流水，余响入霜钟。&lt;br /&gt;
不觉碧山暮，秋云暗几重。&lt;/p&gt;

&lt;h2 id=&quot;20190506&quot;&gt;20190506&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;寻隐者不遇&lt;/strong&gt;&lt;br /&gt;
贾岛&lt;br /&gt;
松下问童子，&lt;br /&gt;
言师采药去。&lt;br /&gt;
只在此山中，&lt;br /&gt;
云深不知处。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;送崔九&lt;/strong&gt;&lt;br /&gt;
裴迪&lt;br /&gt;
归山深浅去，&lt;br /&gt;
须尽丘壑美。&lt;br /&gt;
莫学武陵人，&lt;br /&gt;
暂游桃源里。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;赠别其二&lt;/strong&gt;&lt;br /&gt;
杜牧&lt;br /&gt;
娉娉袅袅十三余，&lt;br /&gt;
豆蔻梢头二月初。&lt;br /&gt;
春风十里扬州路，&lt;br /&gt;
卷上珠帘总不如。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;夜泊牛渚怀古&lt;/strong&gt;&lt;br /&gt;
李白&lt;br /&gt;
牛渚西江夜，青天无片云。&lt;br /&gt;
登舟望秋月，空忆谢将军。&lt;br /&gt;
余亦能高咏，斯人不可闻。&lt;br /&gt;
明朝挂帆席，枫叶落纷纷。&lt;/p&gt;

&lt;h2 id=&quot;20190507&quot;&gt;20190507&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;送灵澈上人&lt;/strong&gt;&lt;br /&gt;
刘长卿&lt;br /&gt;
苍苍竹林寺，&lt;br /&gt;
杳杳钟声晚。&lt;br /&gt;
荷笠带斜阳，&lt;br /&gt;
青山独归远。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;金谷园&lt;/strong&gt;&lt;br /&gt;
杜牧&lt;br /&gt;
繁华事散逐香尘，&lt;br /&gt;
流水无情草自春。&lt;br /&gt;
日暮东风怨啼鸟，&lt;br /&gt;
落花犹似坠楼人。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;赠孟浩然&lt;/strong&gt;&lt;br /&gt;
李白&lt;br /&gt;
吾爱孟夫子，风流天下闻。&lt;br /&gt;
红颜弃轩冕，白首卧松云。&lt;br /&gt;
醉月频中圣，迷花不事君。&lt;br /&gt;
高山安可仰，徒此揖清芬。&lt;/p&gt;

&lt;h2 id=&quot;20190508&quot;&gt;20190508&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;听弹琴&lt;/strong&gt;&lt;br /&gt;
刘长卿&lt;br /&gt;
泠泠七弦上，&lt;br /&gt;
静听松风寒。&lt;br /&gt;
古调虽自爱，&lt;br /&gt;
今人多不弹。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;寄扬州韩绰判官&lt;/strong&gt;&lt;br /&gt;
杜牧&lt;br /&gt;
青山隐隐水迢迢，&lt;br /&gt;
秋尽江南草未凋。&lt;br /&gt;
二十四桥明月夜，&lt;br /&gt;
玉人何处教吹箫。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;渡荆门送别&lt;/strong&gt;&lt;br /&gt;
李白&lt;br /&gt;
渡远荆门外，来从楚国游。&lt;br /&gt;
山随平野尽，江入大荒流。&lt;br /&gt;
月下飞天镜，云生结海楼。&lt;br /&gt;
仍怜故乡水，万里送行舟。&lt;/p&gt;

&lt;h2 id=&quot;20190509&quot;&gt;20190509&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;送上人&lt;/strong&gt;&lt;br /&gt;
刘长卿&lt;br /&gt;
孤云将野鹤，&lt;br /&gt;
岂往人间住。&lt;br /&gt;
莫买沃洲山，&lt;br /&gt;
时人已知处。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;遣怀&lt;/strong&gt;&lt;br /&gt;
杜牧&lt;br /&gt;
落魄江南载酒行，&lt;br /&gt;
楚腰纤细掌中轻。&lt;br /&gt;
十年一觉扬州梦，&lt;br /&gt;
赢得青楼薄幸名。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;送友人&lt;/strong&gt;&lt;br /&gt;
李白&lt;br /&gt;
青山横北郭，白水绕东城。&lt;br /&gt;
此地一为别，孤蓬万里征。&lt;br /&gt;
浮云游子意，落日故人情。&lt;br /&gt;
挥手自兹去，萧萧班马鸣。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;蜀道难&lt;/strong&gt;&lt;br /&gt;
李白&lt;br /&gt;
噫吁嚱，危乎高哉。蜀道之难，难于上青天。&lt;br /&gt;
蚕丛及鱼凫，开国何茫然。&lt;br /&gt;
尔来四万八千岁，不与秦塞通人烟。&lt;br /&gt;
西当太白有鸟道，可以横绝峨眉巅。&lt;br /&gt;
地崩山摧壮士死，然后天梯石栈相钩连。&lt;br /&gt;
上有六龙回日之高标，下有冲波逆折之回川。&lt;br /&gt;
黄鹤之飞尚不得过，猿猱欲度愁攀援。&lt;br /&gt;
青泥何盘盘，百步九折萦岩峦。&lt;br /&gt;
扪参历井仰胁息，以手抚膺坐长叹。&lt;br /&gt;
问君西游何时还，畏途巉岩不可攀。&lt;br /&gt;
但见悲鸟号古木，雄飞雌从绕林间。&lt;br /&gt;
又闻子规啼夜月，愁空山。&lt;br /&gt;
蜀道之难，难以上青天。使人听此凋朱颜。&lt;br /&gt;
连峰去天不盈尺，枯松倒挂倚绝壁。&lt;br /&gt;
飞湍瀑流争喧豗，砯崖转石万壑雷。&lt;br /&gt;
其险也若此，嗟尔远道之人，胡为乎来哉。&lt;br /&gt;
剑阁峥嵘而崔嵬，一夫当关，万夫莫开。&lt;br /&gt;
其守或匪亲，化为狼与豺。&lt;br /&gt;
朝避猛虎，夕避长蛇，磨牙吮血，杀人如麻。&lt;br /&gt;
锦城虽云乐，不如早还家。&lt;br /&gt;
蜀道之难，难于上青天。侧身西望长咨嗟。&lt;/p&gt;

&lt;h2 id=&quot;20190510&quot;&gt;20190510&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;玉台体&lt;/strong&gt;&lt;br /&gt;
权德舆&lt;br /&gt;
昨夜裙带解，&lt;br /&gt;
今朝蟢子飞。&lt;br /&gt;
铅华不可弃，&lt;br /&gt;
莫是藁砧归。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;秋夕&lt;/strong&gt;&lt;br /&gt;
杜牧&lt;br /&gt;
银烛秋光冷画屏，&lt;br /&gt;
轻罗小扇扑流萤。&lt;br /&gt;
天阶夜色凉如水，&lt;br /&gt;
卧看牵牛织女星。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;喜见外弟又言别&lt;/strong&gt;&lt;br /&gt;
李益&lt;br /&gt;
十年离乱后，长大一相逢。&lt;br /&gt;
问姓惊初见，称名忆旧容。&lt;br /&gt;
别来沧海事，语罢暮天钟。&lt;br /&gt;
明日巴陵道，秋山又几重。&lt;/p&gt;

&lt;h2 id=&quot;20190511&quot;&gt;20190511&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;将赴吴兴登乐游原一绝&lt;/strong&gt;&lt;br /&gt;
杜牧&lt;br /&gt;
清时有味是无能，&lt;br /&gt;
闲爱孤云静爱僧。&lt;br /&gt;
欲把一麾江海去，&lt;br /&gt;
乐游原上望昭陵。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;凉思&lt;/strong&gt;&lt;br /&gt;
李商隐&lt;br /&gt;
客去波平槛，蝉休露满枝。&lt;br /&gt;
永怀当此节，倚立自移时。&lt;br /&gt;
北斗兼春远，南陵寓使迟。&lt;br /&gt;
天涯占梦数，疑误有新知。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;酬郭给事&lt;/strong&gt;&lt;br /&gt;
王维&lt;br /&gt;
洞门高阁霭馀辉，桃李阴阴柳絮飞。&lt;br /&gt;
禁里疏钟官舍晚，省中啼鸟吏人稀。&lt;br /&gt;
晨摇玉佩趋金殿，夕奉天书拜琐闱。&lt;br /&gt;
强欲从君无那老，将因卧病解朝衣.&lt;/p&gt;

&lt;h2 id=&quot;20190512&quot;&gt;20190512&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;赤壁&lt;/strong&gt;&lt;br /&gt;
杜牧&lt;br /&gt;
折戟沉沙铁未销，&lt;br /&gt;
自将磨洗认前朝。&lt;br /&gt;
东风不与周郎便，&lt;br /&gt;
铜雀春深锁二乔。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;北青萝&lt;/strong&gt;&lt;br /&gt;
李商隐&lt;br /&gt;
残阳西入崦，茅屋访孤僧。&lt;br /&gt;
落叶人何在，寒云路几层。&lt;br /&gt;
独敲初夜磬，闲倚一枝藤。&lt;br /&gt;
世界微尘里，吾宁爱与憎。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;和贾舍人早朝大明宫之作&lt;/strong&gt;&lt;br /&gt;
王维&lt;br /&gt;
绛帻鸡人送晓筹，尚衣方进翠云裘。&lt;br /&gt;
九天阊阖开宫殿，万国衣冠拜冕旈。&lt;br /&gt;
日色才临仙掌动，香烟欲傍衮龙浮。&lt;br /&gt;
朝罢须裁五色诏，佩声归向凤池头。&lt;/p&gt;

&lt;h2 id=&quot;20190513&quot;&gt;20190513&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;泊秦淮&lt;/strong&gt;&lt;br /&gt;
杜牧&lt;br /&gt;
烟笼寒水月笼沙，&lt;br /&gt;
夜泊秦淮近酒家。&lt;br /&gt;
商女不知亡国恨，&lt;br /&gt;
隔江犹唱后庭花。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;蝉&lt;/strong&gt;&lt;br /&gt;
李商隐&lt;br /&gt;
本以高难饱，徒劳恨费声。&lt;br /&gt;
五更疏欲断，一树碧无情。&lt;br /&gt;
薄宦梗犹泛，故园芜已平。&lt;br /&gt;
烦君最相警，我亦举家清。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;奉和圣制从蓬莱向兴庆阁官道留春雨中春望之作应制&lt;/strong&gt;&lt;br /&gt;
王维&lt;br /&gt;
渭水自萦秦塞曲，黄山旧绕汉宫斜。&lt;br /&gt;
銮舆迥出千门柳，阁道回看上苑花。&lt;br /&gt;
云里帝城双凤阙，雨中春树万人家。&lt;br /&gt;
为乘阳气行时令，不是宸游玩物华。&lt;/p&gt;

&lt;h2 id=&quot;20190514&quot;&gt;20190514&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;征人怨&lt;/strong&gt;&lt;br /&gt;
柳中庸&lt;br /&gt;
岁岁金河复玉关，&lt;br /&gt;
朝朝马策与刀环。&lt;br /&gt;
三春白雪归青冢，&lt;br /&gt;
万里黄河绕黑山。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;风雨&lt;/strong&gt;&lt;br /&gt;
李商隐&lt;br /&gt;
凄凉宝剑篇，羁泊欲穷年。&lt;br /&gt;
黄叶仍风雨，青楼自管弦。&lt;br /&gt;
新知遭薄俗，旧好隔良缘。&lt;br /&gt;
心断新丰酒，销愁斗几千。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;积雨辋川庄作&lt;/strong&gt;&lt;br /&gt;
王维&lt;br /&gt;
积雨空林烟火迟，蒸藜炊黍饷东菑。&lt;br /&gt;
漠漠水田飞白鹭，阴阴夏木啭黄鹂。&lt;br /&gt;
山中习静观朝槿，松下清斋折露葵。&lt;br /&gt;
野老与人争席罢，海鸥何事更相疑。&lt;/p&gt;

&lt;h2 id=&quot;20190515&quot;&gt;20190515&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;金陵图&lt;/strong&gt;&lt;br /&gt;
韦庄&lt;br /&gt;
谁谓伤心画不成，&lt;br /&gt;
画人心逐世人情。&lt;br /&gt;
君看六幅南朝事，&lt;br /&gt;
老木寒云满故城。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;落花&lt;/strong&gt;&lt;br /&gt;
李商隐&lt;br /&gt;
高阁客竟去，小园花乱飞。&lt;br /&gt;
参差连曲陌，迢递送斜晖。&lt;br /&gt;
肠断未忍扫，眼穿仍欲归。&lt;br /&gt;
芳心向春尽，所得是沾衣。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;望月有感&lt;/strong&gt;&lt;br /&gt;
白居易&lt;br /&gt;
时难年荒世业空，弟兄羁旅各西东。&lt;br /&gt;
田园寥落干戈后，骨肉流离道路中。&lt;br /&gt;
吊影分为千里雁，辞根散作九秋蓬。&lt;br /&gt;
共看明月应垂泪，一夜乡心五处同。&lt;/p&gt;

&lt;h2 id=&quot;20190516&quot;&gt;20190516&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;滁州西涧&lt;/strong&gt;&lt;br /&gt;
韦应物&lt;br /&gt;
独怜幽草涧边生，&lt;br /&gt;
上有黄鹂深树鸣。&lt;br /&gt;
春潮带雨晚来急，&lt;br /&gt;
野渡无人舟自横。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;登岳阳楼&lt;/strong&gt;&lt;br /&gt;
杜甫&lt;br /&gt;
昔闻洞庭水，今上岳阳楼。&lt;br /&gt;
吴楚东南坼，乾坤日月浮。&lt;br /&gt;
亲朋无一字，老病有孤舟。&lt;br /&gt;
戎马关山北，凭轩涕泗流。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;奉和中书舍人贾至早朝大明宫&lt;/strong&gt;&lt;br /&gt;
岑参&lt;br /&gt;
鸡鸣紫陌曙光寒，莺啭皇州春色阑。&lt;br /&gt;
金阙晓钟开万户，玉阶仙仗拥千官。&lt;br /&gt;
花迎剑珮星初落，柳拂旌旗露未干。&lt;br /&gt;
独有凤凰池上客，阳春一曲和皆难。&lt;/p&gt;

&lt;h2 id=&quot;20190517&quot;&gt;20190517&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;桃花溪&lt;/strong&gt;&lt;br /&gt;
张旭&lt;br /&gt;
隐隐飞桥隔野烟，&lt;br /&gt;
石矶西畔问渔船。&lt;br /&gt;
桃花尽日随流水，&lt;br /&gt;
洞在清溪何处边。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;奉济驿重送严公四韵&lt;/strong&gt;&lt;br /&gt;
杜甫&lt;br /&gt;
远送从此别，青山空复情。&lt;br /&gt;
几时杯重把，昨夜月同行。&lt;br /&gt;
列郡讴歌惜，三朝出入荣。&lt;br /&gt;
江村独归处，寂寞养残生。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;登金陵凤凰台&lt;/strong&gt;&lt;br /&gt;
李白&lt;br /&gt;
凤凰台上凤凰游，凤去台空江自流。&lt;br /&gt;
吴宫花草埋幽径，晋代衣冠成古丘。&lt;br /&gt;
三山半落青天外，二水中分白鹭洲。&lt;br /&gt;
总为浮云能蔽日，长安不见使人愁。&lt;/p&gt;

&lt;h2 id=&quot;20190518&quot;&gt;20190518&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;寄人&lt;/strong&gt;&lt;br /&gt;
张泌&lt;br /&gt;
别梦依依到谢家，&lt;br /&gt;
小廊回合曲阑斜。&lt;br /&gt;
多情只是春庭月，&lt;br /&gt;
犹为离人照落花。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;别房太尉墓&lt;/strong&gt;&lt;br /&gt;
杜甫&lt;br /&gt;
他乡复行役，驻马别孤坟。&lt;br /&gt;
近泪无干土，低空有断云。&lt;br /&gt;
对棋陪谢傅，把剑觅徐君。&lt;br /&gt;
唯见林花落，莺啼送客闻。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;无题 重帏深下莫愁堂&lt;/strong&gt;&lt;br /&gt;
李商隐&lt;br /&gt;
重帏深下莫愁堂，卧后清宵细细长。&lt;br /&gt;
神女生涯原是梦，小姑居处本无郎。&lt;br /&gt;
风波不信菱枝弱，月露谁教桂叶香。&lt;br /&gt;
直道相思了无益，未妨惆怅是轻狂。&lt;/p&gt;

&lt;h2 id=&quot;20190519&quot;&gt;20190519&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;题金陵渡&lt;/strong&gt;&lt;br /&gt;
张祜&lt;br /&gt;
金陵津渡小山楼，&lt;br /&gt;
一宿行人自可愁。&lt;br /&gt;
潮落夜江斜月里，&lt;br /&gt;
两三星火是瓜洲。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;旅夜书怀&lt;/strong&gt;&lt;br /&gt;
杜甫&lt;br /&gt;
细草微风岸，危樯独夜舟。&lt;br /&gt;
星垂平野阔，月涌大江流。&lt;br /&gt;
名岂文章著，官应老病休。&lt;br /&gt;
飘飘何所似，天地一沙鸥。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;无题 凤尾香罗薄几重&lt;/strong&gt;&lt;br /&gt;
李商隐&lt;br /&gt;
凤尾香罗薄几重，碧文圆顶夜深缝。&lt;br /&gt;
扇裁月魄羞难掩，车走雷声语未通。&lt;br /&gt;
曾是寂寥金烬暗，断无消息石榴红。&lt;br /&gt;
斑骓只系垂杨岸，何处西南任好风。&lt;/p&gt;

&lt;h2 id=&quot;20190520&quot;&gt;20190520&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;赠内人&lt;/strong&gt;&lt;br /&gt;
张祜&lt;br /&gt;
禁门宫树月痕过，&lt;br /&gt;
媚眼惟看宿鹭窠。&lt;br /&gt;
斜拔玉钗灯影畔，&lt;br /&gt;
剔开红焰救飞蛾。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;至德二载甫自京金光门出问道归凤翔乾元初从左拾遗移华州掾与亲故别因出此门有悲往事&lt;/strong&gt;&lt;br /&gt;
杜甫&lt;br /&gt;
此道昔归顺，西郊胡正繁。&lt;br /&gt;
至今残破胆，应有未招魂。&lt;br /&gt;
近得归京邑，移官岂至尊。&lt;br /&gt;
无才日衰老，驻马望千门。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;无题 相见时难别亦难&lt;/strong&gt;&lt;br /&gt;
李商隐&lt;br /&gt;
相见时难别亦难，东风无力百花残。&lt;br /&gt;
春蚕到死丝方尽，蜡炬成灰泪始干。&lt;br /&gt;
晓镜但愁云鬓改，夜吟应觉月光寒。&lt;br /&gt;
蓬山此去无多路，青鸟殷勤为探看。&lt;/p&gt;

&lt;h2 id=&quot;20190521&quot;&gt;20190521&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;集灵台 其一&lt;/strong&gt;&lt;br /&gt;
张祜&lt;br /&gt;
日光斜照集灵台，&lt;br /&gt;
红树花迎晓露开。&lt;br /&gt;
昨夜上皇新授箓，&lt;br /&gt;
太真含笑入帘来。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;月夜忆舍弟&lt;/strong&gt;&lt;br /&gt;
杜甫&lt;br /&gt;
戍鼓断人行，边秋一雁声。&lt;br /&gt;
露从今夜白，月是故乡明。&lt;br /&gt;
有弟皆分散，无家问死生。&lt;br /&gt;
寄书长不达，况乃未休兵。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;无题&lt;/strong&gt;&lt;br /&gt;
李商隐&lt;br /&gt;
来是空言去绝踪，月斜楼上五更钟。&lt;br /&gt;
梦为远别啼难唤，书被催成墨未浓。&lt;br /&gt;
蜡照半笼金翡翠，麝熏微度绣芙蓉。&lt;br /&gt;
刘郎已恨蓬山远，更隔蓬山一万重。&lt;/p&gt;

&lt;h2 id=&quot;20190522&quot;&gt;20190522&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;集灵台 其二&lt;/strong&gt;&lt;br /&gt;
张祜&lt;br /&gt;
虢国夫人承主恩，&lt;br /&gt;
平明骑马入宫门。&lt;br /&gt;
却嫌脂粉污颜色，&lt;br /&gt;
淡扫蛾眉朝至尊。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;天末怀李白&lt;/strong&gt;&lt;br /&gt;
杜甫&lt;br /&gt;
凉风起天末，君子意如何。&lt;br /&gt;
鸿雁几时到，江湖秋水多。&lt;br /&gt;
文章憎命达，魑魅喜人过。&lt;br /&gt;
应共冤魂语，投诗赠汨罗。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;无题&lt;/strong&gt;&lt;br /&gt;
李商隐&lt;br /&gt;
飒飒东风细雨来，芙蓉塘外有轻雷。&lt;br /&gt;
金蟾噬锁烧香入，玉虎牵丝汲井回。&lt;br /&gt;
贾氏窥帘韩掾少，宓妃留枕魏王才。&lt;br /&gt;
春心莫共花争发，一寸相思一寸灰。&lt;/p&gt;

&lt;h2 id=&quot;20190523&quot;&gt;20190523&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;枫桥夜泊&lt;/strong&gt;&lt;br /&gt;
张继&lt;br /&gt;
月落乌啼霜满天，&lt;br /&gt;
江枫渔火对愁眠。&lt;br /&gt;
姑苏城外寒山寺，&lt;br /&gt;
夜半钟声到客船。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;月夜&lt;/strong&gt;&lt;br /&gt;
杜甫&lt;br /&gt;
今夜鄜州月，闺中只独看。&lt;br /&gt;
遥怜小儿女，未解忆长安。&lt;br /&gt;
香雾云鬟湿，清辉玉臂寒。&lt;br /&gt;
何时倚虚幌，双照泪痕干。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;无题&lt;/strong&gt;&lt;br /&gt;
李商隐&lt;br /&gt;
昨夜星辰昨夜风，画楼西畔桂堂东。&lt;br /&gt;
身无彩凤双飞翼，心有灵犀一点通。&lt;br /&gt;
隔座送钩春酒暖，分曹射覆蜡灯红。&lt;br /&gt;
嗟余听鼓应官去，走马兰台类转蓬。&lt;/p&gt;

&lt;h2 id=&quot;20190524&quot;&gt;20190524&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;陇西行四首 其二&lt;/strong&gt;&lt;br /&gt;
陈陶&lt;br /&gt;
誓扫匈奴不顾身，&lt;br /&gt;
五千貂锦丧胡尘。&lt;br /&gt;
可怜无定河边骨，&lt;br /&gt;
犹是春闺梦里人。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;春望&lt;/strong&gt;&lt;br /&gt;
杜甫&lt;br /&gt;
国破山河在，城春草木深。&lt;br /&gt;
感时花溅泪，恨别鸟惊心。&lt;br /&gt;
烽火连三月，家书抵万金。&lt;br /&gt;
白头搔更短，浑欲不胜簪。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;春雨&lt;/strong&gt;&lt;br /&gt;
李商隐&lt;br /&gt;
怅卧新春白袷衣，白门寥落意多违。&lt;br /&gt;
红楼隔雨相望冷，珠箔飘灯独自归。&lt;br /&gt;
远路应悲春晼晚，残霄犹得梦依稀。&lt;br /&gt;
玉珰缄札何由达，万里云罗一雁飞。&lt;/p&gt;

&lt;h2 id=&quot;20190525&quot;&gt;20190525&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;杂诗&lt;/strong&gt;&lt;br /&gt;
佚名&lt;br /&gt;
近寒食雨草萋萋，&lt;br /&gt;
著麦苗风柳映堤。&lt;br /&gt;
等是有家归未得，&lt;br /&gt;
杜鹃休向耳边啼。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;春宿左省&lt;/strong&gt;&lt;br /&gt;
杜甫&lt;br /&gt;
花隐掖垣暮，啾啾栖鸟过。&lt;br /&gt;
星临万户动，月傍九霄多。&lt;br /&gt;
不寝听金钥，因风想玉珂。&lt;br /&gt;
明朝有封事，数问夜如何。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;筹笔驿&lt;/strong&gt;&lt;br /&gt;
李商隐&lt;br /&gt;
猿鸟犹疑畏简书，风云常为护储胥。&lt;br /&gt;
徒令上将挥神笔，终见降王走传车。&lt;br /&gt;
管乐有才原不忝，关张无命欲何如。&lt;br /&gt;
他年锦里经祠庙，梁父吟成恨有余。&lt;/p&gt;

&lt;h2 id=&quot;20190526&quot;&gt;20190526&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;回乡偶书&lt;/strong&gt;&lt;br /&gt;
贺知章&lt;br /&gt;
少小离家老大回，&lt;br /&gt;
乡音无改鬓毛衰。&lt;br /&gt;
儿童相见不相识，&lt;br /&gt;
笑问客从何处来。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;旅宿&lt;/strong&gt;&lt;br /&gt;
杜牧&lt;br /&gt;
旅馆无良伴，凝情自悄然。&lt;br /&gt;
寒灯思旧事，断雁警愁眠。&lt;br /&gt;
远梦归侵晓，家书到隔年。&lt;br /&gt;
沧江好烟月，门系钓鱼船。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;锦瑟&lt;/strong&gt;&lt;br /&gt;
李商隐&lt;br /&gt;
锦瑟无端五十弦，一弦一柱思华年。&lt;br /&gt;
庄生晓梦迷蝴蝶，望帝春心思杜鹃。&lt;br /&gt;
沧海月明珠有泪，蓝田日暖玉生烟。&lt;br /&gt;
此情可待成追忆，只是当时已惘然。&lt;/p&gt;

&lt;h2 id=&quot;20190527&quot;&gt;20190527&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;瑶瑟怨&lt;/strong&gt;&lt;br /&gt;
温庭筠&lt;br /&gt;
冰簟银床梦不成，碧天如水夜云轻。&lt;br /&gt;
雁声远过潇湘去，十二楼中月自明。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;春宫怨&lt;/strong&gt;&lt;br /&gt;
杜荀鹤&lt;br /&gt;
早被婵娟误，欲妆临镜慵。&lt;br /&gt;
承恩不在貌，教妾若为容。&lt;br /&gt;
风暖鸟声碎，日高花影重。&lt;br /&gt;
年年越溪女，相忆采芙蓉。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;隋宫&lt;/strong&gt;&lt;br /&gt;
李商隐&lt;br /&gt;
紫泉宫殿锁烟霞，欲取芜城作帝家。&lt;br /&gt;
玉玺不缘归日角，锦帆应是到天涯。&lt;br /&gt;
于今腐草无萤火，终古垂杨有暮鸦。&lt;br /&gt;
地下若逢陈后主，岂宜重问后庭花。&lt;/p&gt;

&lt;h2 id=&quot;20190528&quot;&gt;20190528&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;月夜&lt;/strong&gt;&lt;br /&gt;
刘方平&lt;br /&gt;
更深月色半人家，&lt;br /&gt;
北斗阑干南斗斜。&lt;br /&gt;
今夜偏知春气暖，&lt;br /&gt;
虫声新透绿窗纱。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;和晋陵陆丞早春游望&lt;/strong&gt;&lt;br /&gt;
杜审言&lt;br /&gt;
独有宦游人，偏惊物候新。&lt;br /&gt;
云霞出海曙，梅柳渡江春。&lt;br /&gt;
淑气催黄鸟，晴光转绿蘋。&lt;br /&gt;
忽闻歌古调，归思欲沾巾。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;送魏万之京&lt;/strong&gt;&lt;br /&gt;
李颀&lt;br /&gt;
朝闻游子唱离歌，昨夜微霜初渡河。&lt;br /&gt;
鸿雁不堪愁里听，云山况是客中过。&lt;br /&gt;
关城树色催寒近，御苑砧声向晚多。&lt;br /&gt;
莫见长安行乐处，空令岁月易蹉跎。&lt;/p&gt;

&lt;h2 id=&quot;20190529&quot;&gt;20190529&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;春怨&lt;/strong&gt;&lt;br /&gt;
刘方平&lt;br /&gt;
纱窗日落渐黄昏，&lt;br /&gt;
金屋无人见泪痕。&lt;br /&gt;
寂寞空庭春欲晚，&lt;br /&gt;
梨花满地不开门。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;杂诗三首 其三&lt;/strong&gt;&lt;br /&gt;
沈佺期&lt;br /&gt;
闻道黄龙戍，频年不解兵。&lt;br /&gt;
可怜闺里月，长在汉家营。&lt;br /&gt;
少妇今春意，良人昨夜情。&lt;br /&gt;
谁能将旗鼓，一为取龙城。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;咏怀古迹 其一&lt;/strong&gt;&lt;br /&gt;
杜甫&lt;br /&gt;
支离东北风尘际，漂泊西南天地间。&lt;br /&gt;
三峡楼台淹日月，五溪衣服共云山。&lt;br /&gt;
羯胡事主终无赖，词客哀时且未还。&lt;br /&gt;
庾信平生最萧瑟，暮年诗赋动江关。&lt;/p&gt;

&lt;h2 id=&quot;20190530&quot;&gt;20190530&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;乌衣巷&lt;/strong&gt;&lt;br /&gt;
刘禹锡&lt;br /&gt;
朱雀桥边野草花，&lt;br /&gt;
乌衣巷口夕阳斜。&lt;br /&gt;
旧时王谢堂前燕，&lt;br /&gt;
飞入寻常百姓家。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;宿桐庐江寄广陵旧游&lt;/strong&gt;&lt;br /&gt;
孟浩然&lt;br /&gt;
山暝闻猿愁，沧江急夜流。&lt;br /&gt;
风鸣两岸叶，月照一孤舟。&lt;br /&gt;
建德非吾土，维扬忆旧游。&lt;br /&gt;
还将两行泪，遥寄海西头。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;咏怀古迹五首 其二&lt;/strong&gt;&lt;br /&gt;
杜甫&lt;br /&gt;
摇落深知宋玉悲，风流儒雅亦吾师。&lt;br /&gt;
怅望千秋一洒泪，萧条异代不同时。&lt;br /&gt;
江山故宅空文藻，云雨荒台岂梦思。&lt;br /&gt;
最是楚宫俱泯灭，舟人指点到今疑。&lt;/p&gt;

&lt;h2 id=&quot;20190531&quot;&gt;20190531&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;和乐天春词&lt;/strong&gt;&lt;br /&gt;
刘禹锡&lt;br /&gt;
新妆宜面下朱楼，&lt;br /&gt;
深锁春光一院愁。&lt;br /&gt;
行到中庭数花朵，&lt;br /&gt;
蜻蜓飞上玉搔头。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;留别王维&lt;/strong&gt;&lt;br /&gt;
孟浩然&lt;br /&gt;
寂寂竟何待，朝朝空自归。&lt;br /&gt;
欲寻芳草去，惜与故人违。&lt;br /&gt;
当路谁相假，知音世所稀。&lt;br /&gt;
只应守寂寞，还掩故园扉。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;咏怀古迹五首 其三&lt;/strong&gt;&lt;br /&gt;
杜甫&lt;br /&gt;
群山万壑赴荆门，生长明妃尚有村。&lt;br /&gt;
一去紫台连朔漠，独有青冢向黄昏。&lt;br /&gt;
画图省识春风面，环佩空归夜月魂。&lt;br /&gt;
千载琵琶作胡语，分明怨恨曲中论。&lt;/p&gt;
</description>
      </item>
    
  </channel>
</rss>