<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: huizhou92</title>
    <description>The latest articles on DEV Community by huizhou92 (@huizhou92).</description>
    <link>https://dev.to/huizhou92</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1443590%2F7ceb5082-e444-4d3b-85ed-4ee077f2ed98.jpeg</url>
      <title>DEV Community: huizhou92</title>
      <link>https://dev.to/huizhou92</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/huizhou92"/>
    <language>en</language>
    <item>
      <title>Big Tech Is Killing Their Customers</title>
      <dc:creator>huizhou92</dc:creator>
      <pubDate>Mon, 20 Jan 2025 06:20:58 +0000</pubDate>
      <link>https://dev.to/huizhou92/big-tech-is-killing-their-customers-min</link>
      <guid>https://dev.to/huizhou92/big-tech-is-killing-their-customers-min</guid>
      <description>&lt;p&gt;Recently, &lt;a href="https://pod.geraspora.de/people/4ce5b01a9e3a1b18d700000a" rel="noopener noreferrer"&gt;Dennis Schubert&lt;/a&gt; posted a fiery update about a crisis in the “diaspora*” project. The platform's network infrastructure was collapsing due to heavy traffic. But what caused this overload? Shockingly, &lt;strong&gt;70% of the requests came from LLM (Large Language Model) bots operated by major tech companies&lt;/strong&gt;. These bots ignored &lt;code&gt;robots.txt&lt;/code&gt; directives, relentlessly scraping every data they could access.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.hxzhouh.com%2Fblog-images%2F2025%2F01%2F3cbeeac63070c2d3d19c34cc21828f43.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.hxzhouh.com%2Fblog-images%2F2025%2F01%2F3cbeeac63070c2d3d19c34cc21828f43.webp" width="800" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dennis discovered that &lt;code&gt;ChatGPT&lt;/code&gt; and &lt;code&gt;Amazon&lt;/code&gt; bots even went as far as to scrape &lt;strong&gt;the entire edit history of Wiki pages&lt;/strong&gt;—every single revision. He couldn’t help but ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“What are they trying to achieve? Are they analyzing how text evolves?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This data hoarding significantly strained diaspora*’s servers, slowing the platform for legitimate users. Dennis tried several countermeasures:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Updating robots.txt&lt;/strong&gt;: Useless, as the bots ignored it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate-limiting&lt;/strong&gt;: Failed because the bots rotated their IP addresses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blocking User Agents&lt;/strong&gt;: Ineffective, as the bots disguised themselves as regular browsers.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Frustrated, Dennis likened the situation to a &lt;strong&gt;DDoS attack on the entire internet&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Big Tech Need Our Data?
&lt;/h2&gt;

&lt;p&gt;The answer lies in &lt;strong&gt;AI’s insatiable hunger for training data&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
High-quality datasets are the backbone of AI models, and the industry is running out of fresh material to train on. As OpenAI engineer James Betker once wrote:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As I’ve spent these hours observing the effects of tweaking various model configurations and hyperparameters, one thing that has struck me is the similarities between all the training runs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It’s becoming clear to me that these models are truly approximating their datasets to an incredible degree&lt;/p&gt;

&lt;p&gt;To stay ahead in the AI arms race, tech giants are aggressively scraping data from every corner of the web—personal blogs, independent wikis, and small projects. They don’t just scrape; they &lt;strong&gt;strip the internet bare&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can We Fight Back?
&lt;/h2&gt;

&lt;p&gt;Big Tech has teams of experts balancing web scraping and user experience, but small websites and independent projects lack these resources. For individuals, it’s an uphill battle.&lt;/p&gt;

&lt;p&gt;Dennis suggested two unconventional methods to fend off bots:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Tarpit Strategy&lt;/strong&gt;: Generate meaningless random text to trick bots into wasting resources on irrelevant data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript Traps&lt;/strong&gt;: Serve bot-detected requests with JavaScript-heavy content, embedding scripts that only bots would execute, such as crypto mining code.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;While these approaches might work, they’re expensive and technically demanding.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Zero-Click Internet
&lt;/h2&gt;

&lt;p&gt;What’s Big Tech’s ultimate goal?&lt;br&gt;&lt;br&gt;
To &lt;strong&gt;trap users within their ecosystems&lt;/strong&gt;. By leveraging AI to generate “the best content,” they eliminate the need for users to visit other websites. No more outbound links, no more exploring—their AI serves everything directly, with ads seamlessly integrated.&lt;/p&gt;

&lt;p&gt;For individual creators, this means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SEO doesn’t matter anymore.&lt;/li&gt;
&lt;li&gt;High-quality content won’t reach users.&lt;/li&gt;
&lt;li&gt;Revenue dries up.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your work is more than fuel for Big Tech’s data engines in this new reality.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Inevitable Decline of the Open Web
&lt;/h2&gt;

&lt;p&gt;Big Tech is reshaping the internet, exploiting data while squeezing value out of independent creators. Fighting back is nearly impossible for small websites. The shift is already happening, and it’s irreversible. Ironically, the open web is dying, and the companies that built it are killing it.&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pod.geraspora.de/posts/17342163" rel="noopener noreferrer"&gt;Dennis Schubert’s Post&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nonint.com/2023/06/10/the-it-in-ai-models-is-the-dataset/" rel="noopener noreferrer"&gt;The IT in AI Models is the Dataset&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.techspot.com/article/2908-the-zero-click-internet/" rel="noopener noreferrer"&gt;TechSpot: The Zero-Click Internet&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;This version maintains the original tone while aligning with Medium’s concise, conversational style. It’s structured for readability and flows logically to keep readers engaged.&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;&lt;a href="https://huizhou92.com/p/big-tech-is-killing-their-customers/" rel="noopener noreferrer"&gt;Long Time Link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;If you find my blog helpful, please subscribe to me via &lt;a href="https://huizhou92.com/index.xml" rel="noopener noreferrer"&gt;RSS&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Or follow me on &lt;a href="https://x.com/@piaopiaopig" rel="noopener noreferrer"&gt;X&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; If you have a &lt;a href="https://medium.huizhou92.com/" rel="noopener noreferrer"&gt;Medium&lt;/a&gt; account, follow me there. My articles will be published there as soon as possible.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>google</category>
      <category>ai</category>
    </item>
    <item>
      <title>Software Engineering: Hyrum's Law</title>
      <dc:creator>huizhou92</dc:creator>
      <pubDate>Wed, 08 Jan 2025 11:37:45 +0000</pubDate>
      <link>https://dev.to/huizhou92/software-engineering-hirams-law-2ghm</link>
      <guid>https://dev.to/huizhou92/software-engineering-hirams-law-2ghm</guid>
      <description>&lt;p&gt;/dev&lt;br&gt;
In software development, have you ever encountered a situation where you are developing a shopping cart feature that requires storing product information in a database when a user adds an item? You might have designed a straightforward function as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;addToCart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// add to db&lt;/span&gt;
    &lt;span class="o"&gt;....&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this method, you assume that the database storage operation will always succeed without considering potential errors such as connection failures, write errors, or incorrect data formats.&lt;/p&gt;

&lt;p&gt;If you assume that the operation will always succeed and do not account for error conditions, you may encounter issues highlighted by Hyrum's Law.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Hyrum's Law?
&lt;/h2&gt;

&lt;p&gt;Hyrum's Law is a principle in software development that states:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;“When you depend on an API, you also depend on its implementation details.”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In other words, even if an API is defined and documented, the various ways it can be implemented should be considered when using that API. You must consider the implementation details, not just the declared functionality.&lt;/p&gt;

&lt;p&gt;Hyrum's Law is named after Google engineer &lt;a href="https://x.com/hyrumwright" rel="noopener noreferrer"&gt;Hyrum Wright&lt;/a&gt;, who introduced the concept in a presentation.&lt;/p&gt;

&lt;p&gt;Hyrum Wright emphasized that developers should pay more attention to API implementation details, as these aspects can affect their code's future maintainability and stability.&lt;/p&gt;
&lt;h2&gt;
  
  
  Importance of Hyrum's Law
&lt;/h2&gt;

&lt;p&gt;Hyrum's Law serves several significant purposes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Awareness of Implementation Details:&lt;/strong&gt; This reminds developers that it is crucial to understand an API's functionalities, implementation details, and limitations when using it. APIs are commonplace in software development, helping us quickly implement features and improve productivity.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Implications for Code Behavior:&lt;/strong&gt; How APIs are implemented can significantly affect code behavior and may lead to unforeseen issues. Hyrum’s Law emphasizes the need to evaluate implementation details and stability carefully to prevent potential problems and enhance code maintainability and reliability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Adaptation to Changes:&lt;/strong&gt; The law also underscores software development's iterative and evolving nature. As software requirements and technical environments change, API implementations may also grow. Thus, staying abreast of these changes is vital for maintaining software quality and stability.&lt;/p&gt;
&lt;h2&gt;
  
  
  A Case Study
&lt;/h2&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In Go's source code, there are echoes of Hyrum's Law.&lt;br&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.hxzhouh.com%2Fblog-images%2F2025%2F01%2F364f331ca65e0d92eb86d66a74167f81.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.hxzhouh.com%2Fblog-images%2F2025%2F01%2F364f331ca65e0d92eb86d66a74167f81.webp" alt=" Hyrum's Law in the Go Source Code" width="800" height="49"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
For instance, in &lt;code&gt;./src/net/http/request.go:1199&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;MaxBytesError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="c"&gt;// Due to Hyrum's law, this text cannot be changed.  &lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"http: request body too large"&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This raises the question: why is it a concern? Changing an error message might affect other users relying on that message.&lt;/p&gt;

&lt;p&gt;I have encountered similar issues where upstream database changes in &lt;code&gt;ErrCode&lt;/code&gt; affected my business logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Recommendations for Hyrum's Law
&lt;/h2&gt;

&lt;p&gt;Here are some suggestions to effectively implement Hyrum’s Law in practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Understand API Documentation:&lt;/strong&gt; Before using an API, carefully read its documentation and specifications to understand its features, uses, limitations, and potential issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Write Robust Code:&lt;/strong&gt; When utilizing APIs, ensure robust error handling and consider various error and exception scenarios to bolster code reliability and stability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use Stable API Versions:&lt;/strong&gt; When multiple API versions are available, opt for stable versions and avoid deprecated or obsolete ones whenever possible.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Conduct Integration and Unit Tests:&lt;/strong&gt; Write integration and unit tests to validate the API's correctness and stability and promptly address any emerging issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Be Aware of API Dependencies:&lt;/strong&gt; Pay attention to API dependencies, avoiding unnecessary dependencies while ensuring that those you do use are reliable and stable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Promptly Address API Changes:&lt;/strong&gt; Stay informed about and adapt to changes in API implementations to maintain software quality and stability amidst evolving requirements.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In summary, adhering to these best practices can help you better apply Hyrum's Law, enhance the maintainability and stability of your code, and adapt to changes and innovations in the software development process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Anti-Patterns Related to Hyrum's Law
&lt;/h2&gt;

&lt;p&gt;In addition to standard practices, here are some prevalent anti-patterns that detract from the principles of Hyrum’s Law:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Direct Dependency on Implementation:&lt;/strong&gt; Some developers may ignore API specifications and directly rely on its concrete implementations, leading to tight coupling and increased fragility and maintenance challenges.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Neglecting API Limitations:&lt;/strong&gt; Failing to consider API limitations and exceptions can result in code uncertainty and unreliability, as developers might assume the API will always function correctly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Direct Use of Low-Level Libraries:&lt;/strong&gt; Bypassing API encapsulation by using low-level libraries or components can complicate code and hinder maintainability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ignoring API Version Changes:&lt;/strong&gt; Developers who overlook API version changes may face compatibility issues and maintenance difficulties, risking disconnection from technological advancements.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unreasonable Additions or Removals of Dependencies:&lt;/strong&gt; Improperly managed dependencies can create confusion and complexity, hindering maintainability.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Avoiding these anti-patterns can ensure better alignment with Hyrum’s Law, ultimately leading to more maintainable and stable code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Hyrum's Law is a vital principle that underscores the importance of focusing on a system's core functionalities and considering various dependencies and side effects present within complex systems.&lt;/p&gt;

&lt;p&gt;Assuming everything is functioning correctly without accounting for dependencies and side effects can result in unexpected issues that might lead to system failures or other significant problems.&lt;/p&gt;

&lt;p&gt;As developers, we must be mindful of the traps posed by Hyrum's Law and consider best practices to ensure the stability and reliability of our code.&lt;/p&gt;

&lt;p&gt;In conclusion, Hyrum's Law is of paramount importance. For developers, understanding this principle and applying it in practice will enhance code quality and reliability, subsequently providing users with better experiences.&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;&lt;a href="https://huizhou92.com/p/software-engineering-hyrums-law/" rel="noopener noreferrer"&gt;Long Time Link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;If you find my blog helpful, please subscribe to me via &lt;a href="https://huizhou92.com/index.xml" rel="noopener noreferrer"&gt;RSS&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Or follow me on &lt;a href="https://x.com/@piaopiaopig" rel="noopener noreferrer"&gt;X&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; If you have a &lt;a href="https://medium.huizhou92.com/" rel="noopener noreferrer"&gt;Medium&lt;/a&gt; account, follow me there. My articles will be published there as soon as possible.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>hyrum</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Debunking the Misconception: Maximum Number of TCP Connections on a Server</title>
      <dc:creator>huizhou92</dc:creator>
      <pubDate>Wed, 04 Dec 2024 07:06:43 +0000</pubDate>
      <link>https://dev.to/huizhou92/debunking-the-misconception-maximum-number-of-tcp-connections-on-a-server-174</link>
      <guid>https://dev.to/huizhou92/debunking-the-misconception-maximum-number-of-tcp-connections-on-a-server-174</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;There's a widespread misconception:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Since TCP port numbers are 16-bit unsigned integers with a maximum value of 65535, a single server can support at most 65536 TCP socket connections.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even experienced network programmers may believe this conclusion to be proper. Let's debunk this myth using both theoretical and practical perspectives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Theoretical Analysis
&lt;/h2&gt;

&lt;p&gt;In &lt;code&gt;*nix&lt;/code&gt; systems, each TCP connection is uniquely identified by a &lt;strong&gt;4-tuple&lt;/strong&gt; structure: &lt;code&gt;{local_ip, local_port, remote_ip, remote_port}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For IPv4, the system can theoretically manage up to &lt;code&gt;2^(32 + 16 + 32 + 16)&lt;/code&gt; connections—equivalent to &lt;code&gt;2^96&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;IPv4 can be viewed as a 32-bit unsigned number.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Breaking Down the 4-Tuple Limits
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A single server typically uses only one &lt;code&gt;local_ip&lt;/code&gt;&lt;/strong&gt;, meaning the server could theoretically manage &lt;code&gt;2^(16 + 32 + 16)&lt;/code&gt; connections.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A single service (e.g., an Nginx process) usually listens on one &lt;code&gt;local_port&lt;/code&gt;&lt;/strong&gt;, which reduces the capacity further to &lt;code&gt;2^(32 + 16)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If one remote machine (client) connects to a server&lt;/strong&gt;, fixing &lt;code&gt;local_ip&lt;/code&gt;, &lt;code&gt;local_port&lt;/code&gt;, and &lt;code&gt;remote_ip&lt;/code&gt; leaves only the &lt;code&gt;remote_port&lt;/code&gt; variable. Since the &lt;code&gt;remote_port&lt;/code&gt; range is 16-bit, there are only &lt;code&gt;2^16 = 65536&lt;/code&gt; possible connections from a single client to a specific server endpoint.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This limitation is the root of the &lt;strong&gt;classic misunderstanding&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For protocols beyond TCP (like UDP), the tuple expands to include the protocol type, making it a 5-tuple, adding even more possibilities.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The actual limits for a server depend on factors beyond the tuple structure.&lt;/p&gt;




&lt;h2&gt;
  
  
  Practical Limitations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  File Descriptors
&lt;/h3&gt;

&lt;p&gt;In Linux, everything is treated as a file, and sockets are no exception. The number of file descriptors determines the maximum number of simultaneous TCP connections.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Maximum file descriptors supported by the system:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="o"&gt;[&lt;/span&gt;root@test1 ~]# &lt;span class="nb"&gt;cat&lt;/span&gt; /proc/sys/fs/file-max
   1616352
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Maximum file descriptors per process:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="o"&gt;[&lt;/span&gt;root@test1 ~]# &lt;span class="nb"&gt;ulimit&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt;
   1024
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both values can be modified. For instance, during stress testing, these limits are often increased manually.&lt;/p&gt;

&lt;h3&gt;
  
  
  ip_local_port_range
&lt;/h3&gt;

&lt;p&gt;When a client connects to the same TCP endpoint (&lt;code&gt;ip:port&lt;/code&gt;), each connection requires a unique local TCP endpoint. For clients with a single IP, the available local ports determine the connection limit.&lt;/p&gt;

&lt;p&gt;On &lt;code&gt;*nix&lt;/code&gt; systems, the default local port range is typically from &lt;code&gt;32768&lt;/code&gt; to &lt;code&gt;61000&lt;/code&gt;. Check this range using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;root@test1 ~]# &lt;span class="nb"&gt;cat&lt;/span&gt; /proc/sys/net/ipv4/ip_local_port_range
32768    60999
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means a single client can establish around &lt;strong&gt;30,000 connections&lt;/strong&gt; to the same server endpoint during stress tests.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Operating systems automatically reuse local ports if multiple distinct remote endpoints (ip:port) are involved.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Memory &amp;amp; CPU
&lt;/h3&gt;

&lt;p&gt;Each TCP socket in the &lt;code&gt;ESTABLISHED&lt;/code&gt; state consumes approximately &lt;strong&gt;3.3 KB of memory&lt;/strong&gt;. While CPU usage for idle connections is minimal, the server's memory capacity significantly impacts the total number of connections.&lt;/p&gt;

&lt;p&gt;In practice, hardware resources like memory and CPU limit the maximum number of TCP connections a server can handle, long before reaching the theoretical &lt;code&gt;4-tuple&lt;/code&gt; limit.&lt;br&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbvf38nm5772agv8zlqid.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbvf38nm5772agv8zlqid.png" alt="2^96 is too bigger" width="670" height="82"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;The maximum number of TCP connections a server can support is an astronomical &lt;code&gt;2^96&lt;/code&gt;. However, practical constraints like memory, CPU, file descriptors, and port availability impose far lower limits.&lt;/p&gt;

&lt;p&gt;There's no universal number; the limit depends on hardware, configuration, and workload.&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;The background Photo by &lt;a href="https://unsplash.com/@alinnnaaaa?utm_source=medium&amp;amp;utm_medium=referral" rel="noopener noreferrer"&gt;Alina Grubnyak&lt;/a&gt; on &lt;a href="https://unsplash.com/?utm_source=medium&amp;amp;utm_medium=referral" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Using JOSE To Protect your APIs 1：JOSE Basics</title>
      <dc:creator>huizhou92</dc:creator>
      <pubDate>Mon, 11 Nov 2024 02:31:16 +0000</pubDate>
      <link>https://dev.to/huizhou92/using-jose-to-protect-your-apis-1jose-basics-gee</link>
      <guid>https://dev.to/huizhou92/using-jose-to-protect-your-apis-1jose-basics-gee</guid>
      <description>&lt;p&gt;With the development of internet technology, data security has become a top priority. Data security covers a broad spectrum, including technical, service, storage, and transmission security. This article focuses on transmission security, specifically how to develop secure APIs.&lt;/p&gt;

&lt;p&gt;This article series will include several topics:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Basic Knowledge&lt;/li&gt;
&lt;li&gt;Introduction to JOSE, JWT, and JWE&lt;/li&gt;
&lt;li&gt;Certificates&lt;/li&gt;
&lt;li&gt;How HTTPS Secures Web Applications&lt;/li&gt;
&lt;li&gt;OAuth 2.0&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The primary content of this article reviews several encryption and verification algorithms, laying a foundation for later practical discussions. Let’s go！&lt;/p&gt;

&lt;h2&gt;
  
  
  Information Security Algorithms
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Encryption Algorithms
&lt;/h3&gt;

&lt;p&gt;Modern cryptography classifies encryption techniques into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single-key algorithms&lt;/li&gt;
&lt;li&gt;Dual-key algorithms&lt;/li&gt;
&lt;li&gt;Keyless algorithms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Single-key algorithms&lt;/strong&gt;, known as symmetric encryption, use the same key for encryption and decryption.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Dual-key algorithms&lt;/strong&gt;, or asymmetric encryption, use different keys for encryption and decryption.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Keyless algorithms&lt;/strong&gt;, also called random key algorithms, generate a unique key for each use, making them an ideal but less common method due to design challenges.&lt;/p&gt;

&lt;h4&gt;
  
  
  Symmetric Encryption Algorithms
&lt;/h4&gt;

&lt;p&gt;Symmetric encryption, also known as private-key encryption, involves using the same key for encryption and decryption. Standard symmetric encryption algorithms include DES, IDEA (based on DES), 3DES, RC4, RC5, RC6, and AES.&lt;/p&gt;

&lt;p&gt;Critical characteristics of symmetric encryption:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fast, suitable for encrypting extensive data.&lt;/li&gt;
&lt;li&gt;The security of the algorithm depends on the key's confidentiality.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Asymmetric Encryption Algorithms
&lt;/h3&gt;

&lt;p&gt;Asymmetric encryption uses a public key for encryption and a private key for decryption. Standard algorithms include RSA, ECC, and DSA.&lt;/p&gt;

&lt;p&gt;Critical characteristics of asymmetric encryption:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Slower speed, mainly used for small data encryption.&lt;/li&gt;
&lt;li&gt;Higher security.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Data Verification Algorithms
&lt;/h2&gt;

&lt;p&gt;Data verification algorithms fall into three categories: message digests, message authentication, and digital signatures.&lt;/p&gt;

&lt;h3&gt;
  
  
  Message Digest (MD)
&lt;/h3&gt;

&lt;p&gt;Message digests, or digital digests, use a one-way hash function to "digest" plaintext into a fixed-length encrypted string, also known as a digital fingerprint. Popular hash algorithms include MD2, MD4, MD5, HAVAL, SHA-1, and SHA256.&lt;/p&gt;

&lt;p&gt;Key characteristics:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The process is irreversible.&lt;/li&gt;
&lt;li&gt;The output length is fixed.&lt;/li&gt;
&lt;li&gt;It ensures data integrity.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Message Authentication (MA)
&lt;/h3&gt;

&lt;p&gt;Message authentication ensures that messages have not been altered during transmission or storage. It often uses hash algorithms combined with encryption to verify the integrity of the message.&lt;/p&gt;

&lt;p&gt;Standard message authentication algorithms use hash functions with keys, known as [HMAC](&lt;a href="https://link.jianshu.com/?t=http://www.ietf.org/rfc/rfc2104.txt" rel="noopener noreferrer"&gt;http://www.ietf.org/rfc/rfc2104.txt&lt;/a&gt;, and combine MD and SHA algorithms with added vital protection.&lt;/p&gt;

&lt;p&gt;Key characteristics:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ensures data integrity and accuracy.&lt;/li&gt;
&lt;li&gt;The process is irreversible.&lt;/li&gt;
&lt;li&gt;The output length is fixed.
### Digital Signatures (DS)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A digital signature encrypts the message digest using the sender’s private key and sends it with the original message. The receiver decrypts the digest using the sender's public key and compares it to the original message digest.&lt;/p&gt;

&lt;p&gt;Key characteristics:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ensures data integrity, sender authentication, and non-repudiation.&lt;/li&gt;
&lt;li&gt;The process is irreversible.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  sub summary
&lt;/h3&gt;

&lt;p&gt;Characteristics and examples of each algorithm&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Algorithm Type&lt;/th&gt;
&lt;th&gt;Features&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Symmetric Encryption&lt;/td&gt;
&lt;td&gt;Fast, suitable for large data/files&lt;/td&gt;
&lt;td&gt;DES, 3DES, AES&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Asymmetric Encryption&lt;/td&gt;
&lt;td&gt;Slower, suitable for small data&lt;/td&gt;
&lt;td&gt;RSA, ECC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Message Digest (MD)&lt;/td&gt;
&lt;td&gt;Integrity&lt;/td&gt;
&lt;td&gt;MD2, MD4, MD5, SHA1, SHA256&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Message Authentication (MA)&lt;/td&gt;
&lt;td&gt;Integrity, authenticity&lt;/td&gt;
&lt;td&gt;HMAC-MD5, HMAC-SHA1, HMAC-SHA256, HMAC-SHA384&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Digital Signature (DS)&lt;/td&gt;
&lt;td&gt;Integrity, authenticity, non-repudiation&lt;/td&gt;
&lt;td&gt;RSA, DSA, ECDSA&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Evolution of Security Solutions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Symmetric Encryption
&lt;/h3&gt;

&lt;p&gt;After the development of the Internet, some enterprises began to focus on security, based on symmetric encryption algorithms, designed this program.&lt;br&gt;&lt;br&gt;
The whole process involves only the AES (symmetric) algorithm, only and encrypts the data in transit. As shown in the figure:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpm5ln4c5han4b5hwdoqy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpm5ln4c5han4b5hwdoqy.png" alt="Pasted image 20241017154609" width="800" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Security Item&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Data Security&lt;/td&gt;
&lt;td&gt;Achieved through AES&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data Integrity&lt;/td&gt;
&lt;td&gt;Not ensured&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data Authenticity&lt;/td&gt;
&lt;td&gt;Not ensured, vulnerable to key exposure&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There are many drawbacks to this program.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;single key can not realize dynamic key management&lt;/li&gt;
&lt;li&gt;Unable to verify data integrity&lt;/li&gt;
&lt;li&gt;After the key is exposed, the security of the whole program will not be broken.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  2. Symmetric Encryption + Message Digest
&lt;/h3&gt;

&lt;p&gt;This solution adds a message digest to ensure data integrity, but the other issues remain.&lt;br&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fssz42pln151eomienh4f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fssz42pln151eomienh4f.png" alt="Pasted image 20241017154624" width="800" height="205"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Security Item&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Data Security&lt;/td&gt;
&lt;td&gt;Achieved through AES&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data Integrity&lt;/td&gt;
&lt;td&gt;Realized through information summaries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data Authenticity&lt;/td&gt;
&lt;td&gt;Not ensured, vulnerable to key exposure&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;drawback&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;single key can not realize dynamic key management&lt;/li&gt;
&lt;li&gt;After the key is exposed, the security of the whole program will not be broken.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  3. Symmetric Encryption + Message Authentication
&lt;/h3&gt;

&lt;p&gt;Symmetric encryption + message digest is used when the security requirements are not exceptionally high. However, there is room for improvement for industries with particularly high-security requirements, such as finance, education, and other sectors. Therefore, people have improved the digest mechanism, the message digest with message authentication code to replace the formation of HTTP + symmetric encryption + message authentication scheme; this scheme is characterized by message authentication code to replace the digest, based on the ordinary digest to increase the two-way checksum, to ensure the authenticity of the data.&lt;br&gt;&lt;br&gt;
The security and disadvantages are similar to the second scheme.&lt;br&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcl0nsgsolyg5yvi19zet.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcl0nsgsolyg5yvi19zet.png" alt="Pasted image 20241017154643" width="800" height="205"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Asymmetric Encryption
&lt;/h3&gt;

&lt;p&gt;Asymmetric encryption solves the issue of key exposure by using a public-private key pair, providing higher security but at the cost of performance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjtfkpmusuyxslowreset.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjtfkpmusuyxslowreset.png" alt="Pasted image 20241017154651" width="800" height="413"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Security&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Security Item&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Data Security&lt;/td&gt;
&lt;td&gt;Achieved via RSA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data Integrity (Tamper-proof)&lt;/td&gt;
&lt;td&gt;Achieved via RSA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data Authenticity (Anti-forgery)&lt;/td&gt;
&lt;td&gt;Achieved through RSA public and private key pairing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;drawback&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Poor performance, slow speed&lt;/li&gt;
&lt;li&gt;Not suitable for extensive data or file encryption/decryption
### 5. Symmetric Encryption + Message Authentication + Asymmetric Encryption&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of the above schemes have flaws, which stem from the encryption algorithms, so is there a way to combine symmetric and asymmetric encryption to complement each other's weaknesses? The answer is yes; human wisdom is infinite, so this scheme comes to mind:&lt;br&gt;&lt;br&gt;
The message is encrypted with symmetric encryption, and the key of the symmetric algorithm is encrypted with asymmetric encryption so that efficiency and security are considered. As shown in the figure below, using AES + authentication + RSA as an example:&lt;br&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.hxzhouh.com%2Fblog-images%2F2024%2F10%2F27378a2bfd1432e8b7abc4634163e44f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.hxzhouh.com%2Fblog-images%2F2024%2F10%2F27378a2bfd1432e8b7abc4634163e44f.png" alt="Pasted image 20241017154027" width="800" height="273"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Security Item&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Data Security&lt;/td&gt;
&lt;td&gt;Achieved through AES and RSA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data Integrity&lt;/td&gt;
&lt;td&gt;Ensured via HMAC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data Authenticity&lt;/td&gt;
&lt;td&gt;Ensured with RSA public-private key pair&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The solution is secure enough to meet the vast majority of security requirements. Many companies use this type of program now.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;AES encryption of the original message, fast&lt;/li&gt;
&lt;li&gt;HMAC on the AES result authentication code to ensure the authenticity of the data&lt;/li&gt;
&lt;li&gt;each time the keys of AES and HMAC are randomly generated, to achieve the effect of dynamic keys&lt;/li&gt;
&lt;li&gt;the RSA algorithm guarantees the security of the key, and the data is small, to play the advantages of RSA&lt;/li&gt;
&lt;li&gt;the key of RSA is two groups, realizing two-way authentication.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This article outlines the basics of encryption algorithms, including symmetric and asymmetric encryption, message authentication, and digital signatures. It also explores the evolution of security solutions, illustrating how modern transmission security balances performance and security. These concepts provide the groundwork for developing secure APIs in future discussions.&lt;/p&gt;

</description>
      <category>jwt</category>
    </item>
    <item>
      <title>SwissTable: A High-Performance Hash Table Implementation</title>
      <dc:creator>huizhou92</dc:creator>
      <pubDate>Thu, 03 Oct 2024 02:59:20 +0000</pubDate>
      <link>https://dev.to/huizhou92/swisstable-a-high-performance-hash-table-implementation-1knc</link>
      <guid>https://dev.to/huizhou92/swisstable-a-high-performance-hash-table-implementation-1knc</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In 2022, ByteDance proposed an &lt;a href="https://github.com/golang/go/issues/54766" rel="noopener noreferrer"&gt;issue&lt;/a&gt; recommending that &lt;code&gt;Golang&lt;/code&gt; adopt SwissTable for its map implementation. In 2023, Dolt published a blog post titled &lt;a href="https://www.dolthub.com/blog/2023-03-28-swiss-map/" rel="noopener noreferrer"&gt;SwissMap: A Smaller, Faster Golang Hash Table&lt;/a&gt;, detailing their design of a &lt;code&gt;swisstable&lt;/code&gt;, which garnered widespread attention. The Go core team is reevaluating the &lt;code&gt;swisstable&lt;/code&gt; design and has added some related code in the &lt;a href="https://github.com/golang/go/blob/6a730e1ef0b7f312fe01815086a2eb5a25739f2d/src/runtime/map_swiss.go#L7" rel="noopener noreferrer"&gt;&lt;code&gt;runtime&lt;/code&gt;&lt;/a&gt;. With some free time during the holidays, let's delve deeper into the principles, compare it to the &lt;code&gt;runtime map&lt;/code&gt;, and understand why it might become the standard for &lt;code&gt;map&lt;/code&gt; implementation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This article was first published in the Medium MPP plan. If you are a Medium user, please follow me on &lt;a href="https://medium.huizhou92.com/" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;. Thank you very much.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This article will not fully explain the principles of &lt;code&gt;hashtable&lt;/code&gt; or &lt;code&gt;swisstable&lt;/code&gt;. A basic understanding of &lt;code&gt;hashtable&lt;/code&gt; is required.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;hashtable&lt;/code&gt; provides a mapping from a &lt;code&gt;key&lt;/code&gt; to a corresponding &lt;code&gt;value&lt;/code&gt; by converting the &lt;code&gt;key&lt;/code&gt; to some "position" using a &lt;code&gt;hash function&lt;/code&gt;. From this position, we can directly retrieve the desired value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Traditional &lt;code&gt;Hashtable&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;hashtable&lt;/code&gt; provides a mapping from a &lt;code&gt;key&lt;/code&gt; to a corresponding value by converting the key to some "position" using a hash function. However, even if the hash function is perfect, conflicts are still inevitable when mapping an infinite number of keys into a finite memory space: two different keys will be mapped to the same position. To solve this, traditional hashtables have several conflict resolution strategies, most commonly &lt;code&gt;chaining&lt;/code&gt; and &lt;code&gt;linear probing&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Chaining
&lt;/h3&gt;

&lt;p&gt;Chaining is the most common method where if multiple keys map to the same position, these keys and values are stored in a linked list. During lookups, the hash function is used to find the position, and then the linked list at that position is traversed to find the matching key. Its structure is similar to this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Figure 1: Chaining implementation of &lt;code&gt;hashtable&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr97z4p2sz1u84rhlz929.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr97z4p2sz1u84rhlz929.png" alt="Pasted image 20240929145217" width="800" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Chaining is straightforward to implement, with fewer boundary conditions to consider. Data insertion and deletion are quick, using head insertion to add new entries and adjusting the next pointer for deletion. Chaining can also prevent performance degradation by converting overly long chains into search trees. However, chaining is not cache-friendly, and performance can be affected if there are many conflicts. Different &lt;code&gt;slots&lt;/code&gt; can be widely spread in memory, leading to poor spatial locality of the data structure overall.&lt;/p&gt;
&lt;h3&gt;
  
  
  Linear Probing
&lt;/h3&gt;

&lt;p&gt;Linear probing is another standard hash table conflict resolution method. Unlike chaining, when a hash conflict occurs, it searches sequentially from the conflict position until it finds an empty slot or loops back to the conflict position. At this point, it resizes and rehashes the entries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Figure 2: Linear probing animation&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.hxzhouh.com%2Fblog-images%2F2024%2F09%2Fbfb5cfbb7f611f0fed2f4d58c0eceaf4.gif" class="article-body-image-wrapper"&gt;&lt;img alt="Linear probing" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.hxzhouh.com%2Fblog-images%2F2024%2F09%2Fbfb5cfbb7f611f0fed2f4d58c0eceaf4.gif" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lookups work similarly: calculate the hash position for the key and then compare each key starting from that position, skipping any deleted entries until an empty slot is reached, indicating the key is not in the table. Deletion uses a tombstone marker.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Figure 3: Linear probing lookup animation&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.hxzhouh.com%2Fblog-images%2F2024%2F09%2Ff0052b66a4e66fb5e9558c4e48601bd7.gif" class="article-body-image-wrapper"&gt;&lt;img alt="Linear probing lookup" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.hxzhouh.com%2Fblog-images%2F2024%2F09%2Ff0052b66a4e66fb5e9558c4e48601bd7.gif" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Linear probing has comparable time complexity to chaining. Its advantages include being cache-friendly and implementable with tight data structures like arrays. However, its drawbacks are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Complex implementation with three states for a &lt;code&gt;slot&lt;/code&gt;: occupied, empty, and deleted.&lt;/li&gt;
&lt;li&gt;Chain reaction of conflicts, leading to more frequent resizing than chaining and potentially more significant memory usage.&lt;/li&gt;
&lt;li&gt;Higher likelihood of lookup process degradation to &lt;code&gt;O(n)&lt;/code&gt; without the ability to convert heavily conflicted areas into search trees.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Many libraries use chaining due to the difficulties with element deletion and conflict chain reactions in linear probing. Despite its drawbacks, linear probing's cache friendliness and memory efficiency provide significant performance advantages on modern computers, leading to its use in languages like &lt;code&gt;golang&lt;/code&gt; and &lt;code&gt;Python&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Go Map Data Storage
&lt;/h3&gt;

&lt;p&gt;Let's recap how &lt;code&gt;Go Map&lt;/code&gt; stores data:&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Figure 4: Go map *&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3f63lz30u625v5n08s3z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3f63lz30u625v5n08s3z.png" alt="Pasted image 20240927142057" width="800" height="700"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quick summary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go &lt;code&gt;map&lt;/code&gt; uses a hash function to map keys to multiple &lt;code&gt;buckets&lt;/code&gt;, each with a fixed number of key-value &lt;code&gt;slots&lt;/code&gt; for storage.&lt;/li&gt;
&lt;li&gt;Each &lt;code&gt;bucket&lt;/code&gt; stores up to 8 key-value pairs. The conflicting keys and values are stored within the same bucket when conflicts occur.&lt;/li&gt;
&lt;li&gt;The map uses a hash function to compute the key's hash value and locate the corresponding &lt;code&gt;bucket&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If a &lt;code&gt;bucket&lt;/code&gt; is complete (all 8 &lt;code&gt;slots&lt;/code&gt; used), an &lt;code&gt;overflow bucket&lt;/code&gt; is generated to continue storing new key-value pairs.&lt;/li&gt;
&lt;li&gt;For lookups, the key's hash value is calculated, the corresponding &lt;code&gt;bucket&lt;/code&gt; is determined, and each &lt;code&gt;slot&lt;/code&gt; within the &lt;code&gt;bucket&lt;/code&gt; is checked. If there is an &lt;code&gt;overflow bucket&lt;/code&gt;, its keys are also checked sequentially.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  SwissTable: An Efficient Hashtable Implementation
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;SwissTable&lt;/code&gt; is a &lt;code&gt;hashtable&lt;/code&gt; implementation based on an improved linear probing method. Its core idea is to optimize performance and memory usage by enhancing the &lt;code&gt;hashtable&lt;/code&gt; structure and metadata storsage. SwissTable uses a new metadata control mechanism to significantly reduce unnecessary &lt;code&gt;key&lt;/code&gt; comparisons and leverages SIMD instructions to boost throughput.&lt;/p&gt;

&lt;p&gt;Reviewing the two standard &lt;code&gt;hashtable&lt;/code&gt; implementations shows they either waste memory, need to be cache-friendly or suffer performance drops in lookup, insertion, and deletion operations after conflicts. These issues persist even with a "perfect hash function." Using a suboptimal hash function dramatically increases the probability of key conflicts and worsens performance, possibly even falling short of linear searches in an array.&lt;/p&gt;

&lt;p&gt;The industry sought a hash table algorithm that was friendly to cache and resistant to lookup performance degradation. Many focused on developing better hash functions close to "perfect hash function" quality while optimizing calculation performance; others worked on improving the hash table's structure to balance cache friendliness, performance, and memory usage. &lt;a href="https://abseil.io/about/design/swisstables" rel="noopener noreferrer"&gt;&lt;code&gt;swisstable&lt;/code&gt;&lt;/a&gt; belongs to the latter.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SwissTable&lt;/code&gt;'s time complexity is similar to linear probing, while its space complexity is between chaining and linear probing. The implementation I've referenced is primarily based on &lt;a href="https://github.com/dolthub/swiss/tree/main" rel="noopener noreferrer"&gt;dolthub/swiss&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Basic Structure of SwissTable
&lt;/h3&gt;

&lt;p&gt;Although the name has changed, &lt;code&gt;swisstable&lt;/code&gt; is still a &lt;code&gt;hashtable&lt;/code&gt; utilizing an improved linear probing method for hash collisions. Its underlying structure resembles an array. Now, let's delve into the structure of &lt;code&gt;swisstable&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt; &lt;span class="n"&gt;comparable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;ctrl&lt;/span&gt;     &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;  
    &lt;span class="n"&gt;groups&lt;/span&gt;   &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  
    &lt;span class="n"&gt;hash&lt;/span&gt;     &lt;span class="n"&gt;maphash&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Hasher&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  
    &lt;span class="n"&gt;resident&lt;/span&gt; &lt;span class="kt"&gt;uint32&lt;/span&gt;   
    &lt;span class="n"&gt;dead&lt;/span&gt;     &lt;span class="kt"&gt;uint32&lt;/span&gt;   
    &lt;span class="n"&gt;limit&lt;/span&gt;    &lt;span class="kt"&gt;uint32&lt;/span&gt;   
&lt;span class="p"&gt;}&lt;/span&gt; 

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;groupSize&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;int8&lt;/span&gt;  

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt; &lt;span class="n"&gt;comparable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;keys&lt;/span&gt;   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;groupSize&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;  
    &lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;groupSize&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;V&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;swisstable&lt;/code&gt;, &lt;code&gt;ctrl&lt;/code&gt; is an array of &lt;code&gt;metadata&lt;/code&gt;, corresponding to the &lt;code&gt;group[K, V]&lt;/code&gt; array. Each &lt;code&gt;group&lt;/code&gt; has 8 &lt;code&gt;slots&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The hash is divided into &lt;code&gt;57 bits&lt;/code&gt; for H1 to determine the starting &lt;code&gt;groups&lt;/code&gt;, and the remaining &lt;code&gt;7 bits&lt;/code&gt; called H2, stored in &lt;code&gt;metadata&lt;/code&gt; as the hash signature of the current key for subsequent search and filtering.&lt;/p&gt;

&lt;p&gt;The key advantage of &lt;code&gt;swisstable&lt;/code&gt; over traditional hash tables lies in the metadata called &lt;code&gt;ctrl&lt;/code&gt;. Control information includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Whether a slot is empty: &lt;code&gt;0b10000000&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Whether a slot has been deleted: &lt;code&gt;0b11111110&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The key's hash signature (H2) in a slot: &lt;code&gt;0bh2&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The unique values of these states allow the use of SIMD instructions, maximizing performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding Data
&lt;/h3&gt;

&lt;p&gt;The process of adding data in &lt;code&gt;swisstable&lt;/code&gt; involves several steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Calculate the hash value and split it into &lt;code&gt;h1&lt;/code&gt; and &lt;code&gt;h2&lt;/code&gt;. Using &lt;code&gt;h1&lt;/code&gt;, determine the starting groups.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;metaMatchH2&lt;/code&gt; to check the current group's &lt;code&gt;metadata&lt;/code&gt; for a matching &lt;code&gt;h2&lt;/code&gt;. If found, further check for the matching key and update the value if they match.&lt;/li&gt;
&lt;li&gt;If no matching key is found, use &lt;code&gt;metaMatchEmpty&lt;/code&gt; to check for empty &lt;code&gt;slots&lt;/code&gt; in the current group. Insert the new key-value pair if an empty slot is found and update the &lt;code&gt;metadata&lt;/code&gt; and &lt;code&gt;resident&lt;/code&gt; count.&lt;/li&gt;
&lt;li&gt;If no empty slots are available in the current group, perform linear probing to check the next &lt;code&gt;groups&lt;/code&gt;.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="n"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resident&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rehash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nextSize&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;splitHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  
    &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;probeStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c"&gt;// inlined find loop  &lt;/span&gt;
        &lt;span class="n"&gt;matches&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;metaMatchH2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;matches&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
            &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;nextMatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c"&gt;// update  &lt;/span&gt;
                &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;  
                &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;  
                &lt;span class="k"&gt;return&lt;/span&gt;  
            &lt;span class="p"&gt;}&lt;/span&gt;  
        &lt;span class="p"&gt;}&lt;/span&gt;  
        &lt;span class="n"&gt;matches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;metaMatchEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;  
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;matches&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c"&gt;// insert  &lt;/span&gt;
            &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;nextMatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
            &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;  
            &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;  
            &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;int8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
            &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resident&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;  
            &lt;span class="k"&gt;return&lt;/span&gt;  
        &lt;span class="p"&gt;}&lt;/span&gt;  
        &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="c"&gt;// linear probing  &lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="kt"&gt;uint32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
            &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;  
        &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;metaMatchH2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="n"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;bitset&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;hasZeroByte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;castUint64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loBits&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;nextMatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bitset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;uint32&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;uint32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TrailingZeros64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;  
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;=&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;   
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although the steps are few, they involve complex bit operations. Normally, &lt;code&gt;h2&lt;/code&gt; needs to be compared with all keys sequentially until the target is found. &lt;code&gt;swisstable&lt;/code&gt; cleverly achieves this by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiplying &lt;code&gt;h2&lt;/code&gt; by &lt;code&gt;0x0101010101010101&lt;/code&gt; to get a uint64, allowing simultaneous comparison with 8 &lt;code&gt;ctrl&lt;/code&gt; values.&lt;/li&gt;
&lt;li&gt;Performing &lt;code&gt;xor&lt;/code&gt; with &lt;code&gt;meta&lt;/code&gt;. If &lt;code&gt;h2&lt;/code&gt; exists in &lt;code&gt;metadata&lt;/code&gt;, the corresponding bit will be zero. The &lt;code&gt;metaMatchH2&lt;/code&gt; function helps us understand this process.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestMetaMatchH2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;metaData&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;metaData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;int8&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;0x7f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0x7f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0x7f&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;metaData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0x7f&lt;/span&gt;
    &lt;span class="n"&gt;metaUint64&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;castUint64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;h2Pattern&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;loBits&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;xorResult&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;metaUint64&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="n"&gt;h2Pattern&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"metaUint64: %b&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xorResult&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;hasZeroByte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xorResult&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"r: %b&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nextMatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;----&lt;/span&gt;
&lt;span class="n"&gt;output&lt;/span&gt;
&lt;span class="c"&gt;// metaUint64: 00000000 11111110 11111110 11111110 0000000 01111111 01111111 00000000&lt;/span&gt;
&lt;span class="c"&gt;// r: 10000000 00000000 00000000 00000000 10000000 00000000 00000000 10000000&lt;/span&gt;
&lt;span class="c"&gt;// 0&lt;/span&gt;
&lt;span class="c"&gt;// 3&lt;/span&gt;
&lt;span class="c"&gt;// 7&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Advantages of SwissTable
&lt;/h3&gt;

&lt;p&gt;Reviewing SwissTable implementation reveals several key benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Operations are shifted from &lt;code&gt;slots&lt;/code&gt; to &lt;code&gt;ctrl&lt;/code&gt;, which are smaller and easily placed in the CPU cache, speeding up operations despite the additional step of locating &lt;code&gt;slots&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Records hash signatures, reducing meaningless key comparisons—the main cause of linear probing performance drops.&lt;/li&gt;
&lt;li&gt;Batch operations on &lt;code&gt;ctrl&lt;/code&gt; for &lt;code&gt;slots&lt;/code&gt; increase throughput significantly.&lt;/li&gt;
&lt;li&gt;Metadata and memory layout are optimized for SIMD instructions, maximizing performance.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Slot&lt;/code&gt; optimizations, such as compressing large data, increase cache hit rates.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;swisstable&lt;/code&gt; solves spatial locality issues and exploits modern CPU features for batch element operations, significantly boosting performance.&lt;/p&gt;

&lt;p&gt;Finally, running a benchmark on a local MacBook M1 (without SIMD support) shows significant performance improvements in large map scenarios.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Figure 5: Official &lt;code&gt;swisstable&lt;/code&gt; benchmark&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4bds1tatmc4snmvat6ma.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4bds1tatmc4snmvat6ma.png" alt="Pasted image 20240930110905" width="800" height="334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Currently, the official implementation of &lt;code&gt;swisstable&lt;/code&gt; in Go is still under discussion, and there are a few community implementations like &lt;a href="https://github.com/mhmtszr/concurrent-swiss-map" rel="noopener noreferrer"&gt;concurrent-swiss-map&lt;/a&gt; and &lt;a href="https://github.com/dolthub/swiss" rel="noopener noreferrer"&gt;swiss&lt;/a&gt;. However, they are not perfect; in small map scenarios, &lt;code&gt;swisstable&lt;/code&gt; may even underperform compared to &lt;code&gt;runtime_map&lt;/code&gt;. Nonetheless, the potential demonstrated by &lt;code&gt;swisstable&lt;/code&gt; in other languages indicates that it is worth anticipation.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Dolthub: &lt;a href="https://www.dolthub.com/blog/2023-03-28-swiss-map/" rel="noopener noreferrer"&gt;SwissMap&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;SwissTable principles: &lt;a href="https://abseil.io/about/design/swisstables" rel="noopener noreferrer"&gt;Abseil SwissTables&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Original SwissTable proposal at cppcon: &lt;a href="https://www.youtube.com/watch?v=ncHmEUmJZf4" rel="noopener noreferrer"&gt;cppcon talk&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Improvements to SwissTable algorithm: &lt;a href="https://www.youtube.com/watch?v=JZE3_0qvrMg" rel="noopener noreferrer"&gt;YouTube link&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Bit manipulation primer: &lt;a href="http://graphics.stanford.edu/~seander/bithacks.html##ValueInWord" rel="noopener noreferrer"&gt;Stanford Bit Hacks&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Hash function comparisons: &lt;a href="https://aras-p.info/blog/2016/08/09/More-Hash-Function-Tests/" rel="noopener noreferrer"&gt;Hash function tests&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;An additional bit manipulation article: &lt;a href="https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/" rel="noopener noreferrer"&gt;Fast Modulo Reduction&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Decrypt Go: varint</title>
      <dc:creator>huizhou92</dc:creator>
      <pubDate>Fri, 20 Sep 2024 09:51:21 +0000</pubDate>
      <link>https://dev.to/huizhou92/decrypt-go-varint-4d29</link>
      <guid>https://dev.to/huizhou92/decrypt-go-varint-4d29</guid>
      <description>&lt;p&gt;Recently, I discovered that the Go standard library includes a built-in implementation of &lt;code&gt;varint&lt;/code&gt;, found in &lt;a href="https://github.com/golang/go/blob/9e9b1f57c26a6d13fdaebef67136718b8042cdba/src/encoding/binary/varint.go" rel="noopener noreferrer"&gt;encoding/binary/varint.go&lt;/a&gt;. This implementation is similar to the &lt;code&gt;varint&lt;/code&gt; used in &lt;code&gt;protobuf&lt;/code&gt;. Using the Golang standard library's &lt;code&gt;varint&lt;/code&gt; source code, we will systematically learn and review the concept of &lt;code&gt;varint&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
If you're familiar with &lt;code&gt;protobuf&lt;/code&gt;, you probably already know that all integer types (except fixed types like &lt;code&gt;fixed32&lt;/code&gt; and &lt;code&gt;fixed64&lt;/code&gt;) are encoded using &lt;code&gt;varint&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;varint&lt;/code&gt; mainly solves two issues:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Space Efficiency&lt;/strong&gt;: Take &lt;code&gt;uint64&lt;/code&gt; as an example, representing values as large as 18,446,744,073,709,551,615. In most real-world scenarios, however, our integer values are much smaller. If your system needs to process values as low as 1, you'd still use &lt;code&gt;8 bytes&lt;/code&gt; to represent this value in transmission, wasting space since most bytes store no useful data. varint encoding uses a variable-length byte sequence to represent integers, reducing the space required for smaller values.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Compatibility&lt;/strong&gt;: &lt;code&gt;varint&lt;/code&gt; allows us to handle integers of different sizes without altering the encoding/decoding logic. This means fields can be upgraded from smaller types (like &lt;code&gt;uint32&lt;/code&gt;) to larger ones (like &lt;code&gt;uint64&lt;/code&gt;) without breaking backward compatibility.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This article will dive into Golang &lt;code&gt;varint&lt;/code&gt; implementation, exploring its design principles and how it addresses the challenges of encoding negative numbers.&lt;/p&gt;



&lt;blockquote&gt;
&lt;p&gt;This article was first published under the Medium MPP plan. Follow me on &lt;a href="https://medium.huizhou92.com/" rel="noopener noreferrer"&gt;Medium&lt;/a&gt; if you're a Medium user.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  The Design Principles of varint
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;varint&lt;/code&gt; is designed based on simple principles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;7-bit Grouping&lt;/strong&gt;: The binary representation of an integer is divided into 7-bit groups. From the least significant bit to the most significant bit, every 7-bit group becomes a unit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Continuation Bit&lt;/strong&gt;: A flag bit is added before each 7-bit group, forming an 8-bit byte. If more bytes follow, the flag bit is set to 1; otherwise, it’s set to 0.
For example, the integer &lt;code&gt;uint64(300)&lt;/code&gt; has a binary representation of &lt;code&gt;100101100&lt;/code&gt;. Dividing this into two groups—&lt;code&gt;10&lt;/code&gt; and &lt;code&gt;0101100&lt;/code&gt;—and adding flag bits results in two bytes: &lt;code&gt;00000010&lt;/code&gt; and &lt;code&gt;10101100&lt;/code&gt;, which is the &lt;code&gt;varint&lt;/code&gt; encoding of 300. Compared to &lt;code&gt;uint64&lt;/code&gt;, which uses 4 bytes, &lt;code&gt;varint&lt;/code&gt; reduces the storage by 75%.
list1:  uint64 to &lt;code&gt;varint&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;300&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AppendUvarint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
       &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%08b "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7sjofhusahoxt1xo6klf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7sjofhusahoxt1xo6klf.png" alt="Figure 1: varint encoding" width="800" height="208"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;code&gt;varint&lt;/code&gt; for Unsigned Integers
&lt;/h2&gt;

&lt;p&gt;The Go standard library provides two sets of &lt;code&gt;varint&lt;/code&gt; functions: one for unsigned integers (&lt;a href="https://github.com/golang/go/blob/9e9b1f57c26a6d13fdaebef67136718b8042cdba/src/encoding/binary/varint.go#L51" rel="noopener noreferrer"&gt;PutUvarint&lt;/a&gt;, &lt;a href="https://github.com/golang/go/blob/9e9b1f57c26a6d13fdaebef67136718b8042cdba/src/encoding/binary/varint.go#L68" rel="noopener noreferrer"&gt;Uvarint&lt;/a&gt;) and another for signed integers (&lt;a href="https://github.com/golang/go/blob/9e9b1f57c26a6d13fdaebef67136718b8042cdba/src/encoding/binary/varint.go#L115" rel="noopener noreferrer"&gt;varint&lt;/a&gt;, &lt;a href="https://github.com/golang/go/blob/9e9b1f57c26a6d13fdaebef67136718b8042cdba/src/encoding/binary/varint.go#L101" rel="noopener noreferrer"&gt;Putvarint&lt;/a&gt;).&lt;br&gt;&lt;br&gt;
Let's first look at the unsigned integer &lt;code&gt;varint&lt;/code&gt; implementation:&lt;br&gt;&lt;br&gt;
list2: go src &lt;code&gt;PutUvarint&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;PutUvarint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;0x80&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="m"&gt;0x80&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;7&lt;/span&gt;
        &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is a very important constant in the code: &lt;code&gt;0x80&lt;/code&gt;, which corresponds to the binary code &lt;code&gt;1000 0000&lt;/code&gt;. This constant is very important for the logic that follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;x &amp;gt;= 0x80&lt;/code&gt;&lt;/strong&gt;: This checks if &lt;code&gt;x&lt;/code&gt; requires more than 7 bits for representation. If it does, &lt;code&gt;x&lt;/code&gt; needs to be split.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;byte(x) | 0x80&lt;/code&gt;&lt;/strong&gt;: This applies a bitwise OR with &lt;code&gt;0x80&lt;/code&gt; (&lt;code&gt;1000 0000&lt;/code&gt;), ensuring the highest bit is set to 1 and extracting the lowest 7 bits of &lt;code&gt;x&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;x &amp;gt;&amp;gt;= 7&lt;/code&gt;&lt;/strong&gt;: Shift &lt;code&gt;x&lt;/code&gt; right by 7 bits to process the next group.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;buf[i] = byte(x)&lt;/code&gt;&lt;/strong&gt;: When the loop ends, the highest bits are all zeros, so no further action is needed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;Uvarint&lt;/code&gt; is the reverse of &lt;code&gt;PutUvarint&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;It should be noted that: &lt;code&gt;varint&lt;/code&gt; splits integers into 7-bit groups, meaning large integers may face inefficiencies. For example, &lt;code&gt;uint64&lt;/code&gt;'s maximum value requires 10 bytes instead of the usual 8 (&lt;code&gt;64/7 ≈ 10&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Encoding Negative Numbers: Zigzag Encoding
&lt;/h2&gt;

&lt;p&gt;Though &lt;code&gt;varint&lt;/code&gt; is efficient, it doesn’t account for negative numbers. In computing, numbers are stored as two’s complement, which means a small negative number might have a sizeable binary representation.&lt;br&gt;&lt;br&gt;
For example, &lt;code&gt;-5&lt;/code&gt; in 32-bit form is represented as &lt;code&gt;11111111111111111111111111111011&lt;/code&gt;, requiring 5 bytes in &lt;code&gt;varint encoding&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Go uses &lt;strong&gt;zigzag encoding&lt;/strong&gt; to solve this problem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For positive numbers &lt;code&gt;n&lt;/code&gt;, map them to &lt;code&gt;2n&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For negative numbers &lt;code&gt;-n&lt;/code&gt;, map them to &lt;code&gt;2n-1&lt;/code&gt;.
This way, positive and negative numbers alternate without conflict, hence the name &lt;code&gt;zigzag encoding&lt;/code&gt;.
For example, after zigzag encoding &lt;code&gt;int32(-5)&lt;/code&gt;, the value becomes 9 (&lt;code&gt;00000000000000000000000000001001&lt;/code&gt;), which &lt;code&gt;varint&lt;/code&gt; can represent with just 1 byte.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s the Golang implementation:&lt;br&gt;&lt;br&gt;
list3: go src &lt;code&gt;Putvarint&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Putvarint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ux&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ux&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;ux&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PutUvarint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ux&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the code, we can see that for the implementation of &lt;code&gt;varint&lt;/code&gt; for signed integers, the Go standard library breaks it down into two steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, the integer is converted using &lt;code&gt;ZigZag encoding&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Then, the converted value is encoded using &lt;code&gt;varint&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For negative numbers, there is an extra step: &lt;code&gt;ux = ^ux&lt;/code&gt;. This part might be confusing—why does this transformation result in &lt;code&gt;2n - 1&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;We can roughly deduce the process, assuming we have an integer &lt;code&gt;-n&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, the original value is shifted left, then inverted. This can be viewed as: first invert the value, then shift left, and finally add 1. This results in &lt;code&gt;2*(~(-n)) + 1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;the two’s complement of a negative number is the bitwise inversion of its absolute value plus 1. So, how do we derive the absolute value from the two’s complement? There is a formula: &lt;code&gt;|A| = ~A + 1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Substituting this formula into the first step: &lt;code&gt;2*(n - 1) + 1 = 2n - 1&lt;/code&gt;. This perfectly matches the ZigZag encoding for negative numbers (mathematics is indeed excellent).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqnx3y2pba0v51fhwoxms.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqnx3y2pba0v51fhwoxms.png" alt="Figure 2: ZigZag encoding" width="800" height="283"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the Go standard library, calling &lt;code&gt;PutUvarint&lt;/code&gt; only applies &lt;code&gt;varint&lt;/code&gt; encoding, while calling &lt;code&gt;PutVarint&lt;/code&gt; first applies ZigZag encoding and then &lt;code&gt;varint&lt;/code&gt; encoding. &lt;/p&gt;

&lt;p&gt;In &lt;code&gt;protobuf&lt;/code&gt;, if the type is &lt;code&gt;int32&lt;/code&gt;, &lt;code&gt;int64&lt;/code&gt;, &lt;code&gt;uint32&lt;/code&gt;, or &lt;code&gt;uint64&lt;/code&gt;, only &lt;code&gt;varint&lt;/code&gt; encoding is used. However, for &lt;code&gt;sint32&lt;/code&gt; and &lt;code&gt;sint64&lt;/code&gt;, ZigZag encoding is applied first, followed by &lt;code&gt;varint&lt;/code&gt; encoding.&lt;/p&gt;

&lt;h2&gt;
  
  
  When &lt;code&gt;varint&lt;/code&gt; Is Not Suitable
&lt;/h2&gt;

&lt;p&gt;Despite its benefits, &lt;code&gt;varint&lt;/code&gt; isn't ideal for all scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Large integers&lt;/strong&gt;: &lt;code&gt;varint&lt;/code&gt; can be less efficient than fixed-length encoding for huge numbers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Random data access&lt;/strong&gt;: Since &lt;code&gt;varint&lt;/code&gt; uses variable lengths, indexing specific integers directly is challenging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frequent mathematical operations&lt;/strong&gt;: &lt;code&gt;varint-encoding&lt;/code&gt; data requires decoding before operations, potentially affecting performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security-sensitive applications&lt;/strong&gt;: &lt;code&gt;varint encoding&lt;/code&gt; may leak information about the original integer's size, which could be unacceptable in secure environments.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
    </item>
    <item>
      <title>Decrypt Go: empty struct</title>
      <dc:creator>huizhou92</dc:creator>
      <pubDate>Wed, 11 Sep 2024 02:45:16 +0000</pubDate>
      <link>https://dev.to/huizhou92/decrypt-go-empty-struct-5i4</link>
      <guid>https://dev.to/huizhou92/decrypt-go-empty-struct-5i4</guid>
      <description>&lt;p&gt;In Go, a normal struct typically occupies a block of memory. However, there's a special case: if it's an empty struct, its size is zero. How is this possible, and what is the use of an empty struct?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This article is first published in the medium MPP plan. If you are a medium user, please follow me in &lt;a href="https://medium.huizhou92.com/" rel="noopener noreferrer"&gt;medium&lt;/a&gt;. Thank you very much.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Test&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;B&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unsafe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unsafe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}{}))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/*
8
0
*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Secret of the Empty Struct
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Special Variable: zerobase
&lt;/h4&gt;

&lt;p&gt;An empty struct is a struct with no memory size. This statement is correct, but to be more precise, it actually has a special starting point: the &lt;code&gt;zerobase&lt;/code&gt; variable. This is a &lt;code&gt;uintptr&lt;/code&gt; global variable that occupies 8 bytes. Whenever countless &lt;code&gt;struct {}&lt;/code&gt; variables are defined, the compiler assigns the address of this &lt;code&gt;zerobase&lt;/code&gt; variable. In other words, in Go, any memory allocation with a size of 0 uses the same address, &lt;code&gt;&amp;amp;zerobase&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://go.dev/play/p/WNxfXviET_i" rel="noopener noreferrer"&gt;Example&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;emptyStruct&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}{}&lt;/span&gt;
    &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}{}&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;emptyStruct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%p&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%p&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%p&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// 0x58e360&lt;/span&gt;
&lt;span class="c"&gt;// 0x58e360&lt;/span&gt;
&lt;span class="c"&gt;// 0x58e360&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The memory addresses of variables of an empty struct are all the same. This is because the compiler assigns &lt;code&gt;&amp;amp;zerobase&lt;/code&gt; during compilation when encountering this special type of memory allocation. This logic is in the &lt;a href="https://go.googlesource.com/go/blob/fe36ce669c1a452d2b0e81108a7e07674b50692a/src/runtime/malloc.go#L983" rel="noopener noreferrer"&gt;&lt;code&gt;mallocgc&lt;/code&gt;&lt;/a&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;//go:linkname mallocgc  &lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;mallocgc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="kt"&gt;uintptr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;typ&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;needzero&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;unsafe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pointer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;unsafe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pointer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;zerobase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the secret of the &lt;code&gt;Empty struct&lt;/code&gt;. With this special variable, we can accomplish many functionalities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Empty Struct and Memory Alignment
&lt;/h3&gt;

&lt;p&gt;Typically, if an empty struct is part of a larger struct, it doesn't occupy memory. However, there's a special case when the empty struct is the last field; it triggers memory alignment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://go.dev/play/p/HcxlywljovS" rel="noopener noreferrer"&gt;Example&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unsafe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Alignof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;{}))&lt;/span&gt;
    &lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unsafe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Alignof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;{}))&lt;/span&gt;
    &lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unsafe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;{}))&lt;/span&gt;
    &lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unsafe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;{}))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/**
8
8
32
24
**/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a pointer to a field is present, the returned address may be outside the struct, potentially leading to memory leaks if the memory is not freed when the struct is released. Therefore, when an empty struct is the last field of another struct, additional memory is allocated for safety. If the empty struct is at the beginning or middle, its address is the same as the next variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;  
    &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;  
    &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;  
    &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;  
    &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;  
    &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;  
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%p&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%p&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%p&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%p&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/**
0x1400012c008
0x1400012c018
0x1400012e008
0x1400012e008
**/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use Cases of the Empty Struct
&lt;/h3&gt;

&lt;p&gt;The core reason for the existence of the empty struct &lt;code&gt;struct{}&lt;/code&gt; is to &lt;strong&gt;save memory&lt;/strong&gt;. When you need a struct but don't care about its contents, consider using an empty struct. Go's core composite structures such as &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;chan&lt;/code&gt;, and &lt;code&gt;slice&lt;/code&gt; can all use &lt;code&gt;struct{}&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;map&lt;/code&gt; &amp;amp; &lt;code&gt;struct{}&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Create map&lt;/span&gt;
&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
&lt;span class="c"&gt;// Assign value&lt;/span&gt;
&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}{}&lt;/span&gt;
&lt;span class="c"&gt;// Check if key exists&lt;/span&gt;
&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;code&gt;chan&lt;/code&gt; &amp;amp; &lt;code&gt;struct{}&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;A classic scenario combines &lt;code&gt;channel&lt;/code&gt; and &lt;code&gt;struct{}&lt;/code&gt;, where &lt;code&gt;struct{}&lt;/code&gt; is often used as a signal without caring about its content. As analyzed in previous articles, the essential data structure of a channel is a management structure plus a ring buffer. The ring buffer is zero-allocated if struct{} is used as an element.&lt;/p&gt;

&lt;p&gt;The only use of &lt;code&gt;chan&lt;/code&gt; and &lt;code&gt;struct{}&lt;/code&gt; together is for &lt;strong&gt;signal transmission&lt;/strong&gt; since the empty struct itself cannot carry any value. Generally, it's used with no buffer channels.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Create a signal channel&lt;/span&gt;
&lt;span class="n"&gt;waitc&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;

&lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;span class="n"&gt;goroutine&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="c"&gt;// Send signal: push element&lt;/span&gt;
    &lt;span class="n"&gt;waitc&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}{}&lt;/span&gt;
    &lt;span class="c"&gt;// Send signal: close&lt;/span&gt;
    &lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;waitc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;goroutine&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Receive signal and perform corresponding actions&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;waitc&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this scenario, is &lt;code&gt;struct{}&lt;/code&gt; absolutely necessary? Not really, and the memory saved is negligible. The key point is that the element value of &lt;code&gt;chan&lt;/code&gt; is not cared about, hence &lt;code&gt;struct{}&lt;/code&gt; is used.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;An empty struct is still a struct, just with a size of 0.&lt;/li&gt;
&lt;li&gt;All empty structs share the same address: the address of &lt;code&gt;zerobase&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We can leverage the empty struct's non-memory-occupying feature to optimize code, such as using maps to implement sets and channels.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dave.cheney.net/2014/03/25/the-empty-struct" rel="noopener noreferrer"&gt;The empty struct, Dave Cheney&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.qiyacloud.cn/2020/12/2020-12-21/" rel="noopener noreferrer"&gt;Go 最细节篇— struct{} 空结构体究竟是啥？&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>go</category>
    </item>
    <item>
      <title>RPC Action EP2: Using Protobuf and Creating a Custom Plugin</title>
      <dc:creator>huizhou92</dc:creator>
      <pubDate>Mon, 09 Sep 2024 10:25:23 +0000</pubDate>
      <link>https://dev.to/huizhou92/rpc-action-ep2-using-protobuf-and-creating-a-custom-plugin-2j9j</link>
      <guid>https://dev.to/huizhou92/rpc-action-ep2-using-protobuf-and-creating-a-custom-plugin-2j9j</guid>
      <description>&lt;p&gt;In the &lt;a href="https://huizhou92.com/p/rpc-learning-ep1-implement-a-simple-rpc-interface-in-go/" rel="noopener noreferrer"&gt;previous&lt;/a&gt; article, I implemented a simple RPC interface using the &lt;code&gt;net/rpc&lt;/code&gt; package and tried out the &lt;code&gt;Gob&lt;/code&gt; encoding that comes with &lt;code&gt;net/rpc&lt;/code&gt; and &lt;code&gt;JSON&lt;/code&gt; encoding to learn some basics of Golang RPC. In this post, I'll combine &lt;code&gt;net/rpc&lt;/code&gt; with protobuf and create my &lt;code&gt;protobuf&lt;/code&gt; plugin to help us generate code, so let's get started.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This article was first published in the Medium MPP plan. If you are a Medium user, please follow me on &lt;a href="https://medium.huizhou92.com/" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;. Thank you very much.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We must have used &lt;code&gt;gRPC&lt;/code&gt; and protobuf during our work, but they are not bound. gRPC can be encoded using JSON, and protobuf can be implemented in other languages.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Protocol Buffers&lt;/strong&gt; (&lt;strong&gt;Protobuf&lt;/strong&gt;) is a &lt;a href="https://en.wikipedia.org/wiki/Free_and_open-source_software" rel="noopener noreferrer"&gt;free and open-source&lt;/a&gt; &lt;a href="https://en.wikipedia.org/wiki/Cross-platform_software" rel="noopener noreferrer"&gt;cross-platform&lt;/a&gt; data format used to &lt;a href="https://en.wikipedia.org/wiki/Serialization" rel="noopener noreferrer"&gt;serialize&lt;/a&gt; structured data. It is useful in developing programs that communicate with each other over a network or for storing data. The method involves an &lt;a href="https://en.wikipedia.org/wiki/Interface_description_language" rel="noopener noreferrer"&gt;interface description language&lt;/a&gt; that describes the structure of some data and a program that generates source code from that description for generating or parsing a stream of bytes that represents the structured data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  An example of using protobuf
&lt;/h2&gt;

&lt;p&gt;First we write a &lt;code&gt;proto&lt;/code&gt; file hello-service.proto that defines a message "String"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="na"&gt;syntax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"proto3"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;api&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;option&lt;/span&gt;  &lt;span class="na"&gt;go_package&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"api"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then use the &lt;code&gt;protoc&lt;/code&gt; utility to generate the Go code for the message String&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;protoc &lt;span class="nt"&gt;--go_out&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; hello-service.proto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we modify the Hello function's arguments to use the String generated by the &lt;code&gt;protobuf&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;HelloServiceInterface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using it is no different from before, even, it is not as convenient as using string directly. So why should we use &lt;code&gt;protobuf&lt;/code&gt;? As I said earlier, &lt;strong&gt;using Protobuf to define language-independent RPC service interfaces and messages, and then using the &lt;code&gt;protoc&lt;/code&gt; tool to generate code in different languages, is where its real value lies&lt;/strong&gt;. For example, use the official plugin &lt;code&gt;protoc-gen-go&lt;/code&gt; to generate &lt;code&gt;gRPC&lt;/code&gt; code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;protoc &lt;span class="nt"&gt;--go_out&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;grpc. hello-service.proto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Plugin system for protoc
&lt;/h2&gt;

&lt;p&gt;To generate code from &lt;code&gt;protobuf&lt;/code&gt; files, we must install the &lt;code&gt;protoc&lt;/code&gt; , but the &lt;code&gt;protoc&lt;/code&gt;  doesn't know what our target language is, so we need plugins to help us generate code. how does protoc's plugin system work? Take the above &lt;code&gt;grpc&lt;/code&gt; as an example.&lt;br&gt;&lt;br&gt;
There is a &lt;code&gt;--go_out&lt;/code&gt; parameter here. Since the plugin we're calling is &lt;code&gt;protoc-gen-go&lt;/code&gt;, the parameter is called go_out; if the name was XXX, the parameter would be called XXX_out.&lt;br&gt;&lt;br&gt;
When &lt;code&gt;protoc&lt;/code&gt; is running, it will first parse the &lt;code&gt;protobuf&lt;/code&gt; file and generate a set of Protocol Buffers-encoded descriptive data. It will first determine whether or not the &lt;code&gt;go&lt;/code&gt; plugin is included in protoc, and then it will try to look for &lt;code&gt;protoc-gen-go&lt;/code&gt; in &lt;code&gt;$PATH&lt;/code&gt;, and if it can't find it, it will report an error, and then it will run &lt;code&gt;protoc-gen-go&lt;/code&gt;. &lt;code&gt;protoc-gen-go&lt;/code&gt; command and sends the description data to the plugin command via stdin. After the plugin generates the file contents, it then inputs Protocol Buffers encoded data to stdout to tell &lt;code&gt;protoc&lt;/code&gt; to generate the specific file.&lt;br&gt;&lt;br&gt;
&lt;code&gt;plugins=grpc&lt;/code&gt; is a plugin that comes with &lt;code&gt;protoc-gen-go&lt;/code&gt; in order to invoke it. If you don't use it, it will only generate a message in Go, but you can use this plugin to generate grpc-related code.  &lt;/p&gt;
&lt;h2&gt;
  
  
  Customize a protoc plugin
&lt;/h2&gt;

&lt;p&gt;If we add &lt;code&gt;Hello&lt;/code&gt; interface timing to protobuf, can we customize a &lt;code&gt;protoc&lt;/code&gt; plugin to generate code directly?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="na"&gt;syntax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"proto3"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;api&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
&lt;span class="k"&gt;option&lt;/span&gt;  &lt;span class="na"&gt;go_package&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"./api"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
&lt;span class="kd"&gt;service&lt;/span&gt; &lt;span class="n"&gt;HelloService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
  &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;Hello&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Objective
&lt;/h3&gt;

&lt;p&gt;For this article, my goal was to create a plugin that would then be used to generate RPC server-side and client-side code that would look something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// HelloService_rpc.pb.go&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;HelloServiceInterface&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;RegisterHelloService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="n"&gt;srv&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;HelloServiceInterface&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RegisterName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HelloService"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;HelloServiceClient&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="n"&gt;HelloServiceInterface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;HelloServiceClient&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;DialHelloService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;HelloServiceClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;rpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;HelloServiceClient&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;HelloServiceClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HelloService.Hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would change our business code to look like the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// service&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;":1234"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
       &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ListenTCP error:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RegisterHelloService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultServer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HelloService&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
       &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Accept&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
       &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
          &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Accept error:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
       &lt;span class="p"&gt;}&lt;/span&gt;  
       &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;rpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServeConn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;HelloService&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;  

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;HelloService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HelloService.proto Hello"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Hello:"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;// client.go&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DialHelloService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"localhost:1234"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
       &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"net.Dial:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;  
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Hello"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
       &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Based on the generated code, our workload is already much smaller and the chances of error are already very small. A good start.&lt;br&gt;&lt;br&gt;
Based on the api code above, we can pull out a template file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;tmplService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;`  
import (  
    "net/rpc")  
type {{.ServiceName}}Interface interface {  
func Register{{.ServiceName}}(  
    if err := srv.RegisterName("{{.ServiceName}}", x); err != nil {        return err    }    return nil}  
    *rpc.Client}  
func Dial{{.ServiceName}}(network, address string) (  
{{range $_, $m := .MethodList}}  
    return p.Client.Call("{{$root.ServiceName}}.{{$m.MethodName}}", in, out)}  
`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The whole template is clear, and there are some placeholders in it, such as MethodName, ServiceName, etc., which we'll cover later.  &lt;/p&gt;

&lt;h3&gt;
  
  
  How to develop a plug-in?
&lt;/h3&gt;

&lt;p&gt;Google released the Go language API &lt;a href="https://go.dev/blog/protobuf-apiv2" rel="noopener noreferrer"&gt;1&lt;/a&gt;, which introduces a new package &lt;code&gt;google.golang.org/protobuf/compile R/protogen&lt;/code&gt;, which greatly reduces the difficulty of plugins development:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First of all, we create a go language project, such as &lt;code&gt;protoc-gen-go-spprpc&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Then we need to define a &lt;code&gt;protogen.Options&lt;/code&gt;, then call its &lt;code&gt;Run&lt;/code&gt; method, and pass in a &lt;code&gt;func(*protogen.Plugin) error&lt;/code&gt; callback. This is the end of the main process code.&lt;/li&gt;
&lt;li&gt;We can also set the ParamFunc parameter of &lt;code&gt;protogen.Options&lt;/code&gt;, so that &lt;code&gt;protogen&lt;/code&gt; will automatically parse the parameters passed by the command line for us. Operations such as reading and decoding &lt;code&gt;protobuf&lt;/code&gt; information from standard input, encoding input information into &lt;code&gt;protobuf&lt;/code&gt; and writing stdout are all handled by &lt;code&gt;protogen&lt;/code&gt;. What we need to do is to interact with &lt;code&gt;protogen.Plugin&lt;/code&gt; to implement code generation logic.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The most important thing for each service is the name of the service, and then each service has a set of methods. For the method defined by the service, the most important thing is the name of the method, as well as the name of the input parameter and the output parameter type. Let's first define a &lt;code&gt;ServiceData&lt;/code&gt; to describe the meta information of the service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// ServiceData &lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ServiceData&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;PackageName&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;  
    &lt;span class="n"&gt;ServiceName&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;  
    &lt;span class="n"&gt;MethodList&lt;/span&gt;  &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Method&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;// Method &lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Method&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;MethodName&lt;/span&gt;     &lt;span class="kt"&gt;string&lt;/span&gt;  
    &lt;span class="n"&gt;InputTypeName&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt;  
    &lt;span class="n"&gt;OutputTypeName&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then comes the main logic, and the code generation logic, and finally the call to &lt;code&gt;tmpl&lt;/code&gt; to generate the code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;protogen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gen&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;protogen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Plugin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
       &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Files&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Generate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
             &lt;span class="k"&gt;continue&lt;/span&gt;  
          &lt;span class="p"&gt;}&lt;/span&gt;  
          &lt;span class="n"&gt;generateFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
       &lt;span class="p"&gt;}&lt;/span&gt;  
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;  
    &lt;span class="p"&gt;})&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="c"&gt;// generateFile function definition&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;generateFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gen&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;protogen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Plugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;protogen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GeneratedFilenamePrefix&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"_rpc.pb.go"&lt;/span&gt;  
    &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewGeneratedFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GoImportPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"service"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tmplService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
       &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error parsing template: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="n"&gt;packageName&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GoPackageName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="c"&gt;// Iterate over each service to generate code&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
       &lt;span class="n"&gt;serviceData&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ServiceData&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;  
          &lt;span class="n"&gt;ServiceName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GoName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
          &lt;span class="n"&gt;PackageName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;packageName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
       &lt;span class="p"&gt;}&lt;/span&gt;  
       &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Methods&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
          &lt;span class="n"&gt;inputType&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GoIdent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GoName&lt;/span&gt;  
          &lt;span class="n"&gt;outputType&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Output&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GoIdent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GoName&lt;/span&gt;  

          &lt;span class="n"&gt;serviceData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MethodList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serviceData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MethodList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Method&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;  
             &lt;span class="n"&gt;MethodName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GoName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
             &lt;span class="n"&gt;InputTypeName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;inputType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
             &lt;span class="n"&gt;OutputTypeName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;outputType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
          &lt;span class="p"&gt;})&lt;/span&gt;  
       &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="c"&gt;// Perform template rendering&lt;/span&gt;
       &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serviceData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
       &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
          &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error executing template: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
       &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Debug plugin
&lt;/h3&gt;

&lt;p&gt;Finally, we put the compiled binary execution file &lt;code&gt;protoc-gen-go-spprpc&lt;/code&gt; in &lt;code&gt;$PATH&lt;/code&gt;, and then run &lt;code&gt;protoc&lt;/code&gt; to generate the code we want.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;protoc &lt;span class="nt"&gt;--go_out&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;.. &lt;span class="nt"&gt;--go-spprpc_out&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;.. HelloService.proto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because &lt;code&gt;protoc-gen-go-spprpc&lt;/code&gt; has to depend on &lt;code&gt;protoc&lt;/code&gt; to run, it's a bit tricky to debug. We can use&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stderr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Fprintln: %v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To print the error log to debug.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;That's all there is to this article. We first implemented an &lt;code&gt;RPC&lt;/code&gt; call using protobuf and then created a &lt;code&gt;protobuf&lt;/code&gt; plugin to help us generate the code. This opens the door for us to learn &lt;code&gt;protobuf&lt;/code&gt; + &lt;code&gt;RPC&lt;/code&gt;, and is our path to a thorough understanding of gRPC. I hope everyone can master this technology.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://taoshu.in/go/create-protoc-plugin.html" rel="noopener noreferrer"&gt;https://taoshu.in/go/create-protoc-plugin.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://chai2010.cn/advanced-go-programming-book/ch4-rpc/ch4-02-pb-intro.html" rel="noopener noreferrer"&gt;https://chai2010.cn/advanced-go-programming-book/ch4-rpc/ch4-02-pb-intro.html&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>go</category>
      <category>protobuf</category>
    </item>
    <item>
      <title>RPC Action EP1: Implement a simple RPC interface in Go</title>
      <dc:creator>huizhou92</dc:creator>
      <pubDate>Mon, 09 Sep 2024 08:25:49 +0000</pubDate>
      <link>https://dev.to/huizhou92/rpc-action-ep1-implement-a-simple-rpc-interface-in-go-1m96</link>
      <guid>https://dev.to/huizhou92/rpc-action-ep1-implement-a-simple-rpc-interface-in-go-1m96</guid>
      <description>&lt;p&gt;RPC(Remote Procedure Call)is a widely used communication method between different nodes in distributed systems and a foundational technology of the Internet era. Go's standard library provides a simple implementation of RPC under the &lt;code&gt;net/rpc&lt;/code&gt; package. This article aims to help you understand RPC by walking you through implementing a simple RPC interface using the &lt;code&gt;net/rpc&lt;/code&gt; package.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This article was first published in the Medium MPP plan. If you are a Medium user, please follow me on &lt;a href="https://medium.huizhou92.com/" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;. Thank you very much.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To enable a function to be remotely called in &lt;code&gt;net/rpc&lt;/code&gt;, it must meet the following &lt;a href="https://go.googlesource.com/go/blob/9177e12ccc2115e44de824ae7247ace88617c29a/src/net/rpc/server.go#L13" rel="noopener noreferrer"&gt;five conditions&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;The method’s type is exported.&lt;/li&gt;
&lt;li&gt;The method is exported.&lt;/li&gt;
&lt;li&gt;The method has two arguments, both of which are exported (or built-in) types.&lt;/li&gt;
&lt;li&gt;The method’s second argument is a pointer.&lt;/li&gt;
&lt;li&gt;The method has a return type of error.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;In other words, the function signature must be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;MethodName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argType&lt;/span&gt; &lt;span class="n"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;replyType&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;T2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating a Simple RPC Request
&lt;/h2&gt;

&lt;p&gt;Based on these five conditions, we can construct a simple RPC interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;HelloService&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;  
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;HelloService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HelloService Hello"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hello:"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;  
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, you can register an object of the &lt;code&gt;HelloService&lt;/code&gt; type as an RPC service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RegisterName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HelloService"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HelloService&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  
    &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;":1234"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ListenTCP error:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Accept&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
           &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Accept error:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
        &lt;span class="p"&gt;}&lt;/span&gt;  
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;rpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServeConn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The client-side implementation is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;":1234"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"net.Dial:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;rpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HelloService.Hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, the client dials the RPC service using &lt;code&gt;rpc.Dial&lt;/code&gt;, then invokes a specific RPC method via &lt;code&gt;client.Call()&lt;/code&gt;. The first parameter is the RPC service name and method name combined with a dot, the second is the input, and the third is the return value, which is a pointer. This example demonstrates how easy it is to use RPC.&lt;/p&gt;

&lt;p&gt;In both the server and client code, we need to remember the RPC service name &lt;code&gt;HelloService&lt;/code&gt; and the method name &lt;code&gt;Hello&lt;/code&gt;. This can easily lead to errors during development, so we can wrap the code slightly by abstracting the common parts. The complete code is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// server.go&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;ServerName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"HelloService"&lt;/span&gt;  

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;HelloServiceInterface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;RegisterHelloService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;srv&lt;/span&gt; &lt;span class="n"&gt;HelloServiceInterface&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;rpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RegisterName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ServerName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;HelloService&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;  

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;HelloService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HelloService Hello"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hello:"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;  
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RegisterHelloService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HelloService&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  
    &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;":1234"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
       &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ListenTCP error:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
       &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Accept&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
       &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
          &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Accept error:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
       &lt;span class="p"&gt;}&lt;/span&gt;  
       &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;rpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServeConn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// client.go&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;HelloServiceClient&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="n"&gt;HelloServiceInterface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;HelloServiceClient&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;ServerName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"HelloService"&lt;/span&gt; 

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;DialHelloService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;HelloServiceClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;rpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;HelloServiceClient&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;HelloServiceClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ServerName&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;".Hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;DialHelloService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"localhost:1234"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"net.Dial:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;  
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Does it look familiar?&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing JSON Codec with Go's &lt;code&gt;net/rpc&lt;/code&gt; Package
&lt;/h2&gt;

&lt;p&gt;By default, Go's standard RPC library uses Go's proprietary Gob encoding. However, it's straightforward to implement other encodings, such as &lt;code&gt;Protobuf&lt;/code&gt; or &lt;code&gt;JSON&lt;/code&gt;, on top of it. The standard library already supports &lt;code&gt;jsonrpc&lt;/code&gt; encoding, and we can implement JSON encoding by making minor changes to the server and client code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// server.go&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RegisterName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HelloService"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HelloService&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  
    &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;":1234"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
       &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ListenTCP error:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
       &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Accept&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
       &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
          &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Accept error:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
       &lt;span class="p"&gt;}&lt;/span&gt;  
       &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;rpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServeCodec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonrpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServerCodec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  
       &lt;span class="c"&gt;//go rpc.ServeConn(conn)  &lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;//client.go&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;DialHelloService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;HelloServiceClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="c"&gt;//client := rpc.NewClient(conn)  &lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;rpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewClientWithCodec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonrpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewClientCodec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;HelloServiceClient&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The JSON request data object internally corresponds to two structures: on the client side, it's &lt;a href="https://go.googlesource.com/go/blob/9177e12ccc2115e44de824ae7247ace88617c29a/src/net/rpc/jsonrpc/client.go#L46" rel="noopener noreferrer"&gt;clientRequest&lt;/a&gt;, and on the server side, it's &lt;a href="https://go.googlesource.com/go/blob/9177e12ccc2115e44de824ae7247ace88617c29a/src/net/rpc/jsonrpc/server.go#L46" rel="noopener noreferrer"&gt;serverRequest&lt;/a&gt;. The content of &lt;code&gt;clientRequest&lt;/code&gt; and &lt;code&gt;serverRequest&lt;/code&gt; structures is essentially the same:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;clientRequest&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;Method&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"method"`&lt;/span&gt;  
    &lt;span class="n"&gt;Params&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt; &lt;span class="s"&gt;`json:"params"`&lt;/span&gt;  
    &lt;span class="n"&gt;Id&lt;/span&gt;     &lt;span class="kt"&gt;uint64&lt;/span&gt; &lt;span class="s"&gt;`json:"id"`&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;serverRequest&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;Method&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;           &lt;span class="s"&gt;`json:"method"`&lt;/span&gt;  
    &lt;span class="n"&gt;Params&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RawMessage&lt;/span&gt; &lt;span class="s"&gt;`json:"params"`&lt;/span&gt;  
    &lt;span class="n"&gt;Id&lt;/span&gt;     &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RawMessage&lt;/span&gt; &lt;span class="s"&gt;`json:"id"`&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;Method&lt;/code&gt; represents the service name composed of &lt;code&gt;serviceName&lt;/code&gt; and &lt;code&gt;Method&lt;/code&gt;. The first element of &lt;code&gt;Params&lt;/code&gt; is the parameter, and &lt;code&gt;Id&lt;/code&gt; is a unique call number maintained by the caller, used to distinguish requests in concurrent scenarios.&lt;/p&gt;

&lt;p&gt;We can use &lt;code&gt;nc&lt;/code&gt; to simulate the server and then run the client code to see what information the JSON-encoded client sends to the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; nc &lt;span class="nt"&gt;-l&lt;/span&gt; 1234
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;nc&lt;/code&gt; command receives the following data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"method"&lt;/span&gt;:&lt;span class="s2"&gt;"HelloService.Hello"&lt;/span&gt;,&lt;span class="s2"&gt;"params"&lt;/span&gt;:[&lt;span class="s2"&gt;"hello"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;,&lt;span class="s2"&gt;"id"&lt;/span&gt;:0&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is consistent with &lt;a href="https://go.googlesource.com/go/blob/9177e12ccc2115e44de824ae7247ace88617c29a/src/net/rpc/jsonrpc/server.go#L46" rel="noopener noreferrer"&gt;serverRequest&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We can also run the server code and use &lt;code&gt;nc&lt;/code&gt; to send a request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'{"method":"HelloService.Hello","params":["Hello"],"Id":1}'&lt;/span&gt; | nc localhost 1234 
&lt;span class="nt"&gt;---&lt;/span&gt; 
&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt;:1,&lt;span class="s2"&gt;"result"&lt;/span&gt;:&lt;span class="s2"&gt;"hello:Hello"&lt;/span&gt;,&lt;span class="s2"&gt;"error"&lt;/span&gt;:null&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This article introduced the &lt;code&gt;rpc&lt;/code&gt; package from Go's standard library, highlighting its simplicity and powerful performance. Many third-party &lt;code&gt;rpc&lt;/code&gt; libraries are built on top of the &lt;code&gt;rpc&lt;/code&gt; package. This article serves as the first installment in a series on RPC research. In the next article, we will combine &lt;code&gt;protobuf&lt;/code&gt; with RPC and eventually implement our own RPC framework.&lt;/p&gt;

</description>
      <category>go</category>
    </item>
    <item>
      <title>A Deep Dive into CNCF’s Cloud-Native AI Whitepaper</title>
      <dc:creator>huizhou92</dc:creator>
      <pubDate>Sat, 29 Jun 2024 22:03:00 +0000</pubDate>
      <link>https://dev.to/huizhou92/a-deep-dive-into-cncfs-cloud-native-ai-whitepaper-3ic3</link>
      <guid>https://dev.to/huizhou92/a-deep-dive-into-cncfs-cloud-native-ai-whitepaper-3ic3</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F72xkoe3x0ra7c0kypgdp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F72xkoe3x0ra7c0kypgdp.png" alt="Featured image of post A Deep Dive into CNCF’s Cloud-Native AI Whitepaper" width="776" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;During KubeCon EU 2024, CNCF launched its first Cloud-Native AI Whitepaper. This article provides an in-depth analysis of the content of this whitepaper.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In March 2024, during KubeCon EU, the Cloud-Native Computing Foundation (CNCF) released its first detailed whitepaper on Cloud-Native Artificial Intelligence (CNAI) &lt;sup id="fnref:1"&gt;1&lt;/sup&gt;. This report extensively explores the current state, challenges, and future development directions of integrating cloud-native technologies with artificial intelligence. This article will delve into the core content of this whitepaper.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This article is first published in the medium MPP plan. If you are a medium user, please follow me in &lt;a href="https://medium.huizhou92.com/" rel="noopener noreferrer"&gt;medium&lt;/a&gt;. Thank you very much.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What is Cloud-Native AI?
&lt;/h2&gt;

&lt;p&gt;Cloud-Native AI refers to building and deploying artificial intelligence applications and workloads using cloud-native technology principles. This includes leveraging microservices, containerization, declarative APIs, and continuous integration/continuous deployment (CI/CD) among other cloud-native technologies to enhance AI applications’ scalability, reusability, and operability.&lt;/p&gt;

&lt;p&gt;The following diagram illustrates the architecture of Cloud-Native AI, redrawn based on the whitepaper.&lt;br&gt;&lt;br&gt;
 &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnnvbsm4103f5z7u2a50o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnnvbsm4103f5z7u2a50o.png" alt="Pasted image 20240418101533" width="800" height="750"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Relationship between Cloud-Native AI and Cloud-Native Technologies
&lt;/h2&gt;

&lt;p&gt;Cloud-native technologies provide a flexible, scalable platform that makes the development and operation of AI applications more efficient. Through containerization and microservices architecture, developers can iterate and deploy AI models quickly while ensuring high availability and scalability of the system. Kuuch as resource scheduling, automatic scaling, and service discovery.&lt;/p&gt;

&lt;p&gt;The whitepaper provides two examples to illustrate the relationship between Cloud-Native AI and cloud-native technologies, namely running AI on cloud-native infrastructure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hugging Face Collaborates with Microsoft to launch Hugging Face Model Catalog on Azure&lt;sup id="fnref:2"&gt;2&lt;/sup&gt;
&lt;/li&gt;
&lt;li&gt;OpenAI Scaling Kubernetes to 7,500 nodes&lt;sup id="fnref:3"&gt;3&lt;/sup&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Challenges of Cloud-Native AI
&lt;/h2&gt;

&lt;p&gt;Despite providing a solid foundation for AI applications, there are still challenges when integrating AI workloads with cloud-native platforms. These challenges include data preparation complexity, model training resource requirements, and maintaining model security and isolation in multi-tenant environments. Additionally, resource management and scheduling in cloud-native environments are crucial for large-scale AI applications and need further optimization to support efficient model training and inference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Development Path of Cloud-Native AI
&lt;/h2&gt;

&lt;p&gt;The whitepaper proposes several development paths for Cloud-Native AI, including improving resource scheduling algorithms to better support AI workloads, developing new service mesh technologies to enhance the performance and security of AI applications, and promoting innovation and standardization of Cloud-Native AI technology through open-source projects and community collaboration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloud-Native AI Technology Landscape
&lt;/h2&gt;

&lt;p&gt;Cloud-Native AI involves various technologies, ranging from containers and microservices to service mesh and serverless computing. Kubernetes plays a central role in deploying and managing AI applications, while service mesh technologies such as Istio and Envoy provide robust traffic management and security features. Additionally, monitoring tools like Prometheus and Grafana are crucial for maintaining the performance and reliability of AI applications.&lt;/p&gt;

&lt;p&gt;Below is the Cloud-Native AI landscape diagram provided in the whitepaper.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kubernetes&lt;/li&gt;
&lt;li&gt;Volcano&lt;/li&gt;
&lt;li&gt;Armada&lt;/li&gt;
&lt;li&gt;Kuberay&lt;/li&gt;
&lt;li&gt;Nvidia NeMo&lt;/li&gt;
&lt;li&gt;Yunikorn&lt;/li&gt;
&lt;li&gt;Kueue&lt;/li&gt;
&lt;li&gt;Flame&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Distributed Training
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Kubeflow Training Operator&lt;/li&gt;
&lt;li&gt;Pytorch DDP&lt;/li&gt;
&lt;li&gt;TensorFlow Distributed&lt;/li&gt;
&lt;li&gt;Open MPI&lt;/li&gt;
&lt;li&gt;DeepSpeed&lt;/li&gt;
&lt;li&gt;Megatron&lt;/li&gt;
&lt;li&gt;Horovod&lt;/li&gt;
&lt;li&gt;Apla&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ML Serving
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Kserve&lt;/li&gt;
&lt;li&gt;Seldon&lt;/li&gt;
&lt;li&gt;VLLM&lt;/li&gt;
&lt;li&gt;TGT&lt;/li&gt;
&lt;li&gt;Skypilot&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  CI/CD — Delivery
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Kubeflow Pipelines&lt;/li&gt;
&lt;li&gt;Mlflow&lt;/li&gt;
&lt;li&gt;TFX&lt;/li&gt;
&lt;li&gt;BentoML&lt;/li&gt;
&lt;li&gt;MLRun&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Data Science
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Jupyter&lt;/li&gt;
&lt;li&gt;Kubeflow Notebooks&lt;/li&gt;
&lt;li&gt;PyTorch&lt;/li&gt;
&lt;li&gt;TensorFlow&lt;/li&gt;
&lt;li&gt;Apache Zeppelin&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Workload Observability
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Prometheus&lt;/li&gt;
&lt;li&gt;Influxdb&lt;/li&gt;
&lt;li&gt;Grafana&lt;/li&gt;
&lt;li&gt;Weights and Biases (wandb)&lt;/li&gt;
&lt;li&gt;OpenTelemetry&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  AutoML
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Hyperopt&lt;/li&gt;
&lt;li&gt;Optuna&lt;/li&gt;
&lt;li&gt;Kubeflow Katib&lt;/li&gt;
&lt;li&gt;NNI&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Governance &amp;amp; Policy
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Kyverno&lt;/li&gt;
&lt;li&gt;Kyverno-JSON&lt;/li&gt;
&lt;li&gt;OPA/Gatekeeper&lt;/li&gt;
&lt;li&gt;StackRox Minder&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Data Architecture
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;ClickHouse&lt;/li&gt;
&lt;li&gt;Apache Pinot&lt;/li&gt;
&lt;li&gt;Apache Druid&lt;/li&gt;
&lt;li&gt;Cassandra&lt;/li&gt;
&lt;li&gt;ScyllaDB&lt;/li&gt;
&lt;li&gt;Hadoop HDFS&lt;/li&gt;
&lt;li&gt;Apache HBase&lt;/li&gt;
&lt;li&gt;Presto&lt;/li&gt;
&lt;li&gt;Trino&lt;/li&gt;
&lt;li&gt;Apache Spark&lt;/li&gt;
&lt;li&gt;Apache Flink&lt;/li&gt;
&lt;li&gt;Kafka&lt;/li&gt;
&lt;li&gt;Pulsar&lt;/li&gt;
&lt;li&gt;Fluid&lt;/li&gt;
&lt;li&gt;Memcached&lt;/li&gt;
&lt;li&gt;Redis&lt;/li&gt;
&lt;li&gt;Alluxio&lt;/li&gt;
&lt;li&gt;Apache Superset&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Vector Databases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Chroma&lt;/li&gt;
&lt;li&gt;Weaviate&lt;/li&gt;
&lt;li&gt;Quadrant&lt;/li&gt;
&lt;li&gt;Pinecone&lt;/li&gt;
&lt;li&gt;Extensions&lt;/li&gt;
&lt;li&gt;Redis&lt;/li&gt;
&lt;li&gt;Postgres SQL&lt;/li&gt;
&lt;li&gt;ElasticSearch&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Model/LLM Observability
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;• Trulens&lt;/li&gt;
&lt;li&gt;Langfuse&lt;/li&gt;
&lt;li&gt;Deepchecks&lt;/li&gt;
&lt;li&gt;OpenLLMetry&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Finally, the following key points are summarized:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Role of Open Source Community&lt;/strong&gt; : The whitepaper indicates the role of the open-source community in advancing Cloud-Native AI, including accelerating innovation and reducing costs through open-source projects and extensive collaboration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Importance of Cloud-Native Technologies&lt;/strong&gt; : Cloud-Native AI, built according to cloud-native principles, emphasizes the importance of repeatability and scalability. Cloud-native technologies provide an efficient development and operation environment for AI applications, especially in resource scheduling and service scalability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Existing Challenges&lt;/strong&gt; : Despite bringing many advantages, Cloud-Native AI still faces challenges in data preparation, model training resource requirements, and model security and isolation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Future Development Directions&lt;/strong&gt; : The whitepaper proposes development paths including optimizing resource scheduling algorithms to support AI workloads, developing new service mesh technologies to enhance performance and security, and promoting technology innovation and standardization through open-source projects and community collaboration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key Technological Components&lt;/strong&gt; : Key technologies involved in Cloud-Native AI include containers, microservices, service mesh, and serverless computing, among others. Kubernetes plays a central role in deploying and managing AI applications, while service mesh technologies like Istio and Envoy provide necessary traffic management and security.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more details, please download the Cloud-Native AI whitepaper &lt;sup id="fnref:4"&gt;4&lt;/sup&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference Links
&lt;/h2&gt;




&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.cncf.io/reports/cloud-native-artificial-intelligence-whitepaper/" rel="noopener noreferrer"&gt;Whitepaper:&lt;/a&gt; ↩︎&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://huggingface.co/blog/hugging-face-endpoints-on-azure" rel="noopener noreferrer"&gt;Hugging Face Collaborates with Microsoft to launch Hugging Face Model Catalog on Azure&lt;/a&gt; ↩︎&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://openai.com/research/scaling-kubernetes-to-7500-nodes" rel="noopener noreferrer"&gt;OpenAI Scaling Kubernetes to 7,500 nodes:&lt;/a&gt; ↩︎&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.cncf.io/reports/cloud-native-artificial-intelligence-whitepaper/" rel="noopener noreferrer"&gt;Cloud-Native AI Whitepaper:&lt;/a&gt; ↩︎&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>cncf</category>
      <category>go</category>
    </item>
    <item>
      <title>If Google No Longer supports Golang</title>
      <dc:creator>huizhou92</dc:creator>
      <pubDate>Sat, 29 Jun 2024 22:01:00 +0000</pubDate>
      <link>https://dev.to/huizhou92/if-google-no-longer-supports-golang-meo</link>
      <guid>https://dev.to/huizhou92/if-google-no-longer-supports-golang-meo</guid>
      <description>&lt;p&gt;Last month’s hot topic in IT circles was Google laying off many developers from its Python core team and flutter/dart team, purportedly for a city-wide reorganization.&lt;br&gt;&lt;br&gt;
&lt;a href="https://news.ycombinator.com/item?id=40171125" rel="noopener noreferrer"&gt;https://news.ycombinator.com/item?id=40171125&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Reportedly, those laid off were mostly core members responsible for important Python maintenance.&lt;br&gt;&lt;br&gt;
As a gopher, I pondered: will Google abandon Go? And if so, what would become of Go?&lt;/p&gt;

&lt;h2&gt;
  
  
  What does Google offer to Go?
&lt;/h2&gt;

&lt;p&gt;Based on our past understanding clarified by &lt;a class="mentioned-user" href="https://dev.to/lance"&gt;@lance&lt;/a&gt; Taylor and descriptions from various sources, we can estimate what Go has likely received from Google.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Job Positions&lt;/strong&gt; : Details regarding job positions of members of the Go core team, including compensation, benefits, and other remuneration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Software and Hardware Resources&lt;/strong&gt; : Information on Go-related resources such as intellectual property, servers, domain names, and module management mirrors required by the community.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offline Activities&lt;/strong&gt; : Possibility of reduced or scaled-down Go conferences worldwide in terms of funding and endorsement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internal Resources of Big Corporations&lt;/strong&gt; : Gradual loss of exposure to advanced projects and opportunities for Go’s adoption due to the absence of resources within Google.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Promotion and Feedback Channels&lt;/strong&gt; : Slower discovery and response to significant issues and features in Go as Google’s internal demands historically take precedence.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Potential Scenarios
&lt;/h2&gt;

&lt;p&gt;What might happen if Google dissolves the Go core team and ceases all infrastructure support?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dissolution of the Go core team, leading members may retire or seek employment elsewhere.&lt;/li&gt;
&lt;li&gt;If Google decides to cease all investment in Go, maintenance of Go could become more complex as it relies heavily on infrastructure. In such a scenario, Go might transition from Google to an external foundation, resulting in noticeable maintenance fluctuations.&lt;/li&gt;
&lt;li&gt;If Google chooses to continue investing in Go through other internal teams, the worst-case scenario could involve Google flexing its ownership of intellectual property, possibly leading to Go being rebranded.&lt;/li&gt;
&lt;li&gt;CNCF might take over Google’s mantle, organizing the future development of Go. Among CNCF projects, the Go language enjoys the widest adoption.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Probability of Occurrence
&lt;/h2&gt;

&lt;p&gt;Currently, Go belongs to Google Cloud. Considering Go’s current trend focusing on customer success, the likelihood of Google Cloud shutting down Go is low. But who knows? I consulted &lt;code&gt;gemini&lt;/code&gt; on this question.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmwhv2d1518ghy4xhrzha.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmwhv2d1518ghy4xhrzha.png" width="800" height="269"&gt;&lt;/a&gt;generated by Gemini&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Drawing from the example of Rust, which transitioned from Mozilla’s core to an independent foundation, Go could potentially thrive even more. A nonprofit organization will probably form around Go (or it may directly join CNCF), with enough support from major companies, at least for a period.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ajmani.net/2024/02/23/go-2019-2022-becoming-a-cloud-team/" rel="noopener noreferrer"&gt;https://ajmani.net/2024/02/23/go-2019-2022-becoming-a-cloud-team/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.reddit.com/r/golang/comments/1cft7mc/if_google_decided_to_part_with_the_core_go_team/" rel="noopener noreferrer"&gt;https://www.reddit.com/r/golang/comments/1cft7mc/if_google_decided_to_part_with_the_core_go_team/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>google</category>
      <category>go</category>
    </item>
    <item>
      <title>Why Did Google Choose To Implement gRPC Using HTTP/2?</title>
      <dc:creator>huizhou92</dc:creator>
      <pubDate>Thu, 23 May 2024 09:35:13 +0000</pubDate>
      <link>https://dev.to/huizhou92/why-did-google-choose-to-implement-grpc-using-http2-197a</link>
      <guid>https://dev.to/huizhou92/why-did-google-choose-to-implement-grpc-using-http2-197a</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://grpc.io/" rel="noopener noreferrer"&gt;gRPC&lt;/a&gt; is an open-source high-performance RPC framework developed by Google. The design goal of gRPC is to run in any environment, supporting pluggable load balancing, tracing, health checking, and authentication. It not only supports service calls within and across data centers but is also suitable for the last mile of distributed computing, connecting devices, mobile applications, and browsers to backend services. For more on the motivation and principles behind gRPC's design, refer to this article: &lt;a href="https://grpc.io/blog/principles" rel="noopener noreferrer"&gt;gRPC Motivation and Design Principles&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This article is first published in the medium MPP plan. If you are a medium user, please follow me in &lt;a href="https://medium.hxzhouh.com/" rel="noopener noreferrer"&gt;medium&lt;/a&gt;. Thank you very much.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Key points from the official article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Internally, there is a framework called Stubby, but it is not based on any standard.&lt;/li&gt;
&lt;li&gt;Supports use in any environment, including IoT, mobile, and browsers.&lt;/li&gt;
&lt;li&gt;Supports streaming and flow control.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In reality, performance is not the primary goal of gRPC design. So why choose HTTP/2?&lt;/p&gt;

&lt;h2&gt;
  
  
  What is HTTP/2
&lt;/h2&gt;

&lt;p&gt;Before discussing why gRPC chose HTTP/2, let's briefly understand HTTP/2.&lt;br&gt;&lt;br&gt;
HTTP/2 can be simply introduced with an image:&lt;br&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.hxzhouh.com%2Fblog-images%2F2024%2F05%2Fae09920e853bee0b21be83f8e770ba01.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.hxzhouh.com%2Fblog-images%2F2024%2F05%2Fae09920e853bee0b21be83f8e770ba01.svg" alt="https://hpbn.co/" width="340" height="175"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From: &lt;a href="https://hpbn.co/" rel="noopener noreferrer"&gt;https://hpbn.co/&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The header in HTTP/1 corresponds to the HEADERS frame in HTTP/2.&lt;/li&gt;
&lt;li&gt;The payload in HTTP/1 corresponds to the DATA frame in HTTP/2.
In the Chrome browser, open &lt;code&gt;chrome://net-internals/#http2&lt;/code&gt; to see information about HTTP/2 connections.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7c6etnpk7edzqn1o00ep.png" alt="chrome-http2" width="672" height="401"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many websites are already running on HTTP/2.&lt;/p&gt;
&lt;h2&gt;
  
  
  gRPC Over HTTP/2
&lt;/h2&gt;

&lt;p&gt;Strictly speaking, gRPC is designed in layers, with the underlying layer supporting different protocols. Currently, gRPC supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md" rel="noopener noreferrer"&gt;gRPC over HTTP2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md" rel="noopener noreferrer"&gt;gRPC Web&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, most discussions are based on gRPC over HTTP2. Let's look at a real gRPC &lt;code&gt;SayHello&lt;/code&gt; request and see how it is implemented over HTTP/2 using Wireshark:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi837smjfhrvprhip6i0r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi837smjfhrvprhip6i0r.png" alt="wireshark-grpc" width="679" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see the following headers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Header: :authority: localhost:50051
Header: :path: /helloworld.Greeter/SayHello
Header: :method: POST
Header: :scheme: http
Header: content-type: application/grpc
Header: user-agent: grpc-java-netty/1.11.0  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the request parameters are in the DATA frame:&lt;br&gt;&lt;br&gt;
&lt;code&gt;GRPC Message: /helloworld.Greeter/SayHello, Request&lt;/code&gt;&lt;br&gt;&lt;br&gt;
In short, gRPC puts metadata in HTTP/2 Headers and serialized request parameters in the DATA frame.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advantages of HTTP/2 Protocol
&lt;/h2&gt;

&lt;h3&gt;
  
  
  HTTP/2 is an Open Standard
&lt;/h3&gt;

&lt;p&gt;Google thought this through and chose not to open-source its internal Stubby but to create something new. As technology becomes more open, the space for proprietary protocols is shrinking.&lt;/p&gt;

&lt;h3&gt;
  
  
  HTTP/2 is a Proven Standard
&lt;/h3&gt;

&lt;p&gt;HTTP/2 was developed based on practical experience, which is crucial. Many unsuccessful standards were created by a group of vendors before implementation, leading to chaos and unusability, such as CORBA. HTTP/2's predecessor was Google's &lt;a href="https://en.wikipedia.org/wiki/SPDY" rel="noopener noreferrer"&gt;SPDY&lt;/a&gt;. Without Google's practice and promotion, HTTP/2 might not exist.&lt;/p&gt;

&lt;h3&gt;
  
  
  HTTP/2 Naturally Supports IoT, Mobile, and Browsers
&lt;/h3&gt;

&lt;p&gt;In fact, mobile phones and mobile browsers were the first to adopt HTTP/2. The mobile internet has driven the development and adoption of HTTP/2.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-language Implementation of HTTP/2 is Easy
&lt;/h3&gt;

&lt;p&gt;Discussing only the implementation of the protocol itself, without considering serialization:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every popular programming language has a mature HTTP/2 Client.&lt;/li&gt;
&lt;li&gt;HTTP/2 Clients are well-tested and reliable.&lt;/li&gt;
&lt;li&gt;Sending HTTP/2 requests with a Client is much easier than sending/receiving packets with sockets.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  HTTP/2 Supports Stream and Flow Control
&lt;/h3&gt;

&lt;p&gt;There are many streaming solutions in the industry, such as those based on WebSocket or &lt;a href="https://github.com/rsocket/rsocket" rel="noopener noreferrer"&gt;rsocket&lt;/a&gt;. However, these solutions are not universal.&lt;br&gt;&lt;br&gt;
Streams in HTTP/2 can also be prioritized, which might be used in complex scenarios, although less frequently in RPC.&lt;/p&gt;

&lt;h3&gt;
  
  
  Easy Support for HTTP/2 in Gateway/Proxy
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Nginx support for gRPC: &lt;a href="https://www.nginx.com/blog/nginx-1-13-10-grpc/" rel="noopener noreferrer"&gt;https://www.nginx.com/blog/nginx-1-13-10-grpc/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Envoy support for gRPC: &lt;a href="https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/grpc#" rel="noopener noreferrer"&gt;https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/grpc#&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  HTTP/2 Ensures Security
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;HTTP/2 naturally supports SSL, although gRPC can run on a clear text protocol (i.e., unencrypted).&lt;/li&gt;
&lt;li&gt;Many proprietary RPC protocols might wrap a layer of TLS support, making it very complex to use. Do developers have enough security knowledge? Are users configuring it correctly? Can operators understand it correctly?&lt;/li&gt;
&lt;li&gt;HTTP/2 ensures secure transmission over public networks. For example, the &lt;a href="https://en.wikipedia.org/wiki/CRIME" rel="noopener noreferrer"&gt;CRIME attack&lt;/a&gt; is hard to prevent in proprietary protocols.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Mature Authentication in HTTP/2
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Authentication systems developed from HTTP/1 are mature and can be seamlessly used in HTTP/2.&lt;/li&gt;
&lt;li&gt;End-to-end authentication from front-end to back-end without any conversion or adaptation.
For example, traditional RPC like Dubbo requires writing a Dubbo filter and considering how to pass authentication-related information through thread local. The RPC protocol itself also needs to support it. In short, it's very complex. In fact, most RPCs in companies do not have authentication and can be called freely.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Disadvantages of HTTP/2 Protocol
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Inefficient Transmission of RPC Metadata
&lt;/h3&gt;

&lt;p&gt;Although HPAC can compress HTTP Headers, for RPC, determining a function call can be simplified to an int. Once negotiated between both ends, it can be directly looked up in a table, without the need for HPAC encoding and decoding.&lt;br&gt;&lt;br&gt;
Consider optimizing an HTTP/2 parser specifically for gRPC to reduce some general processing and improve performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  gRPC Calls in HTTP/2 Require Two Decodings
&lt;/h3&gt;

&lt;p&gt;One for the HEADERS frame and one for the DATA frame.&lt;/p&gt;

&lt;p&gt;The HTTP/2 standard itself only allows one TCP connection, but in practice, gRPC may have multiple TCP connections, which needs attention during use.&lt;br&gt;&lt;br&gt;
Choosing HTTP/2 for gRPC means its performance won't be top-notch. &lt;strong&gt;But for RPC, moderate QPS is acceptable&lt;/strong&gt;, and generality and compatibility are the most important. Refer to the official benchmark: &lt;a href="https://grpc.io/docs/guides/benchmarking.html" rel="noopener noreferrer"&gt;https://grpc.io/docs/guides/benchmarking.html&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/hank-whu/rpc-benchmark" rel="noopener noreferrer"&gt;https://github.com/hank-whu/rpc-benchmark&lt;/a&gt;
If your scenario is to...&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Google's Standard-Setting Ability
&lt;/h2&gt;

&lt;p&gt;In the past decade, Google's ability to set standards has grown stronger. Here are some standards:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP/2&lt;/li&gt;
&lt;li&gt;WebP image format&lt;/li&gt;
&lt;li&gt;WebRTC for real-time communication&lt;/li&gt;
&lt;li&gt;VP9/AV1 video encoding standards&lt;/li&gt;
&lt;li&gt;Service Worker/PWA&lt;/li&gt;
&lt;li&gt;QUIC/HTTP/3
Of course, Google doesn't always succeed. Many initiatives it tried to push failed, such as Chrome's Native Client.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;gRPC is currently the de facto standard in the Kubernetes ecosystem. Will gRPC become the RPC standard in more areas and larger fields?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why gRPC Emerged
&lt;/h2&gt;

&lt;p&gt;Why did an HTTP/2-based RPC emerge?&lt;/p&gt;

&lt;p&gt;I believe an important reason is that in the trend of Cloud Native, the need for open interoperability inevitably leads to HTTP/2-based RPC. Even without gRPC, there would be other HTTP/2-based RPCs.&lt;/p&gt;

&lt;p&gt;gRPC was first used internally at Google on Google Cloud Platform and public APIs: &lt;a href="https://opensource.google.com/projects/grpc" rel="noopener noreferrer"&gt;https://opensource.google.com/projects/grpc&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Although gRPC may not replace internal RPC implementations, in an era of open interoperability, not just on Kubernetes, gRPC will have more and more stages to showcase its capabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt; &lt;a href="https://grpc.io/" rel="noopener noreferrer"&gt;https://grpc.io/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://hpbn.co/" rel="noopener noreferrer"&gt;https://hpbn.co/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://grpc.io/blog/loadbalancing" rel="noopener noreferrer"&gt;https://grpc.io/blog/loadbalancing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://http2.github.io/faq" rel="noopener noreferrer"&gt;https://http2.github.io/faq&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/grpc/grpc" rel="noopener noreferrer"&gt;https://github.com/grpc/grpc&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>grpc</category>
      <category>http</category>
    </item>
  </channel>
</rss>
