<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Abser Blog]]></title><description><![CDATA[Let's build a better world.]]></description><link>https://hashnode.abser.top</link><generator>RSS for Node</generator><lastBuildDate>Sat, 17 Oct 2026 11:48:19 GMT</lastBuildDate><atom:link href="https://hashnode.abser.top/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Open Source History of Dapr project]]></title><description><![CDATA[At the beginning of this open-source column, I wrote this article to describe the birth and development of open-source projects, express my views on the open-source community and ecology, and share it with you. 
Some opinions are out of personal pers...]]></description><link>https://hashnode.abser.top/open-source-history-of-dapr-project</link><guid isPermaLink="true">https://hashnode.abser.top/open-source-history-of-dapr-project</guid><category><![CDATA[Open Source]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[Go Language]]></category><category><![CDATA[dapr]]></category><dc:creator><![CDATA[Abser·Ari]]></dc:creator><pubDate>Sun, 17 Jul 2022 04:46:34 GMT</pubDate><content:encoded><![CDATA[<p>At the beginning of this open-source column, I wrote this article to describe the birth and development of open-source projects, express my views on the open-source community and ecology, and share it with you. </p>
<p>Some opinions are out of personal perspective, and there are inevitably some mistakes and mistakes. Please forgive me and correct me. </p>
<h2 id="heading-background">Background</h2>
<p>before the birth of the Dapr project, I would like to explain the current situation of the Dapr project for readers to understand the project itself. </p>
<p>Dapr is a CNCF community-driven open source project with Microsoft as its contributor. Microsoft, according to the author, the first author should be Bai Haishi and Yaron (he is also the author of the Dapr Learning Manual, who proposed OAM and Dapr). </p>
<p>The work objectives of the Dapr project are described as follows: </p>
<p>Dapr is a portable, event-driven runtime that enables any developer to quickly build flexible, stateless, and stateful applications that can run on cloud platforms or edge computing. 
Some community students think Dapr is the next form of the service mesh, and some people also call this runtime software of the new era mecha (mecha), mecha provides distributed capabilities for business applications, just like the operator wearing a mecha, to do what he could not have done.</p>
<p>The following figure shows Bilgin Ibryam. Multi-Runtime Microservices Architecture </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1658032639778/CRnDlZMU-.png" alt="image.png" /></p>
<p>therefore, the Dapr project is open-source software that provides distributed capabilities for modern distributed applications. Currently, it is open-source on GitHub and has gained 18.6K stars, which is very popular. </p>
<h2 id="heading-birth">Birth</h2>
<p>Tracing back to open source on GitHub, the first submission was on June 21, 2019, 
the birth of open-source projects is usually accompanied by the discovery of practical problems. </p>
<p>Before saying the problems solved by the Dapr project, there is another project that has to be mentioned, Microsoft's OAM(Open Application Model). </p>
<p>The two projects have been known to the public for 19 years. I remember that the co-sponsor of OAM is Ali. At that time, Kubernetes was very popular, and the problems on the computing scheduling platform were Kubernetes solved by Golang's killer application. </p>
<p>However, using Kubernetes puts forward more and higher requirements for Developers, especially its new concept, which covers different APIs and unique working methods. </p>
<p>How to solve this problem? </p>
<p>Any problem in the field of computer science can be solved by adding an indirect intermediate layer.</p>
<p>It is believed that smart readers, based on their current knowledge, have already thought that if a new design language can be used as the middle layer to block the similarities and differences of infrastructure developers do not need to pay attention to and focus on business coding, can it be solved? </p>
<p>In this way, OAM is naturally ready to come out. (If you are concerned about OAM, you can learn about the implementation of this project standard in Alibaba, namely Kubevela project, this project has great potential)</p>
<p>Dapr came up with an idea when Bai Haishi and his Israeli colleagues discussed OAM Yaron Schneider. It designed a new programming mode to encapsulate the common functions of the distributed system into Sidecar(Kubernetes concept, description, and business application in the same Pod container) and expose them to developers through HTTP or gRPC (two common transmission modes, which are compatible with most applications). </p>
<p>The idea is named Distributed Application Runtime, or Dapr for short. [This paragraph is taken from an interview with Bai Haishi, the founder of OAM and DAPR: a simple idea of a 33-year senior programmer -Zhang Shanyou]] </p>
<p>Dapr provides several new features to help solve the problems: </p>
<p>the first is to provide services in the form of Sidecar. In the container orchestration platform, Sidecar provides services in a non-intrusive way. </p>
<p>For example, Envoy Sidecar acts as a proxy for routing and forwarding. It is independent of major applications and therefore has cross-language features. Users can reuse logic without binding to a programming language, which is especially useful in the microservice era. </p>
<p>The second is the concept of Building Block, which allows Dapr users to customize different Building blocks, instead of forcing users to use distributed functions provided by Dapr for all functions.</p>
<h2 id="heading-open-source">Open source</h2>
<p>After talking for so long, I finally talked about the open-source features of the Dapr project. 
The benefits of open source can be seen in the summary of my other article. This article will not go into detail, but mainly explore the reasons why Dapr needs to open source and provide material examples for everyone to understand the open source operation mode. </p>
<p>Dapr can be analyzed from the positioning of its general distributed runtime software, and the standard is its core! </p>
<p>Standards cannot be achieved by one person or a company. It is necessary to strengthen Dapr's influence and promote its designation of standards that are uniformly recognized by everyone. It is the only choice to establish a community of common contributions through open source.</p>
<p>It is not only a matter of standards. Dapr, as an application in the new era, naturally has many new ideas, which need to be verified. A large number of engineers need to be invested in the verification of the programming mode. </p>
<p>This part of manpower expenditure and verification cost is extremely large. The continuous development of the project can only be supported by the rapid discussion of design, implementation, and community verification in the form of Community co-construction. </p>
<p>Therefore, human resources are also considered in most open-source projects. </p>
<p>Finally, reach users. </p>
<p>When Dapr is a user-oriented project, there are developers who are more enthusiastic than open-source communities. Open-source is the best choice to make Dapr's development closer to users and the wide application of cloud developers that it wants to achieve. </p>
<p>We recommend two projects to observe the popularity and activity distribution of open-source projects ( Star-History and OSSInsight ), which are Bytebase and PingCap open-source tools. One picture wins thousands of words, and two pictures are attached to show its function. </p>
<p>Figure 1: Star harvest trend of open source Dapr project</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1658032918444/FsLL7iu_d.png" alt="image.png" /></p>
<h2 id="heading-development">Development</h2>
<p>Since the Dapr project is to serve developers, it is natural to investigate the main functions that developers use in the programming and provide them to users as different building blocks. </p>
<p>Currently, the capabilities it provides include state management, service development, message sending and receiving, publishing and subscription, security information management, Actor mode (originated from the Orleans project in Microsoft's dotnet ecosystem), etc. In the initial form of state management development, concurrent control, version management, and other capabilities are also added. </p>
<p>Now, building blocks such as distributed locks and workflows are gradually added. These new functions and new building blocks are all built by community users' needs.</p>
<p>It can be seen from this that Dapr's open source strategy has achieved remarkable results. </p>
<p>The emergence of Dapr also coincides with the wave of XaaS. It reduces the occupation of the edge environment (more than 50 M binary, only 4 M memory is needed during operation), provides edge devices and applications with low capability, flexibly switches between edge environment and cloud, and supports multiple operating environments, which are its excellent sources of competitiveness. </p>
<p>The development evaluation of an open source project must pay attention to its related ecology. Dapr, as a similar infrastructure project, will discuss two ecosystems. </p>
<p>One is the ecosystem that supports the Dapr project operation. That is, driven by various Building blocks, their ecology determines which infrastructure Dapr users can apply.</p>
<p>Take PubSub as an example. Common message queue drivers such as Kafka, Redis, NatsStreaming, and Pulsar provide the runtime capability in the publish/subscribe mode. </p>
<p>The ecosystem in this area is rich and colorful. The core problem is that drivers are contributed to the community by themselves. The code quality and the functions provided during application runtime are uneven. It can be seen that the idea of standardization cannot be easily achieved in the real world. </p>
<p>One is the Dapr-based project built on it. This ecology can also be reflected in the cases where most companies use Dapr. </p>
<p>The main users of Dapr started from the founders Microsoft and Ali, and now companies such as Qingyun have participated in the co-construction and produced many projects and practical cases. </p>
<p>Taking Microsoft as an example, users who serve it can easily and painlessly switch the underlying dependencies on the cloud (for example, switching message queues from Rabbitmq to kafka). 
For example, Alibaba provides a large number of distributed capabilities for function applications in its functional computing platform. 
For example, Ant Financial has developed a layotto project based on its excellent ServiceMesh development experience, IT has implemented the distributed runtime concept that conforms to its own IT infrastructure (and is open-source).
For example, Qingyun's Openfunction is also built using Dapr in the function computing platform.</p>
<p>Even Microsoft has launched a commercial product container app based on Dapr, which allows users to write function-level services. The infrastructure is provided by context. 
Dapr provides these services with the choice of only focusing on business code logic. </p>
<p>The developer ecosystem of open-source projects is an important criterion. The number of issues created, the speed of response, the richness of proposal submission, the degree of the active contributor, the entry and loss of new contributors and core contributors, and other indicators are all important bases for us to evaluate the developer ecosystem. This section can praise ossinsight project, which provides you with query services through the website and provides us with powerful data for evaluating open-source projects. </p>
<p>Figure 2: analysis of open source activities of the Dapr project</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1658033060286/sUkAuPA7c.png" alt="image.png" /></p>
<h2 id="heading-trend">Trend</h2>
<p>competition trend of domain software: Hot open-source projects actually symbolize the main competition fields in the current industry. PaaS, which took Kubernetes as the core in the past few years, IaaS, which was recently represented by Infra as Code, DevOps and Security, and SaaS and FaaS, which will further compete fiercely in the future, provide better value-added services. Different fields have their own solutions. We can see how to provide more valuable services from the open-source ecosystem. </p>
<p>The development trend of programmers: modern developers are generally faced with anxiety problems. As programmers, some of our work contents are boring, but with the passion for programming and the pursuit of a career, we can develop various innovative achievements in our daily work, which may not only achieve ourselves but also benefit the world. At the industry level and even at the national level, open source is embraced. Under such a development trend, open source will integrate young programmers as one of the popular cultures. 
My personal advice is to understand the open source as soon as possible, embrace him, and become a compound talent. The next step for programmers is to explore the open source field. </p>
<p>And this article has roughly described the context of the Dapr project. Only from the project ecology of Dapr, we can see the fierce competition in the development of cloud computing. We don't know how many projects are floating and disappearing in the tide, or they never appear in our eyes after a wave of waves. I hope readers can have a deeper understanding and ideas about the software life cycle, especially open-source software.</p>
]]></content:encoded></item><item><title><![CDATA[How did I begin to learn to code: the resources I used in a month]]></title><description><![CDATA[Want to learn how to code? This article will guide you through the jungle of technology and resources to help you go from no knowledge to fast, interactive and modern coding skills, following the forest path I took.
I spent a month learning how to st...]]></description><link>https://hashnode.abser.top/how-did-i-begin-to-learn-to-code-the-resources-i-used-in-a-month</link><guid isPermaLink="true">https://hashnode.abser.top/how-did-i-begin-to-learn-to-code-the-resources-i-used-in-a-month</guid><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Programming Tips]]></category><category><![CDATA[programmer]]></category><dc:creator><![CDATA[Abser·Ari]]></dc:creator><pubDate>Sun, 10 Jul 2022 08:57:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/ylveRpZ8L1s/upload/v1657443424705/WPuhBGYbB.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Want to learn how to code? This article will guide you through the jungle of technology and resources to help you go from no knowledge to fast, interactive and modern coding skills, following the forest path I took.</p>
<p>I spent a month learning how to start coding. Although sometimes challenging, it is a very useful experience.</p>
<p>The most difficult challenge is to choose what to learn and learn it. There are so many languages, frameworks and libraries - and many conflicting suggestions.</p>
<p>Also, some learning resources are much better than others. If I knew which resources to focus on, my progress might be faster.</p>
<p>With this in mind, I think I will share something useful with you. If I feel a lot, I am very lucky. I can spend several hours a day studying these materials.</p>
<p>How fast you do it doesn't reflect your potential as a developer, so don't worry if it takes you longer to complete these materials. However, if you have the time, you can finish it in half a month.</p>
<p>These are the paths I have taken, which does not mean you have to go through them all.</p>
<p>Part I: HTML,CSS and JavaScript</p>
<p>These are the three core languages of all web applications, and it is (almost) impossible to build anything on the web without using them.</p>
<p>HTML</p>
<p>If you have never done any coding before, HTML is a good place to start. It is the core building block of the web. Unlike most other languages, it gives learners real-time visual feedback about the code they are writing.</p>
<p>CSS</p>
<p>CSS is HTML's natural companion. On the surface, it is very simple, although there are some concepts - particularly relating to layout and positioning - that can take some time to understand.</p>
<p>The most difficult part of CSS is understanding the layout. Users asked me most of my layout questions on StackOverflow, so the quick Google search solved most of my problems.</p>
<p>H5 and CSS took me about two days. Usually, when you want to know something about coding, it is always the quickest way to get started directly.</p>
<h3 id="heading-javascript">JavaScript</h3>
<p>HTML and CSS are not fully mature programming languages, so you will not be able to fully understand programming before you begin to learn programming languages. JavaScript is the programming language of the Web.</p>
<p>To be honest, although I tried js programming in junior high school, I can't even count the real Coding. Until now, I am also JavaScript Cainiao, so I can't give some help and suggestions on it.</p>
<p>since I started to learn backend, js only took me a short period of time.</p>
<h3 id="heading-go">GO</h3>
<p>Go is an extremely cool language, especially in modern efficient Web programming.</p>
<p>Go is the language that I choose to learn from the backend, and it is also the language that I prefer to learn more. As a beginner in the language, I still can't distinguish the characteristics and quality of various languages, which usually requires years of coding experience or experience of using multiple languages to be clear.</p>
<p>I have experienced the use of C ++ STL and certain Java coding, but from the perspective of the past, it can only be achieved in more than ten days.</p>
<p>I spent about three days on The Way To Go. Before that, I read The guide for getting started with Go in The Cainiao tutorial. Although this book is relatively brief about the advanced features of the Go language, it is undoubtedly enough as an introduction.</p>
<p>Even if I read English, maybe you prefer reading Chinese books, but as a coding staff, English is undoubtedly the language that must be learned. after that, I did a little crawler practice, involving goquery,gocolly crawled Feilu's novel website first and then crawled various business information of various regions.</p>
<p>This probably took me a day. (Knowledge of reading documents learned from here)</p>
<p>Then I started reading the Go Source Code package, traversing each function of each package through their godoc. When I started reading the internal logic of each function, I was stopped because of the huge knowledge system. It took me about three to four days. (Drawing skills learned from here)</p>
<p>At this time, I started to develop a cloud API access service for sending text messages. At that time, understanding and accessing the Alibaba Cloud market brought me trouble, and it was never easy to find a solution to the demand. It took about a week to learn about the access between go and MySQL and the HTTP communication between different terminals.</p>
<p>The following is the background management of the Carousel graph. Here, I began to learn about table design and learn more about MySQL.</p>
<p>Finish the carousel graph (the more you consider, the more you need to do, but the coding may not be changed, it should follow the power law) and start the design of the order system, which is the most difficult part to learn the background functions.</p>
<p>At the same time, I also spent a lot of time consulting and designing, and also contacted with the use of gorm. After finishing the design of the order system, I got a great improvement because I considered a lot of adaptation to the actual situation. After that, the more difficult business must be the game server.</p>
<p>After that, I completed the background construction of an app, which was combined and spliced by various modules. The difficulty here is mainly in teamwork, so it is not detailed here.</p>
<p>here, my go-to-study process has come to an end.</p>
<h2 id="heading-part-2-other-essential-parts-of-any-developer-toolkit">Part 2: other essential parts of any developer toolkit</h2>
<h3 id="heading-git-and-github">Git and GitHub</h3>
<p>Git is the so-called versioning system, and GitHub is the most popular cloud-based Git Service.</p>
<p>In short, Git allows you to back up files, track changes, share your progress with other developers, and collaborate with projects.</p>
<p>When you have just learned and do not need to use Git, it can feel like a hard job. However, this is worthwhile: most professional developers not only rely on GitHub (or similar services) but also have active GitHub configuration files to help you ensure worker safety.</p>
<p>The earlier you start to hand over your work to GitHub, the more experience you will have as a developer.</p>
<h3 id="heading-command-line">Command line</h3>
<p>the command line is the most important part. It is necessary to understand the operation of the command line. At the same time, it is very simple to learn. There are not only many tutorials on the Internet, but also many private Linux dishes of brother no.</p>
<p>However, my suggestion for tools is that if it is not necessary, I just need to know.</p>
<p>The best way to use Git is through "terminal" or "command line", which is also important for modern Web developers, allowing you to use NPM (Node package manager) or Yarn you can easily add third-party packages to your website. There are also many websites that can help you take this step</p>
<h2 id="heading-part-3-what-is-the-next-step">part 3: What is the next step?</h2>
<p>This is all I have learned in a month.</p>
<blockquote>
<p>The content to be learned includes Kubernetes,Istio, and gRPC. This is a lot of technology, and it is best to know them too!</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[TokenBucket]]></title><description><![CDATA[Overview


available per second Limit put tokens into the bucket, or, every time 1/Limit add a token to the second bucket 
maximum storage in buckets burst tokens. If the bucket is full, the new token will be discarded. 
when an N is consumed when th...]]></description><link>https://hashnode.abser.top/tokenbucket</link><guid isPermaLink="true">https://hashnode.abser.top/tokenbucket</guid><category><![CDATA[algorithms]]></category><category><![CDATA[tokenbucket]]></category><category><![CDATA[ratelimit]]></category><dc:creator><![CDATA[Abser·Ari]]></dc:creator><pubDate>Sun, 10 Jul 2022 08:48:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1657443052340/ysyTQpxK4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-overview">Overview</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657442131915/dUeLDBuYM.png" alt="image.png" /></p>
<ul>
<li>available per second Limit put tokens into the bucket, or, every time 1/Limit add a token to the second bucket </li>
<li>maximum storage in buckets burst tokens. If the bucket is full, the new token will be discarded. </li>
<li>when an N is consumed when the data packet of the unit arrives N tokens, and then send the packet </li>
<li>if the available token in the bucket is less than N, the packet will be cached or discarded </li>
</ul>
<h2 id="heading-token-bucket-algorithm">token bucket algorithm</h2>
<p>the token bucket algorithm is the most commonly used algorithm in network Traffic Shaping (Traffic Shaping) and Rate Limiting (Rate Limiting). </p>
<p>Typically, the token bucket algorithm is used to control the number of data sent to the network and allow the sending of burst data. </p>
<h3 id="heading-overview">overview</h3>
<p>this package is based on the Token Bucket algorithm (Token Bucket) to implement throttling, which is very easy to use. RateLimiter is often used to limit the access rate to some physical or logical resources. It supports three methods, </p>
<ul>
<li>AllowN() If you can't get it, return it immediately.</li>
<li>WaitN() It is temporarily lined up. When the token is sufficient, it may be returned to the position because of the Cancel of Context.</li>
<li>ReserveN() Started directly, but the predecessors dug the pit and filled it. The next request will pay the price for this, and wait until the tokens will make up for the air. There is enough token in the barrel.</li>
</ul>
<h3 id="heading-working-instance">Working instance</h3>
<p>assume that one is working RateLimiter </p>
<h4 id="heading-allow-and-wait">allow and wait</h4>
<p>For a Ratelimiter that generates a token per second, every second without a token, we will add a token 1.</p>
<p> If the Ratelimiter does not use it in 10 seconds, then tokens become 10.0. At this time, a request arrives and requests three tokens, we will serve it from the token in Ratelimiter, tokens to 7.0. After this request, another request comes and requests 10 tokens.</p>
<p> We will from the remaining 7 token cards from RatelimiterFor this request, there are three tokens left, we will get them from the new token produced by Ratelimiter. </p>
<p>We already know that the Ratelimiter produces 1 new token per second, which means that the above request still requires the three commands required for above request. The card requires it to wait for 3 seconds.</p>
<h4 id="heading-reserve">reserve</h4>
<p>Imagine a Ratelimiter generated a token per second, and now it is not used (in the initial state). If an expensive request requires 100 token cards. If we choose to let this request wait for 100 seconds before allowing it to execute, this is obviously ridiculous. </p>
<p>Why do we do nothing but just wait for 100 seconds? A better approach is to allow this request to execute immediately (no different from all), and then postpone the subsequent request to the right time point. </p>
<p>We allow this expensive task to perform immediately and delay the subsequent request for 100 seconds. This strategy is to let the task execute and wait at the same time.</p>
<h4 id="heading-about-timetoact">About timetoact</h4>
<p>An important conclusion: Ratelimit does not remember the last request, but the next request allows the time to execute. This can also tell us very straightforwardly that the time interval of reaching the next scheduling time point. </p>
<p>The Ratelimiter is also very simple: the next scheduling time has passed. The difference between this time and the current time is how long the Ratelimiter has not been used. We will translate this time into tokens.Limit == 1), and just one request per second, then tokens will not grow.</p>
<h4 id="heading-burst">burst</h4>
<p>Ratelimiter has a barrel capacity that is directly discarded when the request is greater than the capacity of this barrel.</p>
<p>https://github.com/golang/time/blob/master/rate/rate.go</p>
]]></content:encoded></item><item><title><![CDATA[React Hooks State Persistence]]></title><description><![CDATA[this article describes how to analyze and design State persistence management through React Hooks. 


Analysis
Normal frontend, components are class files, maintain their own status, and are not easy to reuse. 
First, separate the UI and status of th...]]></description><link>https://hashnode.abser.top/react-hooks-state-persistence</link><guid isPermaLink="true">https://hashnode.abser.top/react-hooks-state-persistence</guid><category><![CDATA[Redux]]></category><category><![CDATA[React]]></category><category><![CDATA[state]]></category><category><![CDATA[hooks]]></category><dc:creator><![CDATA[Abser·Ari]]></dc:creator><pubDate>Sun, 10 Jul 2022 08:31:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1657441887497/5HjIEoGsH.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>this article describes how to analyze and design State persistence management through React Hooks. </p>
</blockquote>
<p><a></a></p>
<h2 id="heading-analysis">Analysis</h2>
<p>Normal frontend, components are class files, maintain their own status, and are not easy to reuse. </p>
<p>First, separate the UI and status of the component and connect them with Action, as shown in the following figure. <br />
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657440595754/NW6YDPVEi.png" alt="image.png" />
<a target="_blank" href="https://cdn.nlark.com/yuque/0/2019/png/176280/1573654060345-7a199253-b266-4610-8632-066e77adf5c3.png#align=left&amp;display=inline&amp;height=202&amp;name=UI%3Df%28State%29.png&amp;originHeight=202&amp;originWidth=483&amp;size=9830&amp;status=done&amp;width=483">UI=f(State).png</a><br />Action is an operator </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657441035222/Mu-Hkly0q.png" alt="image.png" />
<a target="_blank" href="https://cdn.hashnode.com/res/hashnode/image/upload/v1657440676286/8Q_TMIEZg.png">image.png</a></p>
<p><a></a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657441146096/PdfOku6Mb.png" alt="image.png" /></p>
<p>According to the Hooks, useState() method  <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is#Description"><code>Object.is</code> comparison algorithm</a> <br /></p>
<p>To compare the state. And useEffect() then provide choose to let it when <a target="_blank" href="https://zh-hans.reactjs.org/docs/hooks-reference.html#conditionally-firing-an-effect">only some values change</a></p>
<p><a></a></p>
<h2 id="heading-design">Design</h2>
<p><a></a></p>
<h3 id="heading-virtual-part-mathematical-model">virtual part Mathematical model</h3>
<p>the real number is not complete, and the imaginary part is introduced. </p>
<p>Imaginary number, you only need to remove the imaginary part to represent the real number. </p>
<p>The same is true for Curry Func. </p>
<p>Similarly: f(S,∆) medium f(S) represents a real number, which is incomplete. You can add the preceding statement to indicate all the situations. </p>
<p>The changed dimension changes from a one-dimensional line to a two-dimensional plane. </p>
<p>In addition, the framework uses f(S, ∆) it is still a one-dimensional line, but it is actually any line of the plane because f(S,...) has already been determined by the user, that is, a plane dimension reduction is selected in multiple dimensions in the code. </p>
<p><a></a></p>
<h3 id="heading-persistence">Persistence</h3>
<p>you need to store data in one place, such as local,session, and remote. </p>
<p><a></a></p>
<h3 id="heading-connector">Connector</h3>
<p>how does a component distribute triggered events to the State for processing? Communication is required. 
Due to the js single-thread model, the shared memory design is selected. Add a Connector communication. 
The Component Component is how to notify the State of changes. Shared memory, using Connector middle layer. </p>
<p><a></a></p>
<h3 id="heading-action-by-curryfunc">Action by CurryFunc</h3>
<p>how do I know which states have been changed by the framework user-defined Action? That is, the specific value of azone is unknown. Use Curry Func to meet the requirement of delay evaluation. 
Use fg(S){return f(∆) } replace f(S,∆) 
use the State framework by users themselves f(∆) register your own state change operator. 
State framework for developers fg(S) , just pass in all the State. 
Due to the existence of the React Hooks, the state is used. f(S,∆) the function to update. Therefore, the framework leaves useState() interface and returns f(∆)</p>
<p>For user status management. </p>
<p>Redux is also based on this function model, which has been officially used in Hooks. useReducer(reducer, initialState) it is implemented. The reducer is set f(S,∆) , and it returns state and dispatch, where state is S A and dispatch is f(∆) </p>
<p><a></a></p>
<h4 id="heading-redux">Redux</h4>
<p>Redux is also based on this function model, which has been officially used in Hooks. useReducer(reducer, initialState) it is implemented. The reducer is set f(S,∆) , and it returns state and dispatch, where state is S A and dispatch is f(∆) </p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useReducer</span>(<span class="hljs-params">reducer, initialState</span>) </span>{
  <span class="hljs-keyword">const</span> [state, setState] = useState(initialState);
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">dispatch</span>(<span class="hljs-params">action</span>) </span>{
    <span class="hljs-keyword">const</span> nextState = reducer(state, action);
    setState(nextState);
  }
  <span class="hljs-keyword">return</span> [state, dispatch];
}
</code></pre>
<p>in our view, it also implements Connector internally. </p>
<p><a></a></p>
<h2 id="heading-implementation">Implementation</h2>
<p><a></a></p>
<h4 id="heading-persistence">Persistence</h4>
<p>the first is to implement storage through Hooks, using Local Store </p>
<pre><code class="lang-go">function useLocalJSONStore(key, defaultValue) {
    <span class="hljs-keyword">const</span> [state, setState] = useState(
      () =&gt; JSON.parse(localStorage.getItem(key)) || defaultValue
    );
    useEffect(() =&gt; {
      localStorage.setItem(key, JSON.stringify(state));
    }, [key, state]);
    <span class="hljs-keyword">return</span> [state, setState];
}
</code></pre>
<p>provides persistent storage and external state management support. Considering that we will use Go as the front end: </p>
<ol>
<li>use Hooks and sqlite3 to store locally </li>
<li>use Hooks to communicate with Go </li>
</ol>
<p><a></a></p>
<h3 id="heading-connector">Connector</h3>
<p>to implement global status notifications using Hooks. 
First understand useState() to access to setState() will trigger the current component rendering: https://zh-hans.reactjs.org/docs/hooks-state.html 
Connector let using global state components subscription to connect on the global status updates, will own setState()Pass in the update queue when any of the components use dispatch() 
﻿
import { useEffect } from "react"</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>

<span class="hljs-keyword">const</span> Connector = {}

<span class="hljs-keyword">const</span> Broadcast = <span class="hljs-function">(<span class="hljs-params">name, state</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (!Connector[name]) <span class="hljs-keyword">return</span>;
    Connector[name].forEach(<span class="hljs-function"><span class="hljs-params">setter</span> =&gt;</span> setter(state))
}

<span class="hljs-keyword">const</span> Subscribe = <span class="hljs-function">(<span class="hljs-params">name, setter</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (!Connector[name]) Connector[name] =[];
    Connector[name].push(setter)
}

<span class="hljs-keyword">const</span> UnSubscribe = <span class="hljs-function">(<span class="hljs-params">name, setter</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (!Connector[name]) <span class="hljs-keyword">return</span>
    <span class="hljs-keyword">const</span> index = Connector[name].indexOf(setter)
    <span class="hljs-keyword">if</span> (index !== <span class="hljs-number">-1</span>) Connector[name].splice(index, <span class="hljs-number">1</span>)
}

<span class="hljs-keyword">const</span> connect = <span class="hljs-function">(<span class="hljs-params">name,setState</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'connect'</span>)
    useEffect(<span class="hljs-function">() =&gt;</span>{
        Subscribe(name, setState)
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'subscirbe'</span>,name)
        <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
            UnSubscribe(name,setState)
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'unsubscribe'</span>,name)
        }
    },[])
}
</code></pre>
<p><a></a></p>
<h3 id="heading-usestore">useStore</h3>
<p>user usage useStore() to obtain the global status and dispatch() function. The internal implementation is to State Hook and get setState() register to the subscription list.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> {Broadcast,connect} <span class="hljs-keyword">from</span> <span class="hljs-string">'./Connector'</span>
<span class="hljs-keyword">import</span> {useState} <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useStore</span>(<span class="hljs-params">key,value</span>) </span>{
    <span class="hljs-keyword">const</span> [state,setState] = useState(value)
    connect(key,setState)

    <span class="hljs-keyword">return</span> [state, <span class="hljs-function">(<span class="hljs-params">key,value</span>) =&gt;</span> {
        Broadcast(key,value)
    }]
}
</code></pre>
<p><a></a></p>
<h3 id="heading-current-status">Current status</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657440769721/4fTwvVDYB.png" alt="image.png" /></p>
<p><a></a></p>
<h2 id="heading-use">Use</h2>
<p>Use useStore(key, value) OK.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> {useStore} <span class="hljs-keyword">from</span> <span class="hljs-string">'./useStore'</span>

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Counter</span>(<span class="hljs-params">{key,initialCount}</span>) </span>{
    <span class="hljs-comment">// const [count, setCount] = useLocalJSONStore(keyname, initialCount);</span>
    <span class="hljs-keyword">const</span> [state, dispatch] = useStore(key,initialCount)
    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
        Count: {state}
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> dispatch(keyname,initialCount)}&gt;Reset<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> dispatch(keyname,state-1)}&gt;-<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> dispatch(keyname,state+1)}&gt;+<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/&gt;</span></span>
    );
  }
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657440784966/shVVNrBRj.png" alt="image.png" /></p>
<p><a></a></p>
<h2 id="heading-advanced">Advanced</h2>
<ul>
<li>[ ] asynchronous status</li>
<li>[ ] Decorator</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Technician and experiencer]]></title><description><![CDATA[We believe that the experience of the experience is linked to the actual things and actual behaviors, while the technology of the technician symbolizes more general knowledge. 
First of all, in practical operation, it can be seen that skilled people ...]]></description><link>https://hashnode.abser.top/technician-and-experiencer</link><guid isPermaLink="true">https://hashnode.abser.top/technician-and-experiencer</guid><category><![CDATA[Experience ]]></category><category><![CDATA[Miscellaneous]]></category><dc:creator><![CDATA[Abser·Ari]]></dc:creator><pubDate>Sun, 10 Jul 2022 08:07:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1657436141955/-YlCOB-HY.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>We believe that the experience of the experience is linked to the actual things and actual behaviors, while the technology of the technician symbolizes more general knowledge. </p>
<p>First of all, in practical operation, it can be seen that skilled people are inferior to experienced people in all aspects, but they usually do better than inexperienced people. 
By many views gained from the experience of the universal Judgment (Generic), we believe that technology was born. </p>
<p>Generally, we think that people with technology have a deeper understanding of this kind of thing, (in short, smarter) because their behaviors will be guided, and their starting point is reason rather than inertia. We also believe that people with technology master the ability to impart theories, but experienced people cannot teach others. </p>
<p>Do you want to judge whether you are good at a certain technology and a master in this field? </p>
<p>when you think that you can do something if others ask you but you can only tell the specific situation and specific practices, you are not a wise professor. If the universal judgment you say is not considered dialectically by yourself, you are not a Master of this event. </p>
<p>According to this statement, the concept of a Technologist is close to a wise man, and wisdom is also explained as knowledge about the origin and principle of things. Readers can now think about what characteristics people with high IQ have in the concept we are talking about? </p>
<p>from the above ideas, it is not surprising that mathematicians call them philosophers or wise men, because this discipline is based on the basic principles (Root) rather than a series of secondary disciplines. </p>
<p>Therefore, the more common the principle is, the more it is regarded as truth. People who think they have mastered the truth tend to be frustrated in the field of new knowledge. </p>
<p>Since the opinions that can be collected correspond to the infinite things, in reality, I am inconvenient to think that the universal principle of a kind of things also lacks the existence of truth because there are infinite kinds. </p>
<p>So when experts claim to be masters in other fields, I don't fear to think that they are not very good in this field.</p>
<p>The above metaphysical discussion is not to explore whether the truth exists in a pessimistic way. Instead, I want to express my praise for practical operation from the perspective of reality and the method of getting the so-called twice the result with half the effort by deeply learning the principles of things. </p>
<p>On the other hand, as programmers, top programmers, and technicians' technologies, they can explain the measurement of the difference in value they create. </p>
<p>It is not difficult to become an expert in a certain field through practice but based on the viewpoint of experience summary, it will be our goal to put forward universal fragments (.e. creation, design, and the invention of new technologies). </p>
]]></content:encoded></item><item><title><![CDATA[How Cloud Develop Kit from Google designed the docstore interface]]></title><description><![CDATA[Refer

Docstore · Go CDK
urls.go - google/go-cloud - Sourcegraph
driver.go - Go


Design objectives:
through the abstraction layer, we can mask differences, provide services in a standardized way, and configure business applications through descripti...]]></description><link>https://hashnode.abser.top/how-cloud-develop-kit-from-google-designed-the-docstore-interface</link><guid isPermaLink="true">https://hashnode.abser.top/how-cloud-develop-kit-from-google-designed-the-docstore-interface</guid><category><![CDATA[Cloud]]></category><category><![CDATA[Go Language]]></category><category><![CDATA[Google]]></category><category><![CDATA[mongo]]></category><category><![CDATA[Docstore]]></category><dc:creator><![CDATA[Abser·Ari]]></dc:creator><pubDate>Sat, 09 Jul 2022 04:35:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1657340675337/M4PoWhIbO.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a></a></p>
<h2 id="heading-refer">Refer</h2>
<ul>
<li><a target="_blank" href="https://gocloud.dev/howto/docstore/">Docstore · Go CDK</a></li>
<li><a target="_blank" href="https://sourcegraph.com/github.com/google/go-cloud@master/-/blob/docstore/mongodocstore/urls.go">urls.go - google/go-cloud - Sourcegraph</a></li>
<li><a target="_blank" href="https://cs.opensource.google/go/go/+/refs/tags/go1.18.3:src/database/sql/driver/driver.go">driver.go - Go</a>
<a></a></li>
</ul>
<h2 id="heading-design-objectives">Design objectives:</h2>
<p><strong>through the abstraction layer, we can mask differences, provide services in a standardized way, and configure business applications through description files. </strong></p>
<p><strong>Provides design ideas and guidelines for applications that use document storage. </strong>
<a></a></p>
<h2 id="heading-intro">Intro</h2>
<p>common in MongoDB <a target="_blank" href="https://en.wikipedia.org/wiki/Document-oriented_database">document Storage</a> provides an abstraction layer. </p>
<p>Document Storage is a service that stores data in semi-structured JSON-like documents. These documents are grouped into collections. Like other NoSQL databases, document storage is modeless. </p>
<p>The design needs to support adding, retrieving, modifying, and deleting documents. 
docstore Driver implementation of various services, including cloud and local solutions. You can develop applications locally and then reconfigure them to multiple cloud providers with minimal initialization. 
<a></a></p>
<h2 id="heading-6k66k6h">设计</h2>
<p><a></a></p>
<h3 id="heading-structuring-portable-code">Structuring Portable Code</h3>
<p>Structuring Portable Code the non-interface design imitates the database/SQL package of golang and wraps the existing common logic into the structure. The internal fields of the structure are driver interfaces. The method provided externally is the method corresponding to the structure rather than the implementation of the direction provided driver.</p>
<blockquote>
<p>The advantage of this design is that there is no need to implement general logic processing for each interface, and the code can be transplanted. In some cases, you only need to add and modify methods on the structure and do not need to destroy the method design in the interface. You can also mask some assertion logic. When switching different drivers, users do not need to determine the implementation of some optional interfaces.</p>
</blockquote>
<p><a target="_blank" href="https://gocloud.dev/concepts/structure/">Structuring Portable Code · Go CDK</a>
[sql package - database/sql - Go Packages](https://pkg.go.dev/database/sql#DB
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657339087759/HnpeQujl6.jpg" alt="yuque_diagram.jpg" />
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657339090477/d6gw6aN1x.jpg" alt="yuque_diagram (1).jpg" /></p>
<p><br />Code like below：</p>
<pre><code class="lang-go"><span class="hljs-comment">// Define</span>
<span class="hljs-keyword">type</span> DB <span class="hljs-keyword">interface</span>{
    Exec(sql <span class="hljs-keyword">string</span>)error
}

<span class="hljs-comment">// Realize</span>
<span class="hljs-keyword">type</span> mysql <span class="hljs-keyword">struct</span> {}
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(m *mysql)</span> <span class="hljs-title">Exec</span><span class="hljs-params">(sql <span class="hljs-keyword">string</span>)</span> <span class="hljs-title">error</span></span> {<span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>}

<span class="hljs-comment">// Execute</span>
sql.Database.Exec(<span class="hljs-string">""</span>)
</code></pre>
<pre><code class="lang-go"><span class="hljs-comment">// package and structure</span>
<span class="hljs-keyword">package</span> sql

<span class="hljs-keyword">type</span> DB <span class="hljs-keyword">struct</span> {
    driver driver.DB
}

<span class="hljs-comment">// higher level logic</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(db *DB)</span> <span class="hljs-title">AnySignature</span><span class="hljs-params">(anyParams <span class="hljs-keyword">string</span>)</span> <span class="hljs-params">(anyReturn error)</span></span> {
    <span class="hljs-comment">//... </span>
    db.driver.Exec(<span class="hljs-string">"..."</span>)
    <span class="hljs-comment">//...</span>
    <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
}
<span class="hljs-comment">// Define</span>
<span class="hljs-keyword">package</span> driver 

<span class="hljs-keyword">type</span> DB <span class="hljs-keyword">interface</span>{
    Exec(sql <span class="hljs-keyword">string</span>)error
}

<span class="hljs-comment">// Realize</span>
<span class="hljs-keyword">type</span> mysql <span class="hljs-keyword">struct</span> {}
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(m *mysql)</span> <span class="hljs-title">Exec</span><span class="hljs-params">(sql <span class="hljs-keyword">string</span>)</span> <span class="hljs-title">error</span></span> {<span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>}

<span class="hljs-comment">// Execute</span>
sql.DB.AnySignature(<span class="hljs-string">""</span>)
</code></pre>
<p><a></a></p>
<h3 id="heading-actions-list">Actions List</h3>
<p>For MongoDB, batch processing can be carried out to improve efficiency. As the shielding layer of packaging, we hope to obtain this benefit according to the actual processing of driver. A queue or cache is required to submit a batch operation.</p>
<p><a target="_blank" href="https://docs.mongoing.com/mongodb-crud-operations/bulk-write-operations">Batch write operations-MongoDB-CN-Manual</a></p>
<ul>
<li>[x] I think it is enough to undertake Google Go CDK design </li>
</ul>
<p><a></a></p>
<h3 id="heading-driver-map-andamp-opener">Driver Map &amp; Opener</h3>
<p>Inherited from the Mysql Driver registration method, through the golang standard import_" github.com/xxx/driver" different database drivers can be introduced. The principle is to use a global Map.</p>
<p>Go CDK has upgraded the Opener feature. The original custom URL Parsing method is "mysql", "user:password@/dbname" the features of the new version are blob+file:///dir even + + prefix (e.g. blob+bucket+file:///dir) for Google Cloud SDK, the same URL can provide different functions. However, in our opinion, this function does not have much effect for the time being, so we will block their design. </p>
<p><a></a></p>
<h3 id="heading-dependency-injection-wire">Dependency Injection wire</h3>
<p>Go CDK use the wire project to inject dependencies to automatically switch the structure of different backend providers to the SDK. Different from the way Dapr accesses different services, Dapr uses the yaml description to determine the different plug-ins that are enabled. </p>
<p>For example, you need wire.Build() indicates the new function of the driver to be introduced. </p>
<p>It has little impact on this project and may not be added for the time being. </p>
<p><a></a></p>
<h3 id="heading-uuid-usage">UUID usage</h3>
<p>mongoDB, each entry must have a Key, which can be passed through parameters. </p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Player <span class="hljs-keyword">struct</span> {
    ID   <span class="hljs-keyword">interface</span>{} <span class="hljs-string">`docstore:"_id,omitempty"`</span>
    Name <span class="hljs-keyword">string</span>
}
</code></pre>
<p>The simplest is to indicate the_id field directly in the structure. </p>
<pre><code class="lang-go">docstore.OpenCollection(context.Background(), <span class="hljs-string">"mongo://my-db/my-coll?id_field=name"</span>)
</code></pre>
<p>You can also use the URL Parameter in the high-level abstraction. The following example specifies the_ID as the name field of the above-mentioned high-level abstraction, which is used by the underlying layer <code>mongodocstore.OpenCollection</code> mapping relationship, will automatically generate mongo official driver type <code>primitivie.ObjectID</code></p>
<pre><code class="lang-go">coll, err := mongodocstore.OpenCollection(mcoll, <span class="hljs-string">"id"</span>, <span class="hljs-literal">nil</span>)

<span class="hljs-keyword">type</span> IDer <span class="hljs-keyword">struct</span> {
    ID primitive.ObjectID
}
</code></pre>
<p>you can also use <code>mongodocstore.OpenCollectionWithIDFunc</code> to specify how to generate an ID.</p>
<pre><code class="lang-go">nameFromDocument := <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(doc docstore.Document)</span> <span class="hljs-title">interface</span></span>{} {
    <span class="hljs-keyword">return</span> primitive.NewObjectID()
}
coll, err := mongodocstore.OpenCollectionWithIDFunc(mcoll, nameFromDocument, <span class="hljs-literal">nil</span>)
</code></pre>
<p><a></a></p>
<h2 id="heading-summary">Summary</h2>
<p>We have completed the access design and understanding of Document Store and can perform basic operations on adding, deleting, modifying, and querying docstores. Next, we will build service applications based on this layer of abstraction. </p>
<p>For special functions of different docstores, you can add them to docstore to determine whether they are target-driven and change the method of external exposure.</p>
<p><a></a></p>
<h2 id="heading-function">function</h2>
<p>the following shows the functions of the library. </p>
<p><a></a></p>
<h3 id="heading-connect-mongodb">Connect MongoDB</h3>
<p>The default mongo driver uses MONGO_SERVER_URL link to the server, so you can use code to set it here or directly set it by using environment variables. </p>
<p>the following meaning is from mongodb://localhost:27017 the link on the server is called <code>my-db</code>in the database <code>my-coll</code> document. The unique field name of mongo is <code>name</code>. </p>
<pre><code class="lang-go">os.Setenv(<span class="hljs-string">"MONGO_SERVER_URL"</span>, <span class="hljs-string">"mongodb://localhost:27017"</span>)

coll, err := docstore.OpenCollection(context.Background(), <span class="hljs-string">"mongo://my-db/my-coll?id_field=name"</span>)
<span class="hljs-keyword">defer</span> coll.Close()
</code></pre>
<p><a></a></p>
<h3 id="heading-corresponding-display-structure">Corresponding display structure</h3>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Player <span class="hljs-keyword">struct</span> {
    Name             <span class="hljs-keyword">string</span> <span class="hljs-string">`docstore:"name,omitempty"`</span>
    Score            <span class="hljs-keyword">int</span>
    DocstoreRevision <span class="hljs-keyword">interface</span>{}
}
</code></pre>
<p><a></a></p>
<h3 id="heading-create">Create</h3>
<pre><code class="lang-go">coll.Create(ctx, &amp;Player{Name: <span class="hljs-string">"Pat"</span>, Score: <span class="hljs-number">7</span>});
</code></pre>
<p><a></a></p>
<h3 id="heading-get">Get</h3>
<pre><code class="lang-go">coll.Get(ctx, &amp;Player{Name: <span class="hljs-string">"Pat"</span>});
</code></pre>
<p><a></a></p>
<h3 id="heading-queries">Queries</h3>
<p>you may need to manually create indexes to complete the query function. </p>
<pre><code class="lang-go"><span class="hljs-keyword">import</span> (
    <span class="hljs-string">"context"</span>
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"io"</span>

    <span class="hljs-string">"gocloud.dev/docstore"</span>
)

<span class="hljs-comment">// Ask for all players with scores at least 20.</span>
iter := coll.Query().Where(<span class="hljs-string">"Score"</span>, <span class="hljs-string">"&gt;="</span>, <span class="hljs-number">20</span>).OrderBy(<span class="hljs-string">"Score"</span>, docstore.Descending).Get(ctx)
<span class="hljs-keyword">defer</span> iter.Stop()

<span class="hljs-comment">// Query.Get returns an iterator. Call Next on it until io.EOF.</span>
<span class="hljs-keyword">for</span> {
    <span class="hljs-keyword">var</span> p Player
    err := iter.Next(ctx, &amp;p)
    <span class="hljs-keyword">if</span> err == io.EOF {
        <span class="hljs-keyword">break</span>
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> err
    } <span class="hljs-keyword">else</span> {
        fmt.Printf(<span class="hljs-string">"%s: %d\n"</span>, p.Name, p.Score)
    }
}
</code></pre>
<p><a></a></p>
<h3 id="heading-update-a-single-field-of-an-update-entry">Update a single field of an Update entry</h3>
<pre><code class="lang-go">pat2 := &amp;Player{Name: <span class="hljs-string">"Pat"</span>}
err := coll.Actions().Update(pat, docstore.Mods{<span class="hljs-string">"Score"</span>: <span class="hljs-number">15</span>}).Get(pat2).Do(ctx)
</code></pre>
<p><a></a></p>
<h3 id="heading-replace">Replace</h3>
<p>completely replace the entire entry </p>
<pre><code class="lang-go">coll.Replace(ctx, &amp;Player{Name: <span class="hljs-string">"Pat"</span>, Score: <span class="hljs-number">15</span>})
</code></pre>
<p><a></a></p>
<h3 id="heading-put">Put</h3>
<p>the Put function is equivalent to CreateOrUpdate</p>
<pre><code class="lang-go">coll.Put(ctx, &amp;Player{Name: <span class="hljs-string">"Pat"</span>, Score: <span class="hljs-number">15</span>})
</code></pre>
<p><a></a></p>
<h3 id="heading-delete">Delete</h3>
<pre><code class="lang-go">coll.Delete(ctx, &amp;Player{Name: <span class="hljs-string">"Pat"</span>, Score: <span class="hljs-number">15</span>})
</code></pre>
<p><a></a></p>
<h3 id="heading-more-examples">More examples</h3>
<ul>
<li><a target="_blank" href="https://github.com/google/go-cloud/tree/master/samples/gocdk-docstore">CLI Sample</a></li>
<li><a target="_blank" href="https://gocloud.dev/tutorials/order/">Order Processor sample</a></li>
<li><a target="_blank" href="https://godoc.org/gocloud.dev/docstore#pkg-examples">docstore package examples</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Role of microservice framework]]></title><description><![CDATA[HTTP Channel and GRPC Channel
before we begin, let's explore the differences between HTTP and RPC. The reason why gRPC is discussed here is that no one uses common RPC. 
HTTP is a common communication method used for business coding, and its populari...]]></description><link>https://hashnode.abser.top/role-of-microservice-framework</link><guid isPermaLink="true">https://hashnode.abser.top/role-of-microservice-framework</guid><category><![CDATA[Microservices]]></category><category><![CDATA[framework]]></category><category><![CDATA[Experience ]]></category><category><![CDATA[http]]></category><category><![CDATA[gRPC]]></category><dc:creator><![CDATA[Abser·Ari]]></dc:creator><pubDate>Tue, 05 Jul 2022 03:48:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/4AKThuzuHmQ/upload/v1657003197040/miVRbjc6Z.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-http-channel-and-grpc-channel">HTTP Channel and GRPC Channel</h2>
<p>before we begin, let's explore the differences between HTTP and RPC. The reason why gRPC is discussed here is that no one uses common RPC. </p>
<p>HTTP is a common communication method used for business coding, and its popularity is needless to say. As a Web programmer, HTTP Server programming is its core skill. RPC is also indispensable in microservices. </p>
<p>Can programmers who are familiar with one of the encoding quickly get started with the business coding of another transmission method? </p>
<p>After all, the business logic is consistent, which seems to be only different in network transmission. </p>
<p>Colleagues who have done this know that the differences in business coding are not small. Although the differences are constrained to the transport layer through the abstraction layer during design, there is no framework to block the differences in implementation. Therefore, coding students need to go deep into it and handle it by themselves. </p>
<p>For example, you need to learn more about envoy and proto files, how to encode requests and return values, and how to use specific protobuf to parse message packets in your business. </p>
<p>The differences can be shielded at the abstraction level. We still need to write detailed differences in implementation. These are the operations that some programmers can replace with frameworks. </p>
<h2 id="heading-top-programmers-and-beginners-beginners-and-idiots">Top programmers and beginners, beginners, and idiots</h2>
<p>the role of the framework is to make correct coding behavior without thinking.</p>
<p>There are enough ecological libraries for the current language to help compile various coding types. When lacking, some ecosystems can be transplanted by referring to other languages to reduce the workload. However, not every programmer can do such behavior at any time. </p>
<p>Google is a friend. Business Code they often get into trouble because of something they don't know so that no matter how their skills or intelligence are, they can't solve the problem.</p>
<p>In the business, some coding work will be compared to moving bricks. Programmers are described as manual work to move code from here to there. However, when someone participates in the process, the error probability will also be related to the state of a person.</p>
<p>Through Murphy's law, we can recognize that errors must occur in these processes. How do reduce personal decisions to ensure high quality and high output of assembly line coding manpower?</p>
<p>If you want to treat yourself as an idiot coder and leave the error-prone parts to tools, the framework will generate great benefits. </p>
<blockquote>
<p>Nothing is built on Stone; Everything is built on sand, but we must build sand as stone.
                                -Jorge Louis Borges </p>
</blockquote>
<p>the following are some examples: </p>
<ul>
<li>code review: </li>
</ul>
<p>architects not only need to formulate process standards, but also need to supervise the implementation. Code review is the major part of the workload. However, there are thousands of people, and code writers have their ideas. There may even be a design-based cohesion function, which is scattered at all levels in implementation, and the review process is even more inefficient. </p>
<p>Constraints can be carried out through the framework, which is also the wisdom of software engineering. By increasing restrictions, standards can be formulated to provide efficiency.</p>
<ul>
<li>Best Practices: </li>
</ul>
<p>business code usually uses simple addition, deletion, modification, query data, and target resources. At the same time, there are some common functional requirements, such as JWT. </p>
<p>The framework can shield these differences. For example, JWT only has different types of tokens carried by HTTP, and ORM shields the actual data storage software interfaces in the background for addition, deletion, query, modification, and modification. </p>
<p>This is another wisdom of computer science, solving problems by adding a middle layer. Framework users can switch to different implementations without thinking.</p>
<p>If the best practices provided by the framework cannot meet the requirements, it is time for the document to show its role. Technical personnel-oriented documentation is useful only when problems occur.</p>
<h2 id="heading-the-dilemma-of-microservices-caused-by-abstract-hierarchy-and-abstract-leakage">The dilemma of microservices caused by abstract hierarchy and abstract leakage</h2>
<blockquote>
<p>Google software engineering mentions three key differences between programming and software engineering: <strong>time</strong>, <strong>scope</strong>, and <strong>trade-offs</strong>. </p>
</blockquote>
<p>However, the idea of the framework is beautiful enough, but the realization, in reality, is full of trade-offs and the pursuit of perfection. </p>
<p>Even if the strange requirements of a specific time limit on the business side are excluded. The design cannot be accomplished overnight and a perfect abstract design can be completed.</p>
<p>Abstract leakage refers to the abstraction of implementation details that should be hidden during software development, which inevitably exposes the underlying details and limitations.</p>
<p>Not to mention that a complete system has more than one or two levels. How to make reasonable abstraction and promote it as a standard is a long-term practice and change in many microservice frameworks and coding fields. </p>
<p>Abstraction means unification, while behind the abstraction level, it usually means the actual services with different characteristics. Do you use the union or intersection of these services for abstraction? Whether to consider extended compatibility or functionality.</p>
<blockquote>
<p>For more information, see another article. <a target="_blank" href>Mongo Doc access design</a>, is practical experience. </p>
<p>Also The API of Dapr. Many Interfaces of Golang (IO, SQL, and Net) can see abstract practical practices.</p>
</blockquote>
<p>For example, designers will struggle with whether to provide a certain function to the outside, so they have done a lot of work to provide it. However, in terms of function usage, it may be a pseudo requirement or a simple shielding. However, in actual scenarios, it is necessary to have a lower layer of functions, and the abstraction level is still broken down. </p>
<p>At this point, everyone understands that it falls into specific scenarios and analyzes specific problems. Therefore, a microservice framework that has passed the postgraduate entrance examination for a long time must have solved many problems in the target scenario. </p>
<blockquote>
<p>This reminds me that programmers always pursue new technologies. New microservice frameworks usually have high expectations, hoping that they can completely solve the problems encountered in practice that the old frameworks cannot solve. Finally, expectations often fail. Why can we expect a new untested framework to meet the needs of the technical framework that has been designed and modified many times in practice in specific fields?</p>
</blockquote>
<p>Back to our question at the beginning, is there a framework that unifies the HTTP Channel and gRPC Channel, and only needs to write the handler's internal code without paying attention to other work?</p>
<p> In the modern framework, Dapr did accomplish this. </p>
<p>What about the abstract cost? </p>
<p>The field type in the Protobuf is lost, and it is considered a payload. The handler has different self-processing types, which is consistent with HTTP abstraction. </p>
<p>Is it true that such an abstraction layer has just come up with now? If you have a deeper understanding of computer science, you will find that some past ideas shine brilliantly in new scenarios. </p>
<p>Time is the most significant variable (for example, previous programmers needed to deduct bytes. Now, do you still need to care about insufficient memory for personal PC and cloud coding?). </p>
<h2 id="heading-summary">Summary</h2>
<p>The above describes the problems related to the microservice framework considered in the experience. Just raising questions is a hooligan. My opinions and suggestions are mentioned a lot in the article. </p>
<p>To make a summary, it is: </p>
<p>providing a fool-like automated microservice framework enables programmers to make fewer decisions and make better decisions. </p>
<p>Only by using the time saved to innovate business links and business models, and not being involved in non-creative work such as environment building, can workers feel the value of innovation and self-achievement.</p>
]]></content:encoded></item><item><title><![CDATA[Node Status Manager]]></title><description><![CDATA[ReadLink

pkg/kubelet/nodestatus/setters.go
/pkg /kubelet /kubelet_node_status.go


Directory Layout
pkg/kubelet/nodestatus
 |- setters.go
 |- setters_test.go


Setter
// Setter modifies the node in-place, and returns an error if the modification fai...]]></description><link>https://hashnode.abser.top/node-status-manager</link><guid isPermaLink="true">https://hashnode.abser.top/node-status-manager</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[sourcecode-reading]]></category><category><![CDATA[System Architecture]]></category><dc:creator><![CDATA[Abser·Ari]]></dc:creator><pubDate>Sun, 26 Jun 2022 11:44:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/HFI_UM7RLoU/upload/v1656243395651/MjFEBBjt1.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a></a></p>
<h2 id="heading-readlink">ReadLink</h2>
<ul>
<li><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes/-/blob/pkg/kubelet/nodestatus/setters.go">pkg/kubelet/nodestatus/setters.go</a></li>
<li><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes@d2c5779dadc9ed7a462c36bc280b2f9a200c571e">/</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes@d2c5779dadc9ed7a462c36bc280b2f9a200c571e/-/tree/pkg">pkg /</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes@d2c5779dadc9ed7a462c36bc280b2f9a200c571e/-/tree/pkg/kubelet">kubelet /</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes@d2c5779dadc9ed7a462c36bc280b2f9a200c571e/-/blob/pkg/kubelet/kubelet_node_status.go">kubelet_node_status.go</a></li>
</ul>
<p><a></a></p>
<h2 id="heading-directory-layout">Directory Layout</h2>
<pre><code class="lang-go">pkg/kubelet/nodestatus
 |- setters.<span class="hljs-keyword">go</span>
 |- setters_test.<span class="hljs-keyword">go</span>
</code></pre>
<p><a></a></p>
<h2 id="heading-setter">Setter</h2>
<pre><code class="lang-go"><span class="hljs-comment">// Setter modifies the node in-place, and returns an error if the modification failed.</span>
<span class="hljs-comment">// Setters may partially mutate the node before returning an error.</span>
<span class="hljs-keyword">type</span> Setter <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(node *v1.Node)</span> <span class="hljs-title">error</span></span>
</code></pre>
<p>the Setter function defines a function that performs operations on the v1.Node object. If an error is returned, the Node object may also be changed. 
From the function definition, you can see its usage: use functions to generate different setters for a class of modification of Node objects. In this way, you can modify the state of a Node. 
Use the simplest func GoRuntime() Setter example: </p>
<pre><code class="lang-go"><span class="hljs-comment">// GoRuntime returns a Setter that sets GOOS and GOARCH on the node.</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">GoRuntime</span><span class="hljs-params">()</span> <span class="hljs-title">Setter</span></span> {
    <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(node *v1.Node)</span> <span class="hljs-title">error</span></span> {
        node.Status.NodeInfo.OperatingSystem = goruntime.GOOS
        node.Status.NodeInfo.Architecture = goruntime.GOARCH
        <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
    }
}
</code></pre>
<p>this mode belongs to the middleware operation mode. You can contact middleware for understanding. 
<a></a></p>
<h2 id="heading-setter-list">Setter List</h2>
<p>we learned the setter mode changed by Node status. Currently, the code contains the following 12 setters:</p>
<ul>
<li><strong>NodeAddress </strong>returns a Setter that updates address-related information on the node.：updates address-related fields, such as IP address and hostname (typically the hostname variable in kubelet). </li>
<li><strong>MachineInfo </strong>returns a Setter that updates machine-related information on the node.：updates fields related to host information, such as the maximum number of pods, the number of pods allocated to each core, and the number of resources. </li>
<li><strong>VersionInfo </strong>returns a Setter that updates version-related information on the node.：containerRuntime version, cadvisor version</li>
<li><strong>DaemonEndpoints </strong>returns a Setter that updates the daemon endpoints on the node.</li>
<li><strong>Images </strong>returns a Setter that updates the images on the node.：updates image information. </li>
<li><strong>GoRuntime </strong>returns a Setter that sets GOOS and GOARCH on the node.：GOOS GOARCH information </li>
<li><strong>ReadyCondition</strong> returns a Setter that updates the v1.NodeReady condition on the node.：determines whether the node is in the Ready state from Kubelet fields such as the error return function in the runtimeState. </li>
<li><strong>MemoryPressureCondition </strong>returns a Setter that updates the v1.NodeMemoryPressure condition on the node.</li>
<li><strong>PIDPressureCondition </strong>returns a Setter that updates the v1.NodePIDPressure condition on the node.</li>
<li><strong>DiskPressureCondition </strong>returns a Setter that updates the v1.NodeDiskPressure condition on the node.</li>
<li><strong>VolumesInUse </strong>returns a Setter that updates the volumes in use on the node.</li>
<li><strong>VolumeLimits </strong>returns a Setter that updates the volume limits on the node.</li>
</ul>
<p>Setter 的入参通常是 Kubelet 中的字段，自然使用是通过 Kubelet 去初始化使用。
<a></a></p>
<h2 id="heading-kubelet-node-status">Kubelet Node Status</h2>
<p><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes@d2c5779dadc9ed7a462c36bc280b2f9a200c571e">/</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes@d2c5779dadc9ed7a462c36bc280b2f9a200c571e/-/tree/pkg">pkg /</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes@d2c5779dadc9ed7a462c36bc280b2f9a200c571e/-/tree/pkg/kubelet">kubelet /</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes@d2c5779dadc9ed7a462c36bc280b2f9a200c571e/-/blob/pkg/kubelet/kubelet_node_status.go">kubelet_node_status.go</a>
<a></a></p>
<h3 id="heading-setter">Setter 使用处</h3>
<p>after all setters are initialized in the defaultNodeStatusFuncs function, the function returns a Setter array. </p>
<p><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes@d2c5779dadc9ed7a462c36bc280b2f9a200c571e/-/blob/pkg/kubelet/kubelet_node_status.go?L613">kubelet_node_status.go? L613</a></p>
<pre><code class="lang-go"><span class="hljs-comment">// defaultNodeStatusFuncs is a factory that generates the default set of</span>
<span class="hljs-comment">// setNodeStatus funcs</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(kl *Kubelet)</span> <span class="hljs-title">defaultNodeStatusFuncs</span><span class="hljs-params">()</span> []<span class="hljs-title">func</span><span class="hljs-params">(*v1.Node)</span> <span class="hljs-title">error</span></span> {
    <span class="hljs-comment">// if cloud is not nil, we expect the cloud resource sync manager to exist</span>
    <span class="hljs-keyword">var</span> nodeAddressesFunc <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span> <span class="hljs-params">([]v1.NodeAddress, error)</span></span>
    <span class="hljs-keyword">if</span> kl.cloud != <span class="hljs-literal">nil</span> {
        nodeAddressesFunc = kl.cloudResourceSyncManager.NodeAddresses
    }
    <span class="hljs-keyword">var</span> validateHostFunc <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span> <span class="hljs-title">error</span></span>
    <span class="hljs-keyword">if</span> kl.appArmorValidator != <span class="hljs-literal">nil</span> {
        validateHostFunc = kl.appArmorValidator.ValidateHost
    }
    <span class="hljs-keyword">var</span> setters []<span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(n *v1.Node)</span> <span class="hljs-title">error</span></span>
    setters = <span class="hljs-built_in">append</span>(setters,
        nodestatus.NodeAddress(kl.nodeIPs, kl.nodeIPValidator, kl.hostname, kl.hostnameOverridden, kl.externalCloudProvider, kl.cloud, nodeAddressesFunc),
        nodestatus.MachineInfo(<span class="hljs-keyword">string</span>(kl.nodeName), kl.maxPods, kl.podsPerCore, kl.GetCachedMachineInfo, kl.containerManager.GetCapacity,
            kl.containerManager.GetDevicePluginResourceCapacity, kl.containerManager.GetNodeAllocatableReservation, kl.recordEvent),
        nodestatus.VersionInfo(kl.cadvisor.VersionInfo, kl.containerRuntime.Type, kl.containerRuntime.Version),
        nodestatus.DaemonEndpoints(kl.daemonEndpoints),
        nodestatus.Images(kl.nodeStatusMaxImages, kl.imageManager.GetImageList),
        nodestatus.GoRuntime(),
    )
    <span class="hljs-comment">// Volume limits</span>
    setters = <span class="hljs-built_in">append</span>(setters, nodestatus.VolumeLimits(kl.volumePluginMgr.ListVolumePluginWithLimits))

    setters = <span class="hljs-built_in">append</span>(setters,
        nodestatus.MemoryPressureCondition(kl.clock.Now, kl.evictionManager.IsUnderMemoryPressure, kl.recordNodeStatusEvent),
        nodestatus.DiskPressureCondition(kl.clock.Now, kl.evictionManager.IsUnderDiskPressure, kl.recordNodeStatusEvent),
        nodestatus.PIDPressureCondition(kl.clock.Now, kl.evictionManager.IsUnderPIDPressure, kl.recordNodeStatusEvent),
        nodestatus.ReadyCondition(kl.clock.Now, kl.runtimeState.runtimeErrors, kl.runtimeState.networkErrors, kl.runtimeState.storageErrors, validateHostFunc, kl.containerManager.Status, kl.shutdownManager.ShutdownStatus, kl.recordNodeStatusEvent),
        nodestatus.VolumesInUse(kl.volumeManager.ReconcilerStatesHasBeenSynced, kl.volumeManager.GetVolumesInUse),
        <span class="hljs-comment">// TODO(mtaufen): I decided not to move this setter for now, since all it does is send an event</span>
        <span class="hljs-comment">// and record state back to the Kubelet runtime object. In the future, I'd like to isolate</span>
        <span class="hljs-comment">// these side-effects by decoupling the decisions to send events and partial status recording</span>
        <span class="hljs-comment">// from the Node setters.</span>
        kl.recordNodeSchedulableEvent,
    )
    <span class="hljs-keyword">return</span> setters
}
</code></pre>
<p>The array is assigned to the setNodeStatusFuncs of kubelet.</p>
<pre><code class="lang-go">    <span class="hljs-comment">// Generating the status funcs should be the last thing we do,</span>
    <span class="hljs-comment">// since this relies on the rest of the Kubelet having been constructed.</span>
    klet.setNodeStatusFuncs = klet.defaultNodeStatusFuncs()
</code></pre>
<p><a></a></p>
<h2 id="heading-syncnodestatus-procedure">SyncNodeStatus Procedure</h2>
<p>how do Kubelet use these Kubelet? The core is syncNodeStatus functions.</p>
<p><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes@d2c5779dadc9ed7a462c36bc280b2f9a200c571e/-/blob/pkg/kubelet/kubelet_node_status.go?L435">kubelet_node_status</a></p>
<pre><code class="lang-go"><span class="hljs-comment">// syncNodeStatus should be called periodically from a goroutine.</span>
<span class="hljs-comment">// It synchronizes node status to master if there is any change or enough time</span>
<span class="hljs-comment">// passed from the last sync, registering the kubelet first if necessary.</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(kl *Kubelet)</span> <span class="hljs-title">syncNodeStatus</span><span class="hljs-params">()</span></span> {
    kl.syncNodeStatusMux.Lock()
    <span class="hljs-keyword">defer</span> kl.syncNodeStatusMux.Unlock()

    <span class="hljs-keyword">if</span> kl.kubeClient == <span class="hljs-literal">nil</span> || kl.heartbeatClient == <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span>
    }
    <span class="hljs-keyword">if</span> kl.registerNode {
        <span class="hljs-comment">// This will exit immediately if it doesn't need to do anything.</span>
        kl.registerWithAPIServer()
    }
    <span class="hljs-keyword">if</span> err := kl.updateNodeStatus(); err != <span class="hljs-literal">nil</span> {
        klog.ErrorS(err, <span class="hljs-string">"Unable to update node status"</span>)
    }
}
</code></pre>
<p>syncNodeStatus the function is called periodically in goroutine to synchronize the node status to the master.
<a></a></p>
<h3 id="heading-entry">入口 Entry</h3>
<p>currently, it is called in three places: </p>
<ol>
<li><p><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes@d2c5779dadc9ed7a462c36bc280b2f9a200c571e/-/blob/pkg/kubelet/kubelet.go?L1428:26">kubelet.go? L1428:26</a>
in the Run function of the Kubelet, start goroutine for periodic synchronization. </p>
<pre><code class="lang-go"><span class="hljs-keyword">go</span> wait.JitterUntil(kl.syncNodeStatus, kl.nodeStatusUpdateFrequency, <span class="hljs-number">0.04</span>, <span class="hljs-literal">true</span>, wait.NeverStop)
</code></pre>
</li>
<li><p><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes@d2c5779dadc9ed7a462c36bc280b2f9a200c571e/-/blob/pkg/kubelet/kubelet.go?L2433:7">kubelet.go? L2433:7</a>
: performs one-time synchronization in the fastStatusUpdateOnce function.</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(kl *Kubelet)</span> <span class="hljs-title">fastStatusUpdateOnce</span><span class="hljs-params">()</span></span> {
 <span class="hljs-keyword">for</span> {
     ...
     kl.syncNodeStatus()
     <span class="hljs-keyword">return</span>
 }
}
</code></pre>
</li>
<li><p><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes@d2c5779dadc9ed7a462c36bc280b2f9a200c571e/-/blob/pkg/kubelet/nodeshutdown/nodeshutdown_manager_linux.go?L283:11">nodeshutdown_manager_linux.go? L283:11</a>
: it is called in the start() function of nodeshutdownmanager, which is actually a goroutine and is triggered only after the shutdown event is received from the channel.</p>
<pre><code class="lang-go"><span class="hljs-keyword">if</span> isShuttingDown {
 <span class="hljs-comment">// Update node status and ready condition</span>
 <span class="hljs-keyword">go</span> m.syncNodeStatus()

 m.processShutdownEvent()
}
</code></pre>
</li>
</ol>
<p><a></a></p>
<h3 id="heading-registerwithapiserver">注册 RegisterWithAPIserver</h3>
<p>if kubelet needs to be registered, a for loop is executed to wait for registration to the APIServer.</p>
<pre><code class="lang-go"><span class="hljs-keyword">for</span> {
    time.Sleep(step)
    step = step * <span class="hljs-number">2</span>
    <span class="hljs-keyword">if</span> step &gt;= <span class="hljs-number">7</span>*time.Second {
        step = <span class="hljs-number">7</span> * time.Second
    }

    <span class="hljs-comment">// 1. 获取 node 对象及其信息</span>
    node, err := kl.initialNode(context.TODO())
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        klog.ErrorS(err, <span class="hljs-string">"Unable to construct v1.Node object for kubelet"</span>)
        <span class="hljs-keyword">continue</span>
    }

    klog.InfoS(<span class="hljs-string">"Attempting to register node"</span>, <span class="hljs-string">"node"</span>, klog.KObj(node))
    <span class="hljs-comment">// 2. 注册到 APIServer 中去</span>
    registered := kl.tryRegisterWithAPIServer(node)
    <span class="hljs-keyword">if</span> registered {
        klog.InfoS(<span class="hljs-string">"Successfully registered node"</span>, <span class="hljs-string">"node"</span>, klog.KObj(node))
        kl.registrationCompleted = <span class="hljs-literal">true</span>
        <span class="hljs-keyword">return</span>
    }
}
</code></pre>
<ol>
<li>node, err := kl.initialNode(context.TODO()) : obtains the node object and its information. </li>
<li>registered := kl.tryRegisterWithAPIServer(node) : Register to APIServer </li>
</ol>
<p><a></a></p>
<h3 id="heading-use-setter">Use Setter</h3>
<p><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes@d2c5779dadc9ed7a462c36bc280b2f9a200c571e/-/blob/pkg/kubelet/kubelet_node_status.go?L470:20">Function tryUpdateNodeStatus (kubelet_node_status.go? L470:20)</a>
: the processing part of the volumeManager is omitted.</p>
<pre><code class="lang-go"><span class="hljs-comment">// tryUpdateNodeStatus tries to update node status to master if there is any</span>
<span class="hljs-comment">// change or enough time passed from the last sync.</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(kl *Kubelet)</span> <span class="hljs-title">tryUpdateNodeStatus</span><span class="hljs-params">(tryNumber <span class="hljs-keyword">int</span>)</span> <span class="hljs-title">error</span></span> {
    originalNode := node.DeepCopy()
    ...
    kl.setNodeStatus(node)
    ...
    <span class="hljs-comment">// Patch the current status on the API server</span>
    updatedNode, _, err := nodeutil.PatchNodeStatus(kl.heartbeatClient.CoreV1(), types.NodeName(kl.nodeName), originalNode, node)
    ...
    <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
}
</code></pre>
<p>kl.setNodeStatus just traverses all the Setter functions we mentioned just now.</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(kl *Kubelet)</span> <span class="hljs-title">setNodeStatus</span><span class="hljs-params">(node *v1.Node)</span></span> {
    <span class="hljs-keyword">for</span> i, f := <span class="hljs-keyword">range</span> kl.setNodeStatusFuncs {
        klog.V(<span class="hljs-number">5</span>).InfoS(<span class="hljs-string">"Setting node status condition code"</span>, <span class="hljs-string">"position"</span>, i, <span class="hljs-string">"node"</span>, klog.KObj(node))
        <span class="hljs-keyword">if</span> err := f(node); err != <span class="hljs-literal">nil</span> {
            klog.ErrorS(err, <span class="hljs-string">"Failed to set some node status fields"</span>, <span class="hljs-string">"node"</span>, klog.KObj(node))
        }
    }
}
</code></pre>
<p><a></a></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>we have learned: </p>
<ol>
<li>what are the change functions of the Node Status and what rules are followed to sign the function.</li>
<li>how to register a Setter function to a Kubelet. </li>
<li>Kubelet when these setters are called to change the status of a Node. </li>
</ol>
<p>Next: </p>
<ol>
<li>you can try to add a custom setter function. </li>
<li>Kubernetes code is not as neat as the design. Some todo can be changed after reading this article and code. Try to decouple the code. (You can also find it by searching todo in the code.)</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Configmap/Secret Manager]]></title><description><![CDATA[ReadLink

configmap manager
pkg/kubelet/secret/secret_manager.go


Configmap Manager
// Manager interface provides methods for Kubelet to manage ConfigMap.
type Manager interface {
    // Get configmap by configmap namespace and name.
    GetConfigMa...]]></description><link>https://hashnode.abser.top/configmapsecret-manager</link><guid isPermaLink="true">https://hashnode.abser.top/configmapsecret-manager</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[Open Source]]></category><category><![CDATA[controller]]></category><category><![CDATA[sourcecode-reading]]></category><dc:creator><![CDATA[Abser·Ari]]></dc:creator><pubDate>Sat, 25 Jun 2022 15:40:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/ieic5Tq8YMk/upload/v1656171553995/5Z_nkpe9t.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a></a></p>
<h2 id="heading-readlink">ReadLink</h2>
<ul>
<li><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes/-/blob/pkg/kubelet/configmap/configmap_manager.go">configmap manager</a></li>
<li><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes/-/blob/pkg/kubelet/secret/secret_manager.go">pkg/kubelet/secret/secret_manager.go</a>
<a></a></li>
</ul>
<h2 id="heading-configmap-manager">Configmap Manager</h2>
<pre><code class="lang-go"><span class="hljs-comment">// Manager interface provides methods for Kubelet to manage ConfigMap.</span>
<span class="hljs-keyword">type</span> Manager <span class="hljs-keyword">interface</span> {
    <span class="hljs-comment">// Get configmap by configmap namespace and name.</span>
    GetConfigMap(namespace, name <span class="hljs-keyword">string</span>) (*v1.ConfigMap, error)

    <span class="hljs-comment">// WARNING: Register/UnregisterPod functions should be efficient,</span>
    <span class="hljs-comment">// i.e. should not block on network operations.</span>

    <span class="hljs-comment">// RegisterPod registers all configmaps from a given pod.</span>
    RegisterPod(pod *v1.Pod)

    <span class="hljs-comment">// UnregisterPod unregisters configmaps from a given pod that are not</span>
    <span class="hljs-comment">// used by any other registered pod.</span>
    UnregisterPod(pod *v1.Pod)
}
</code></pre>
<p>接口非常简单。</p>
<ol>
<li>GetConfigMap ： 通过 namespace 和 name 获取对应 ConfigMap 对象。</li>
<li>RegisterPod(pod *v1.Pod)：把指定 Pod 对象 yaml 指定的 configmap 注册到 Controller 中管理</li>
<li>UnregisterPod(pod *v1.Pod)：把指定 Pod 对象 yaml 指定的 configmap 从 Controller 中注册管理中删除，注意 ConfigMap 需要没有任何其他已注册的 Pod 引用（即无被依赖项）才可以删除</li>
</ol>
<p>当前代码中有两种 manager 的实现</p>
<p>-<code>NewCachingConfigMapManager(kubeClient clientset.Interface, getTTL manager.GetObjectTTLFunc) Manager</code>：该实现有两点逻辑</p>
<ul>
<li>当一个 Pod 创建或者更新时，所有的 configmap 缓存都失效。</li>
<li>GetObject() 调用首先从本地缓存获取，失败则访问 APISever 并刷新 configmap 的缓存。</li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// NewCachingConfigMapManager creates a manager that keeps a cache of all configmaps</span>
<span class="hljs-comment">// necessary for registered pods.</span>
<span class="hljs-comment">// It implement the following logic:</span>
<span class="hljs-comment">// - whenever a pod is create or updated, the cached versions of all configmaps</span>
<span class="hljs-comment">//   are invalidated</span>
<span class="hljs-comment">// - every GetObject() call tries to fetch the value from local cache; if it is</span>
<span class="hljs-comment">//   not there, invalidated or too old, we fetch it from apiserver and refresh the</span>
<span class="hljs-comment">//   value in cache; otherwise it is just fetched from cache</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">NewCachingConfigMapManager</span><span class="hljs-params">(kubeClient clientset.Interface, getTTL manager.GetObjectTTLFunc)</span> <span class="hljs-title">Manager</span></span> {
    getConfigMap := <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(namespace, name <span class="hljs-keyword">string</span>, opts metav1.GetOptions)</span> <span class="hljs-params">(runtime.Object, error)</span></span> {
        <span class="hljs-keyword">return</span> kubeClient.CoreV1().ConfigMaps(namespace).Get(context.TODO(), name, opts)
    }
    configMapStore := manager.NewObjectStore(getConfigMap, clock.RealClock{}, getTTL, defaultTTL)
    <span class="hljs-keyword">return</span> &amp;configMapManager{
        manager: manager.NewCacheBasedManager(configMapStore, getConfigMapNames),
    }
}
</code></pre>
<ul>
<li><code>NewWatchingConfigMapManager(kubeClient clientset.Interface, resyncInterval time.Duration) Manager</code>：<ul>
<li>当一个 Pod 创建或者更新时，会对指定该 Pod 引用的资源，并且该资源未被其他 Pod 引用进行独立的 watch。</li>
<li>GetObject() 调用首先从本地缓存获取</li>
</ul>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// NewWatchingConfigMapManager creates a manager that keeps a cache of all configmaps</span>
<span class="hljs-comment">// necessary for registered pods.</span>
<span class="hljs-comment">// It implements the following logic:</span>
<span class="hljs-comment">// - whenever a pod is created or updated, we start individual watches for all</span>
<span class="hljs-comment">//   referenced objects that aren't referenced from other registered pods</span>
<span class="hljs-comment">// - every GetObject() returns a value from local cache propagated via watches</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">NewWatchingConfigMapManager</span><span class="hljs-params">(kubeClient clientset.Interface, resyncInterval time.Duration)</span> <span class="hljs-title">Manager</span></span> {
    listConfigMap := <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(namespace <span class="hljs-keyword">string</span>, opts metav1.ListOptions)</span> <span class="hljs-params">(runtime.Object, error)</span></span> {
        <span class="hljs-keyword">return</span> kubeClient.CoreV1().ConfigMaps(namespace).List(context.TODO(), opts)
    }
    watchConfigMap := <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(namespace <span class="hljs-keyword">string</span>, opts metav1.ListOptions)</span> <span class="hljs-params">(watch.Interface, error)</span></span> {
        <span class="hljs-keyword">return</span> kubeClient.CoreV1().ConfigMaps(namespace).Watch(context.TODO(), opts)
    }
    newConfigMap := <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span> <span class="hljs-title">runtime</span>.<span class="hljs-title">Object</span></span> {
        <span class="hljs-keyword">return</span> &amp;v1.ConfigMap{}
    }
    isImmutable := <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(object runtime.Object)</span> <span class="hljs-title">bool</span></span> {
        <span class="hljs-keyword">if</span> configMap, ok := object.(*v1.ConfigMap); ok {
            <span class="hljs-keyword">return</span> configMap.Immutable != <span class="hljs-literal">nil</span> &amp;&amp; *configMap.Immutable
        }
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
    }
    gr := corev1.Resource(<span class="hljs-string">"configmap"</span>)
    <span class="hljs-keyword">return</span> &amp;configMapManager{
        manager: manager.NewWatchBasedManager(listConfigMap, watchConfigMap, newConfigMap, isImmutable, gr, resyncInterval, getConfigMapNames),
    }
}
</code></pre>
<p><a></a></p>
<h2 id="heading-secret-manager">Secret Manager</h2>
<p>secret manager 除了资源类型和 configmap 不一样，其他逻辑相同，所以仅列出两种 secret manager 的初始化函数。<br /><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes">/</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes/-/tree/pkg">pkg /</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes/-/tree/pkg/kubelet">kubelet /</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes/-/tree/pkg/kubelet/secret">secret /</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes/-/blob/pkg/kubelet/secret/secret_manager.go">secret_manager.go</a></p>
<pre><code class="lang-go"><span class="hljs-comment">// NewCachingSecretManager creates a manager that keeps a cache of all secrets</span>
<span class="hljs-comment">// necessary for registered pods.</span>
<span class="hljs-comment">// It implements the following logic:</span>
<span class="hljs-comment">// - whenever a pod is created or updated, the cached versions of all secrets</span>
<span class="hljs-comment">//   are invalidated</span>
<span class="hljs-comment">// - every GetObject() call tries to fetch the value from local cache; if it is</span>
<span class="hljs-comment">//   not there, invalidated or too old, we fetch it from apiserver and refresh the</span>
<span class="hljs-comment">//   value in cache; otherwise it is just fetched from cache</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">NewCachingSecretManager</span><span class="hljs-params">(kubeClient clientset.Interface, getTTL manager.GetObjectTTLFunc)</span> <span class="hljs-title">Manager</span></span> {
    getSecret := <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(namespace, name <span class="hljs-keyword">string</span>, opts metav1.GetOptions)</span> <span class="hljs-params">(runtime.Object, error)</span></span> {
        <span class="hljs-keyword">return</span> kubeClient.CoreV1().Secrets(namespace).Get(context.TODO(), name, opts)
    }
    secretStore := manager.NewObjectStore(getSecret, clock.RealClock{}, getTTL, defaultTTL)
    <span class="hljs-keyword">return</span> &amp;secretManager{
        manager: manager.NewCacheBasedManager(secretStore, getSecretNames),
    }
}

<span class="hljs-comment">// NewWatchingSecretManager creates a manager that keeps a cache of all secrets</span>
<span class="hljs-comment">// necessary for registered pods.</span>
<span class="hljs-comment">// It implements the following logic:</span>
<span class="hljs-comment">// - whenever a pod is created or updated, we start individual watches for all</span>
<span class="hljs-comment">//   referenced objects that aren't referenced from other registered pods</span>
<span class="hljs-comment">// - every GetObject() returns a value from local cache propagated via watches</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">NewWatchingSecretManager</span><span class="hljs-params">(kubeClient clientset.Interface, resyncInterval time.Duration)</span> <span class="hljs-title">Manager</span></span> {
    listSecret := <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(namespace <span class="hljs-keyword">string</span>, opts metav1.ListOptions)</span> <span class="hljs-params">(runtime.Object, error)</span></span> {
        <span class="hljs-keyword">return</span> kubeClient.CoreV1().Secrets(namespace).List(context.TODO(), opts)
    }
    watchSecret := <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(namespace <span class="hljs-keyword">string</span>, opts metav1.ListOptions)</span> <span class="hljs-params">(watch.Interface, error)</span></span> {
        <span class="hljs-keyword">return</span> kubeClient.CoreV1().Secrets(namespace).Watch(context.TODO(), opts)
    }
    newSecret := <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span> <span class="hljs-title">runtime</span>.<span class="hljs-title">Object</span></span> {
        <span class="hljs-keyword">return</span> &amp;v1.Secret{}
    }
    isImmutable := <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(object runtime.Object)</span> <span class="hljs-title">bool</span></span> {
        <span class="hljs-keyword">if</span> secret, ok := object.(*v1.Secret); ok {
            <span class="hljs-keyword">return</span> secret.Immutable != <span class="hljs-literal">nil</span> &amp;&amp; *secret.Immutable
        }
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
    }
    gr := corev1.Resource(<span class="hljs-string">"secret"</span>)
    <span class="hljs-keyword">return</span> &amp;secretManager{
        manager: manager.NewWatchBasedManager(listSecret, watchSecret, newSecret, isImmutable, gr, resyncInterval, getSecretNames),
    }
}
</code></pre>
<p><a></a></p>
<h2 id="heading-cachebasedmanager">cache_based_manager</h2>
<p><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes">/</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes/-/tree/pkg">pkg /</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes/-/tree/pkg/kubelet">kubelet /</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes/-/tree/pkg/kubelet/util">util /</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes/-/tree/pkg/kubelet/util/manager">manager /</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes/-/blob/pkg/kubelet/util/manager/cache_based_manager.go">cache_based_manager.go</a></p>
<pre><code class="lang-go"><span class="hljs-comment">// cacheBasedManager keeps a store with objects necessary</span>
<span class="hljs-comment">// for registered pods. Different implementations of the store</span>
<span class="hljs-comment">// may result in different semantics for freshness of objects</span>
<span class="hljs-comment">// (e.g. ttl-based implementation vs watch-based implementation).</span>
<span class="hljs-keyword">type</span> cacheBasedManager <span class="hljs-keyword">struct</span> {
    objectStore          Store
    getReferencedObjects <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(*v1.Pod)</span> <span class="hljs-title">sets</span>.<span class="hljs-title">String</span></span>

    lock           sync.Mutex
    registeredPods <span class="hljs-keyword">map</span>[objectKey]*v1.Pod
}
</code></pre>
<p>该 manager 代码位于  <a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes">/</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes/-/tree/pkg">pkg /</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes/-/tree/pkg/kubelet">kubelet /</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes/-/tree/pkg/kubelet/util">util /</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes/-/tree/pkg/kubelet/util/manager">manager /</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes/-/blob/pkg/kubelet/util/manager/cache_based_manager.go">cache_based_manager.go</a>，属于通用的 Manager 结构体工具，用于保留注册的  Pod 所必要引用的 kubernetes 对象（objects）<br />如何做到的呢？<br />通过 getReferencedObjects 字段，一个可以传入的成员函数，自定义实现用于从 v1.Pod 对象中获取到对应对象（或一组对象）的 name。流程如下：</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(c *cacheBasedManager)</span> <span class="hljs-title">RegisterPod</span><span class="hljs-params">(pod *v1.Pod)</span></span> {
    <span class="hljs-comment">// 1. 获取名字</span>
    names := c.getReferencedObjects(pod)
    c.lock.Lock()
    <span class="hljs-keyword">defer</span> c.lock.Unlock()
    <span class="hljs-comment">// 2. 给每一个名字和 pod 的命名空间一起添加到 c.objectStore 中存储</span>
    <span class="hljs-keyword">for</span> name := <span class="hljs-keyword">range</span> names {
        c.objectStore.AddReference(pod.Namespace, name)
    }
    <span class="hljs-comment">// 3. 检查是否之前已经注册了该 Pod</span>
    <span class="hljs-keyword">var</span> prev *v1.Pod
    key := objectKey{namespace: pod.Namespace, name: pod.Name, uid: pod.UID}
    prev = c.registeredPods[key]
    <span class="hljs-comment">// 4. 用新注册的 pod 替换之前存储的注册 Pod 的信息.</span>
    c.registeredPods[key] = pod
    <span class="hljs-comment">// 5. 删除旧 Pod 在 c.objectStore 中的引用信息,这是因为在上面第二步 Add 到 c.objectStore</span>
    <span class="hljs-comment">// 中时,这些资源的引用次数又新增了一次,但实际上只是同一个 Pod 的引用,自然需要删除,当然,也有</span>
    <span class="hljs-comment">// 可能新 Pod 已经不再引用目标资源了, Delete 函数在下面也处理这个情况</span>
    <span class="hljs-keyword">if</span> prev != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">for</span> name := <span class="hljs-keyword">range</span> c.getReferencedObjects(prev) {
            <span class="hljs-comment">// On an update, the .Add() call above will have re-incremented the</span>
            <span class="hljs-comment">// ref count of any existing object, so any objects that are in both</span>
            <span class="hljs-comment">// names and prev need to have their ref counts decremented. Any that</span>
            <span class="hljs-comment">// are only in prev need to be completely removed. This unconditional</span>
            <span class="hljs-comment">// call takes care of both cases.</span>
            c.objectStore.DeleteReference(prev.Namespace, name)
        }
    }
}
</code></pre>
<ol>
<li>获取名字</li>
<li>给每一个名字和 pod 的命名空间一起添加到 c.objectStore 中存储</li>
<li>检查是否之前已经注册了该 Pod</li>
<li>用新注册的 pod 替换之前存储的注册 Pod 的信息.</li>
<li>删除旧 Pod 在 c.objectStore 中的引用信息,这是因为在上面第二步 Add 到 c.objectStore 中时,这些资源的引用次数又新增了一次,但实际上只是同一个 Pod 的引用,自然需要删除,当然,也有可能新 Pod 已经不再引用目标资源了, Delete 函数在下面也处理这个情况</li>
</ol>
<p><a></a></p>
<h3 id="heading-ttl-objectstore">ttl ObjectStore</h3>
<p>cache_based 的 objectStore 通过 ttl 设置缓存有效期。
<a></a></p>
<h2 id="heading-watchbasedmanager">watch_based_manager</h2>
<p><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes">/</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes/-/tree/pkg">pkg /</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes/-/tree/pkg/kubelet">kubelet /</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes/-/tree/pkg/kubelet/util">util /</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes/-/tree/pkg/kubelet/util/manager">manager /</a><a target="_blank" href="https://sourcegraph.com/github.com/kubernetes/kubernetes/-/blob/pkg/kubelet/util/manager/watch_based_manager.go">watch_based_manager.go</a><br />可以看到，watch_based_manager 最后使用了 NewCacheBasedManager ，所以 watch_based_manager  和 cache_based_manager 不同的是 ObjectStore 字段。</p>
<pre><code class="lang-go"><span class="hljs-comment">// NewWatchBasedManager creates a manager that keeps a cache of all objects</span>
<span class="hljs-comment">// necessary for registered pods.</span>
<span class="hljs-comment">// It implements the following logic:</span>
<span class="hljs-comment">// - whenever a pod is created or updated, we start individual watches for all</span>
<span class="hljs-comment">//   referenced objects that aren't referenced from other registered pods</span>
<span class="hljs-comment">// - every GetObject() returns a value from local cache propagated via watches</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">NewWatchBasedManager</span><span class="hljs-params">(
    listObject listObjectFunc,
    watchObject watchObjectFunc,
    newObject newObjectFunc,
    isImmutable isImmutableFunc,
    groupResource schema.GroupResource,
    resyncInterval time.Duration,
    getReferencedObjects <span class="hljs-keyword">func</span>(*v1.Pod)</span> <span class="hljs-title">sets</span>.<span class="hljs-title">String</span>) <span class="hljs-title">Manager</span></span> {

    <span class="hljs-comment">// If a configmap/secret is used as a volume, the volumeManager will visit the objectCacheItem every resyncInterval cycle,</span>
    <span class="hljs-comment">// We just want to stop the objectCacheItem referenced by environment variables,</span>
    <span class="hljs-comment">// So, maxIdleTime is set to an integer multiple of resyncInterval,</span>
    <span class="hljs-comment">// We currently set it to 5 times.</span>
    maxIdleTime := resyncInterval * <span class="hljs-number">5</span>

    <span class="hljs-comment">// TODO propagate stopCh from the higher level.</span>
    objectStore := NewObjectCache(listObject, watchObject, newObject, isImmutable, groupResource, clock.RealClock{}, maxIdleTime, wait.NeverStop)
    <span class="hljs-keyword">return</span> NewCacheBasedManager(objectStore, getReferencedObjects)
}
</code></pre>
<p>watch_based_manager  通过 watch 而不是简单的 ttl 去确认或者刷新缓存。</p>
]]></content:encoded></item></channel></rss>