<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>gRPC – gRPC Blog</title><link>https://grpc.io/blog/</link><description>Recent content in gRPC Blog on gRPC</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><atom:link href="https://grpc.io/blog/index.xml" rel="self" type="application/rss+xml"/><item><title>Blog: gRPConf 2025 Announcement</title><link>https://grpc.io/blog/grpconf-2025-announcement/</link><pubDate>Mon, 30 Jun 2025 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/grpconf-2025-announcement/</guid><description>
&lt;p>Attention gRPC community!&lt;/p>
&lt;p>Mark your calendars for &lt;strong>August 26th, 2025&lt;/strong>, as gRPConf returns to the Google Cloud Campus in Sunnyvale, California. The &lt;a href="https://events.linuxfoundation.org/grpconf/program/schedule" target="_blank" rel="noopener">schedule&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> is now live!&lt;/p>
&lt;p>This is your chance to dive deep into the world of gRPC, connect with fellow developers, and stay ahead of the curve in all things gRPC.&lt;/p>
&lt;h3 id="why-attend">Why Attend?&lt;/h3>
&lt;ul>
&lt;li>Learn: Explore the latest gRPC advancements, best practices, and real-world use cases through a series of informative talks and workshops.&lt;/li>
&lt;li>Connect: Network with a vibrant community of gRPC experts, users, and open-source contributors.&lt;/li>
&lt;li>Share: Discuss your own gRPC experiences, challenges, and successes with peers who share your passion.&lt;/li>
&lt;li>Innovate: Gain inspiration and discover new ways to leverage gRPC in your own projects.&lt;/li>
&lt;/ul>
&lt;p>&lt;a href="https://events.linuxfoundation.org/grpconf/register/" target="_blank" rel="noopener">&lt;strong>Register Now!&lt;/strong>&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/p>
&lt;p>Early bird registration is available until July 30th for $50. Keep an eye on the official gRPC website and social media channels for updates.&lt;/p>
&lt;p>We can&amp;rsquo;t wait to see you at gRPConf 2025!&lt;/p></description></item><item><title>Blog: How robots talk: building distributed robots with gRPC and WebRTC</title><link>https://grpc.io/blog/robotics/</link><pubDate>Wed, 18 Jun 2025 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/robotics/</guid><description>
&lt;p>If you&amp;rsquo;re building any kind of distributed machine, like robots, drones, or IoT devices, two questions come up fast:&lt;/p>
&lt;ul>
&lt;li>How do you send structured commands and data efficiently?&lt;/li>
&lt;li>How do you keep communication resilient when you have an unreliable network?&lt;/li>
&lt;/ul>
&lt;p>In this article, I’ll share the approach we use at &lt;a href="https://www.viam.com/" target="_blank" rel="noopener">Viam&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, an open-source robotics platform that combines gRPC for structured RPCs and WebRTC for peer-to-peer streaming. Even if you&amp;rsquo;re not building robots, the same architectural ideas can help you design more scalable and adaptable systems.&lt;/p>
&lt;h2 id="bridging-the-gap-between-lab-grade-robotics-and-real-world-systems">Bridging the gap between lab-grade robotics and real-world systems&lt;/h2>
&lt;p>&lt;a href="https://en.wikipedia.org/wiki/Robot_Operating_System" target="_blank" rel="noopener">ROS&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> (Robot Operating System) has long been the go-to framework for building and prototyping robotics systems, especially in research and academia. It works well on trusted, local networks because that’s what it was designed for.&lt;/p>
&lt;p>But today&amp;rsquo;s robots don’t stay on tightly-regulated lab benches. They&amp;rsquo;re deployed on factory floors, out at sea, or in remote fields, where network conditions are unpredictable and reliability matters.&lt;/p>
&lt;p>ROS doesn’t handle network communication out of the box. If you need to talk to a robot over the internet, you’re on your own to architect the solution. Modern robotics requires more than local LAN protocols. It needs cloud-ready, peer-to-peer, resilient communication stacks.&lt;/p>
&lt;p>Rather than relying on a distributed messaging stack like MQTT or relaying commands through the cloud, Viam uses gRPC and WebRTC to power &lt;a href="https://docs.viam.com/#platform" target="_blank" rel="noopener">its robotics platform&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. Used together, these protocols offer a modern alternative that complements ROS’s strengths. gRPC provides structured, language-agnostic APIs with fast, efficient Protobuf serialization. And WebRTC adds low-latency, peer-to-peer connections, which is ideal for streaming sensor data or real-time video between machines.&lt;/p>
&lt;p>Some robot builders are also layering gRPC interfaces on top of ROS, blending ROS’s rich ecosystem with the modern transport and scalability of gRPC.&lt;/p>
&lt;h2 id="why-grpc-makes-sense-for-robots">Why gRPC makes sense for robots&lt;/h2>
&lt;p>Modern robots are no longer single-purpose machines in fixed environments. They&amp;rsquo;re mobile, multi-part systems that need to collaborate with sensors, perception services, and control loops, often in real time.&lt;/p>
&lt;p>gRPC supports these needs in several key ways:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Low-latency, real-time control&lt;/strong>: gRPC enables continuous, bidirectional streams, allowing systems to send real-time pose updates to a robotic arm, while simultaneously receiving telemetry, without additional round-trip delays.&lt;/li>
&lt;li>&lt;strong>Cross-platform, multi-language consistency&lt;/strong>: gRPC automatically generates client libraries (stubs) for languages like Python, Go, C++, and others, making it easier to bridge different devices, SDKs, and environments with a consistent interface.&lt;/li>
&lt;li>&lt;strong>Lightweight and efficient serialization&lt;/strong>: gRPC also helps in bandwidth-constrained environments or on embedded devices, enabled by Protobuf’s lightweight binary encoding.&lt;/li>
&lt;li>&lt;strong>Security benefits&lt;/strong>: gRPC is designed with end-to-end encryption (TLS by default) and authentication capabilities baked in, ensuring secure communication between machine parts, whether across local networks or the public internet, without requiring developers to bolt on separate security layers.&lt;/li>
&lt;li>&lt;strong>Service abstraction for machine parts&lt;/strong>: With gRPC and Protobuf, every part of a robot, from motors to cameras to sensors, can be modeled as a standardized, language-agnostic service.
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/blog/robotics/component-protos.png" alt="Every robot part becomes an encapsulated, language-agnostic service" id="component-protos" data-toggle="modal" data-target="#modal-component-protos"/>
&lt;div class="modal" id="modal-component-protos">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/blog/robotics/component-protos.png" alt="Every robot part becomes an encapsulated, language-agnostic service"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/li>
&lt;/ul>
&lt;p>In &lt;a href="https://github.com/viamrobotics/api" target="_blank" rel="noopener">Viam’s public API&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, each robot component is defined as a gRPC service using Protobuf. Components like arms, cameras, and sensors expose typed methods that can be called remotely. Here&amp;rsquo;s an excerpt from the &lt;a href="https://github.com/viamrobotics/api/blob/main/proto/viam/component/arm/v1/arm.proto" target="_blank" rel="noopener">&lt;code>arm.proto&lt;/code>&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> file that defines basic movement and pose retrieval methods for a robotic arm:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-proto" data-lang="proto">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// An ArmService services all arms associated with a robot
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>&lt;span style="color:#069;font-weight:bold">service&lt;/span> ArmService {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#069;font-weight:bold">rpc&lt;/span> MoveToPosition (MoveToPositionRequest) &lt;span style="color:#069;font-weight:bold">returns&lt;/span> (MoveToPositionResponse);&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#069;font-weight:bold">rpc&lt;/span> GetEndPosition (GetEndPositionRequest) &lt;span style="color:#069;font-weight:bold">returns&lt;/span> (GetEndPositionResponse);&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#069;font-weight:bold">rpc&lt;/span> GetJointPositions(GetJointPositionsRequest) &lt;span style="color:#069;font-weight:bold">returns&lt;/span> (GetJointPositionsResponse);&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>}&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>These proto services can then generate &lt;a href="https://docs.viam.com/dev/reference/sdks/" target="_blank" rel="noopener">SDKs&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> to help you work with your machines. This example uses the Python SDK to move an arm. Under the hood, gRPC handles encoding the command into a Protobuf message and sending it over HTTP/2 (or WebRTC, depending on the environment).&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">from&lt;/span> &lt;span style="color:#0cf;font-weight:bold">viam.components.arm&lt;/span> &lt;span style="color:#069;font-weight:bold">import&lt;/span> ArmClient
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>arm &lt;span style="color:#555">=&lt;/span> ArmClient&lt;span style="color:#555">.&lt;/span>from_robot(robot&lt;span style="color:#555">=&lt;/span>robot, name&lt;span style="color:#555">=&lt;/span>&lt;span style="color:#c30">&amp;#34;my-arm&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"># Move the arm to a target 3D position&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>arm&lt;span style="color:#555">.&lt;/span>move_to_position(x&lt;span style="color:#555">=&lt;/span>&lt;span style="color:#f60">0.1&lt;/span>, y&lt;span style="color:#555">=&lt;/span>&lt;span style="color:#f60">0.2&lt;/span>, z&lt;span style="color:#555">=&lt;/span>&lt;span style="color:#f60">0.3&lt;/span>, orientation&lt;span style="color:#555">=&lt;/span>&lt;span style="color:#069;font-weight:bold">None&lt;/span>, world_state&lt;span style="color:#555">=&lt;/span>&lt;span style="color:#069;font-weight:bold">None&lt;/span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="why-webrtc-is-also-part-of-the-picture">Why WebRTC is also part of the picture&lt;/h2>
&lt;p>At first glance, gRPC and WebRTC might seem redundant. Both can stream data and send structured messages. But they solve very different challenges in robotics.&lt;/p>
&lt;p>WebRTC excels at direct, peer-to-peer connections, which is essential when:&lt;/p>
&lt;ul>
&lt;li>Devices are on local networks or constrained by NAT/firewalls&lt;/li>
&lt;li>You want to bypass a central relay or cloud server&lt;/li>
&lt;li>You’re streaming high-bandwidth sensor data (like real-time video or LIDAR) between machines&lt;/li>
&lt;/ul>
&lt;p>Viam uses gRPC for orchestration and WebRTC as the underlying transport, combining them for fast, structured messaging with minimal routing overhead.&lt;/p>
&lt;h2 id="flexible-transport-layers-with-grpc">Flexible transport layers with gRPC&lt;/h2>
&lt;p>While WebRTC enables peer-to-peer communication in distributed machines, gRPC also offers flexibility to swap underlying transport layers.&lt;/p>
&lt;p>Here is &lt;a href="https://github.com/viamrobotics/goutils/tree/main/rpc/examples/echo" target="_blank" rel="noopener">an example gRPC server that runs over WebRTC and other transport protocols&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. Viam also uses Unix domain sockets (UDS) for local messaging between the &lt;code>viam-server&lt;/code> and internal modules, Bluetooth for provisioning machines or proxying network traffic, and serial ports for embedded peripherals.&lt;/p>
&lt;p>Because gRPC defines a consistent interface at the API layer, we can change the transport depending on the environment or device without rewriting client logic, a huge strength when building systems that span cloud, local, and constrained networks.&lt;/p>
&lt;h2 id="a-real-world-example-coordinating-a-claw-game">A real-world example: coordinating a claw game&lt;/h2>
&lt;p>Picture a remote-controlled claw machine, like the ones you&amp;rsquo;d find in an arcade. It has two main components: a camera and a robotic arm. A user interface, such as a &lt;a href="https://docs.viam.com/dev/reference/sdks/#frontend-sdks" target="_blank" rel="noopener">web app&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> or &lt;a href="https://docs.viam.com/dev/reference/sdks/#mobile-sdk" target="_blank" rel="noopener">mobile app&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, sends control commands and receives a live video stream to help guide the claw to its prize.&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/blog/robotics/viam-enclosed-robotic-arm.jpg" alt="Viam enclosed robotic arm as a claw game at a conference" id="viam-enclosed-robotic-arm.jpg" data-toggle="modal" data-target="#modal-viam-enclosed-robotic-arm.jpg"/>
&lt;div class="modal" id="modal-viam-enclosed-robotic-arm.jpg">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/blog/robotics/viam-enclosed-robotic-arm.jpg" alt="Viam enclosed robotic arm as a claw game at a conference"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>Here&amp;rsquo;s how gRPC and WebRTC work together behind the scenes:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Initialization&lt;/strong>: The system establishes control channels using gRPC over HTTP/2. Each component registers its services (e.g. &lt;code>ArmService&lt;/code>, &lt;code>CameraService&lt;/code>).&lt;/li>
&lt;li>&lt;strong>Connection&lt;/strong>: gRPC coordinates the exchange of peer metadata and signaling to set up a WebRTC session between the SDK and machine parts.&lt;/li>
&lt;li>&lt;strong>Real-time operation&lt;/strong>: WebRTC now handles the media and data streams directly between peers. Commands are sent using gRPC method calls, routed over the WebRTC transport. Video and sensor streams flow the other way.&lt;/li>
&lt;/ul>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/blog/robotics/grpc-and-webrtc.png" alt="Viam uses gRPC to initialize connections and WebRTC for peer-to-peer communication in this robot claw game" id="grpc-and-webrtc" data-toggle="modal" data-target="#modal-grpc-and-webrtc"/>
&lt;div class="modal" id="modal-grpc-and-webrtc">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/blog/robotics/grpc-and-webrtc.png" alt="Viam uses gRPC to initialize connections and WebRTC for peer-to-peer communication in this robot claw game"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>This dual-protocol approach allows real-time interaction, smooth streaming, and resilient fallback behavior, even in unpredictable network conditions.&lt;/p>
&lt;h2 id="why-this-pattern-matters-for-the-broader-community">Why this pattern matters for the broader community&lt;/h2>
&lt;p>The combination of gRPC’s structure and WebRTC’s flexibility opens the door to a new class of distributed systems, not just in robotics, but anywhere you need:&lt;/p>
&lt;ul>
&lt;li>Real-time, bi-directional communication between loosely-coupled systems&lt;/li>
&lt;li>Typed, versioned APIs that span languages and devices&lt;/li>
&lt;li>Transport-agnostic flexibility, with the option to go peer-to-peer when needed&lt;/li>
&lt;/ul>
&lt;p>gRPC structures the conversation. WebRTC carries it across the network.&lt;/p>
&lt;h2 id="viam-for-real-time-robot-control">Viam for real-time robot control&lt;/h2>
&lt;p>gRPC has evolved far beyond simple request/response APIs. Across many industries beyond robotics, the way machines communicate is more critical than ever. gRPC and WebRTC aren’t just faster protocols, they’re influential building blocks for the next generation of distributed, resilient, and intelligent machines.&lt;/p>
&lt;p>If you’re building systems that need to talk to each other across devices, environments, and networks, it might be time to explore a more scalable and adaptable communication layer.&lt;/p>
&lt;p>While you could engineer a similar stack on your own, &lt;a href="https://www.viam.com/" target="_blank" rel="noopener">Viam&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> offers these capabilities out of the box. The on-machine functionality is open-source and free to operate, with optional cloud services available on a usage-based model when you scale to fleets.&lt;/p>
&lt;p>&lt;em>Technical review by &lt;a href="https://www.linkedin.com/in/nick-hehr/" target="_blank" rel="noopener">Nick Hehr&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> (Viam)&lt;/em>&lt;/p></description></item><item><title>Blog: gRPC and AI: A Powerful Partnership</title><link>https://grpc.io/blog/grpc-and-ai/</link><pubDate>Tue, 20 May 2025 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/grpc-and-ai/</guid><description>
&lt;p>We recently showcased the exciting potential of Large Language Models (LLMs) to transform gRPC development at gRPConf 2024. If you&amp;rsquo;re curious to see how AI can streamline your gRPC workflows, read on! We would love to emphasize that these capabilities are accessible to you &lt;em>today&lt;/em> using &lt;a href="https://codeassist.google/" target="_blank" rel="noopener">Gemini Code Assist&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;p>In our gRPConf demonstration, we explored how LLMs, particularly Google&amp;rsquo;s Gemini, can streamline your gRPC workflows in three key ways. Now let&amp;rsquo;s see how can you utilize LLM&amp;rsquo;s gRPC knowledge using Gemini Code Assist as an example:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Swagger to Protobuf: Explore Your API as a gRPC Service:&lt;/strong> Curious to see what your existing REST APIs would look like as high-performance gRPC services? Open your OpenAPI YAML file, then write prompts like&lt;/p>
&lt;p>&lt;em>&amp;ldquo;Convert OpenAPI schema to Protobuf&amp;rdquo;&lt;/em>&lt;/p>
&lt;p>to explore the potential of gRPC for your current services, accelerating adoption, and discovering new possibilities for your API architecture.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Protobuf to JUnit Test Cases: Supercharge Your Testing Workflow:&lt;/strong> Want to ensure your gRPC services are robust and reliable? You can use prompts like&lt;/p>
&lt;p>&lt;em>&amp;ldquo;Create JUnit tests for a service implementing PetStoreService in petstore.proto&amp;rdquo;&lt;/em>&lt;/p>
&lt;p>to automatically generate comprehensive JUnit test cases from your Protobuf definitions. Experience how you can quickly create tests in multiple languages (Java, Go, Python, etc.), enabling you to focus on building innovative features with confidence.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Natural Language to Protobuf: Unleash Your Service Ideas:&lt;/strong> Have a vision for a new gRPC service? You can directly describe your service concepts in plain English, using prompts like&lt;/p>
&lt;p>&lt;em>&amp;ldquo;Help me create a pet store gRPC service, and it should list all the pets, create a new pet, and get pet information by ID.&amp;rdquo;&lt;/em>&lt;/p>
&lt;p>to generate Protobuf schemas. Discover how you can quickly prototype new services, foster collaboration between teams, and bring your ideas to life with ease.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>LLMs like Gemini possess a significant understanding of gRPC concepts and code structures, enabling you to leverage them in your development workflow. We&amp;rsquo;re excited to continue exploring the potential of LLMs to further streamline workflows, automate tasks, and empower developers to build and maintain high-quality gRPC services.&lt;/p>
&lt;p>At the same time, feel free to start trying Gemini Code Assist with your own prompts today!&lt;/p>
&lt;p>Catch the &lt;a href="https://www.youtube.com/watch?v=IZsYnCftm7w" target="_blank" rel="noopener">recording of our demo&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> in the below YouTube video to see these prompt-based transformations in action. And don&amp;rsquo;t miss the opportunity to connect with the gRPC community and explore more innovations at the upcoming gRPC Conference on August 26th, Sunnyvale, CA. You can&lt;/p>
&lt;ul>
&lt;li>Sign up for the upcoming gRPC Conference in 2025 at &lt;a href="https://events.linuxfoundation.org/grpconf/" target="_blank" rel="noopener">https://events.linuxfoundation.org/grpconf/&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>Submit a talk proposal before May 28th, 11:59 PM PDT at: &lt;a href="https://events.linuxfoundation.org/grpconf/program/cfp/" target="_blank" rel="noopener">https://events.linuxfoundation.org/grpconf/program/cfp/&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Stay tuned for more exciting advancements in the gRPC and AI space at the upcoming gRPC Conference in 2025!&lt;/p></description></item><item><title>Blog: Highlights in gRPConf 2024:Customer Showcase, Developer Engagement, Birds of Feathers Discussions and more.</title><link>https://grpc.io/blog/grpconf-2024-videos/</link><pubDate>Mon, 25 Nov 2024 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/grpconf-2024-videos/</guid><description>
&lt;p>We loved hosting gRPConf 2024 this summer in Sunnyvale, California. Thank you to
hundreds of developers from Netflix, Apple, Turso, Microsoft, Cisco, Coinbase,
LinkedIn, Datadog, Mercari, Aspect Build, Signeen, Authzed, Reboot.dev,
to name a few, who joined our special event. We were overwhelmed by the
various topics and advanced use cases around the gRPC ecosystem. If you missed
the opportunity to join in person, here are the video recordings that highlight
the presentations during the day:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://youtu.be/HK2mxpBedcg" target="_blank" rel="noopener">[gRPConf 2024 Keynote] Welcome! | Kevin Nilson, Google&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/aTVFx0YaDFo" target="_blank" rel="noopener">[gRPConf 2024 Keynote] State of gRPC | Abhishek Kumar, Google&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/sImWl7JyK_Q" target="_blank" rel="noopener">[gRPConf 2024 Keynote] Overview of gRPC | Ivy Zhuang, Google&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/p80PVtLW8eg" target="_blank" rel="noopener">[gRPConf 2024 Keynote] Industry Trends and gRPC | Muninder Sambi &amp;amp; Anoop Vetteth, Google&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/5dMK5OW6WSw" target="_blank" rel="noopener">Ten Years of gRPC | Jung-Yu (Gina) Yeh &amp;amp; Richard Belleville, Google&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/0g5Ef3mVOKg" target="_blank" rel="noopener">Reducing gRPC Call Volume Through Caching and Batching | Benjamin Fedorka, Netflix&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/7maAI9Z3-II" target="_blank" rel="noopener">Building a New gRPC Library in Swift | George Barnett, Apple&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/8oj1nPt6L0Y" target="_blank" rel="noopener">gRPC Rust | Doug Fawley, Google, and Lucio Franco, Turso&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/9nyUyUD4jwM" target="_blank" rel="noopener">How Low Can You Go? A Dive into gRPC and ttRPC | Archana Choudhary &amp;amp; Sudipta Pandit, Microsoft&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/DrikBWJZ0uA" target="_blank" rel="noopener">Dynamic Policy Enforcement for Privacy Techniques in Microservice Architectures | Rami Haddad, Cisco&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/G6PRjmXuBG8" target="_blank" rel="noopener">Load Balancing in gRPC | Easwar Swaminathan, Google&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/GDJrw36wwWY" target="_blank" rel="noopener">Enhancing gRPC micro-services | Holly Casaletto and Yucong Sun, Coinbase&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/IZsYnCftm7w" target="_blank" rel="noopener">gRPC and AI | Eric Anderson &amp;amp; Yuexin Li, Google&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/LIiprzx6avM" target="_blank" rel="noopener">High Performance Service Meshes with gRPC Proxyless | Jung-Yu (Gina) Yeh &amp;amp; Arvind Bright, Google&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/S6iudSfAEmY" target="_blank" rel="noopener">Managing Protocol Buffers at Scale | Richard Belleville &amp;amp; Terry Wilson, Google&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/SjWa636dpP8" target="_blank" rel="noopener">Rethinking Data Flow in gRPC-Go: | Ricardo Fernández Alvarado &amp;amp; Easwar Swaminathan, Google&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/_GDyu2FOiA0" target="_blank" rel="noopener">Dos and Don’ts: Designing an xDS Backend for the LinkedIn Scale | Paul Chesnais, LinkedIn&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/gc3kNMvgrHQ" target="_blank" rel="noopener">Adapting our xDS control plane for proxyless gRPC | Antoine Tollenaere, Datadog&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/ihzQp3phKCU" target="_blank" rel="noopener">gRPC APIs under One Roof: Mastering gRPC Federation for Efficient BFFs | Shuhei Kitagawa, Mercari&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/m9kCnYgoac8" target="_blank" rel="noopener">A Deep Dive into Advanced TLS | Andrey Ermolov &amp;amp; Gregory Cooke, Google&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/nuG_7HflISU" target="_blank" rel="noopener">Powering Cisco ThousandEyes high-performant data streams w/ gRPC &amp;amp; OpenTelem. | Vitaly Kumov, Cisco&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/p9xzHg0Rk4U" target="_blank" rel="noopener">Building Monorepo gRPC Services with Bazel | Alex Eagle, Aspect Build&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/psYQFbPgIOI" target="_blank" rel="noopener">gRPC Metadata Limits: The Good, the Bad, and the Ugly | Alisha Nanda, Google&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/qFSHoxs8i2Q" target="_blank" rel="noopener">Fortifying gRPC Microservices: Beyond JWT with mTLS and SPIFFE | Mehrdad Afshari, Signeen&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/uQh9ZVGkrak" target="_blank" rel="noopener">gRPC Performance and Testing: a Maintainer Perspective | Ashley Zhang &amp;amp; Adam Heller, Google&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/v_e2ExQwphQ" target="_blank" rel="noopener">Building SpiceDB: a gRPC-first database | Jimmy Zelinskie, authzed&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/zVhvJXdyXLY" target="_blank" rel="noopener">Enabling Distributed Transactions Across Microservices using gRPC | Benjamin Hindman, reboot.dev&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/Rf1V6M6SDr4" target="_blank" rel="noopener">Subsetting in gRPC: How we implemented it at Datadog | Sergey Matyukevich, Datadog&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/grpc-conf-2024-image1.jpg" alt="Conference Gate" id="grpc-conf-2024-image1.jpg" data-toggle="modal" data-target="#modal-grpc-conf-2024-image1.jpg"/>
&lt;div class="modal" id="modal-grpc-conf-2024-image1.jpg">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/grpc-conf-2024-image1.jpg" alt="Conference Gate"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/grpc-conf-2024-image2.jpg" alt="Kevin Opening Keynote" id="grpc-conf-2024-image2.jpg" data-toggle="modal" data-target="#modal-grpc-conf-2024-image2.jpg"/>
&lt;div class="modal" id="modal-grpc-conf-2024-image2.jpg">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/grpc-conf-2024-image2.jpg" alt="Kevin Opening Keynote"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/grpc-conf-2024-image3.jpg" alt="Abhishek Keynote: State of gRPC" id="grpc-conf-2024-image3.jpg" data-toggle="modal" data-target="#modal-grpc-conf-2024-image3.jpg"/>
&lt;div class="modal" id="modal-grpc-conf-2024-image3.jpg">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/grpc-conf-2024-image3.jpg" alt="Abhishek Keynote: State of gRPC"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/grpc-conf-2024-image4.jpg" alt="Ivy Zhuang Keynote Talk: Overview of gRPC" id="grpc-conf-2024-image4.jpg" data-toggle="modal" data-target="#modal-grpc-conf-2024-image4.jpg"/>
&lt;div class="modal" id="modal-grpc-conf-2024-image4.jpg">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/grpc-conf-2024-image4.jpg" alt="Ivy Zhuang Keynote Talk: Overview of gRPC"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/grpc-conf-2024-image5.jpg" alt="gRPConf 2024 Audiences ask questions" id="grpc-conf-2024-image5.jpg" data-toggle="modal" data-target="#modal-grpc-conf-2024-image5.jpg"/>
&lt;div class="modal" id="modal-grpc-conf-2024-image5.jpg">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/grpc-conf-2024-image5.jpg" alt="gRPConf 2024 Audiences ask questions"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/grpc-conf-2024-image6.jpg" alt="gRPConf 2024 Audiences" id="grpc-conf-2024-image6.jpg" data-toggle="modal" data-target="#modal-grpc-conf-2024-image6.jpg"/>
&lt;div class="modal" id="modal-grpc-conf-2024-image6.jpg">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/grpc-conf-2024-image6.jpg" alt="gRPConf 2024 Audiences"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>We received a wealth of feedbacks from everyone throughout the day which has
helped us shape our future roadmap. Stay tuned to gRPC on many platforms for new
releases, announcements and events:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.youtube.com/@grpcio" target="_blank" rel="noopener">gRPC YouTube Channel&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.meetup.com/grpcio/" target="_blank" rel="noopener">gRPC Meetup Group&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://grpc.io" target="_blank" rel="noopener">Website&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://grpc.io/blog/" target="_blank" rel="noopener">Blog&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/grpc" target="_blank" rel="noopener">GitHub&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://groups.google.com/g/grpc-io" target="_blank" rel="noopener">Google Group Forum&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://twitter.com/grpcio" target="_blank" rel="noopener">Twitter&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Blog: Announcing Our New Mailing List grpc-io-announce</title><link>https://grpc.io/blog/grpc-io-announce/</link><pubDate>Wed, 06 Nov 2024 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/grpc-io-announce/</guid><description>
&lt;p>Want to stay ahead of the curve on critical gRPC announcements? We&amp;rsquo;ve got you
covered!&lt;/p>
&lt;p>Introducing &lt;a href="https://groups.google.com/g/grpc-io-announce" target="_blank" rel="noopener">grpc-io-announce&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, a
new mailing list dedicated to delivering essential updates directly to your
inbox. This high-signal channel cuts through the noise and focuses on what
matters most, including:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Security vulnerabilities and reliability issues&lt;/strong>: Be the first to know
about security concerns and get timely updates on fixes and mitigations.&lt;/li>
&lt;li>&lt;strong>Major platform support changes&lt;/strong>: Stay informed about changes in support
for different platforms.&lt;/li>
&lt;li>&lt;strong>Project and governance news&lt;/strong>: Get the latest updates on major project
milestones and governance decisions.&lt;/li>
&lt;/ul>
&lt;p>Note: Release announcements and feature launch announcements will stay in the
existing &lt;a href="https://groups.google.com/g/grpc-io" target="_blank" rel="noopener">grpc-io group&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;p>No more scouring through grpc-io groups or worrying about missing critical
information. Subscribe to &lt;strong>grpc-io-announce&lt;/strong> and get peace of mind knowing
you won&amp;rsquo;t miss critical information.&lt;/p>
&lt;p>&lt;strong>Join the group today: &lt;a href="https://groups.google.com/g/grpc-io-announce" target="_blank" rel="noopener">grpc-io-announce group&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/strong>&lt;/p>
&lt;p>For more information, please see &lt;a href="https://github.com/grpc/proposal/blob/master/P6-grpc-io-announce.md" target="_blank" rel="noopener">P6 grpc-io-announce&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;p>We&amp;rsquo;re committed to keeping you informed and ensuring a smooth gRPC experience.&lt;/p></description></item><item><title>Blog: Configuring proxyless gRPC with Kubernetes Gateway API and OpenTelemetry metrics for Cloud Service Mesh now available in preview</title><link>https://grpc.io/blog/proxyless-grpc/</link><pubDate>Thu, 12 Sep 2024 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/proxyless-grpc/</guid><description>
&lt;p>We are excited to announce that configuring proxyless gRPC with the Kubernetes Gateway API and OpenTelemetry metrics for Cloud Service Mesh are now available as preview features. This integration allows you to leverage the powerful capabilities of the Kubernetes Gateway API to manage traffic to your gRPC services within the Cloud Service Mesh environment, along with the added benefit of gRPC OpenTelemetry metrics for enhanced observability.&lt;/p>
&lt;div class="youtube-video">
&lt;iframe src="https://www.youtube.com/embed/BwFBYLa5mgY" allowfullscreen title="Single Cluster Gateway for Mesh and gRPC Observability in Cloud Service Mesh">&lt;/iframe>
&lt;/div>
&lt;h3 id="whats-new">What&amp;rsquo;s new:&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Kubernetes Gateway API Integration&lt;/strong>: Now you can use the Kubernetes Gateway API to define and manage traffic routing for services running in your Cloud Service Mesh. This provides a more standardized and flexible approach to managing ingress and traffic management within your Kubernetes clusters.&lt;/li>
&lt;li>&lt;strong>gRPC OpenTelemetry Metrics for Cloud Service Mesh&lt;/strong>: Gain deeper insights into your gRPC services with integrated OpenTelemetry metrics, providing valuable observability data for monitoring and troubleshooting.&lt;/li>
&lt;/ul>
&lt;h3 id="benefits">Benefits:&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Simplified traffic management&lt;/strong>: The Kubernetes Gateway API provides a declarative way to manage traffic routing, making it easier to configure and manage ingress for your services.&lt;/li>
&lt;li>&lt;strong>Enhanced observability&lt;/strong>: gRPC OpenTelemetry metrics for Cloud Service Mesh provide valuable insights into the performance and health of your gRPC services, aiding in monitoring and troubleshooting.&lt;/li>
&lt;/ul>
&lt;h3 id="get-started">Get started:&lt;/h3>
&lt;p>To learn more about how to configure Cloud Service Mesh with the Kubernetes Gateway API and try out this new feature, check out our &lt;a href="https://cloud.google.com/service-mesh/docs/gateway/proxyless-grpc-mesh" target="_blank" rel="noopener">documentation and tutorials&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. More information on OpenTelemetry Metrics for Cloud Service Mesh can be found in our &lt;a href="https://cloud.google.com/service-mesh/docs/service-routing/observability-proxyless-grpc" target="_blank" rel="noopener">documentation&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;p>We are eager to hear your feedback on these new features. Please share your thoughts and experiences through our community channels.&lt;/p></description></item><item><title>Blog: gRPConf 2024 Schedule</title><link>https://grpc.io/blog/grpconf-2024-schedule/</link><pubDate>Wed, 03 Jul 2024 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/grpconf-2024-schedule/</guid><description>
&lt;p>Attention gRPC community!&lt;/p>
&lt;p>Mark your calendars for &lt;strong>August 27th, 2024&lt;/strong>, as gRPConf returns to the Google Cloud Campus in Sunnyvale, California. The &lt;a href="https://events.linuxfoundation.org/grpconf/program/schedule" target="_blank" rel="noopener">schedule&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> is now live!&lt;/p>
&lt;p>This is your chance to dive deep into the world of gRPC, connect with fellow developers, and stay ahead of the curve in all things gRPC.&lt;/p>
&lt;h3 id="why-attend">Why Attend?&lt;/h3>
&lt;ul>
&lt;li>Learn: Explore the latest gRPC advancements, best practices, and real-world use cases through a series of informative talks and workshops.&lt;/li>
&lt;li>Connect: Network with a vibrant community of gRPC experts, users, and open-source contributors.&lt;/li>
&lt;li>Share: Discuss your own gRPC experiences, challenges, and successes with peers who share your passion.&lt;/li>
&lt;li>Innovate: Gain inspiration and discover new ways to leverage gRPC in your own projects.&lt;/li>
&lt;/ul>
&lt;p>&lt;a href="https://events.linuxfoundation.org/grpconf/register/" target="_blank" rel="noopener">&lt;strong>Register Now!&lt;/strong>&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/p>
&lt;p>Early bird registration is available until July 30th for $50. Keep an eye on the official gRPC website and social media channels for updates.&lt;/p>
&lt;p>We can&amp;rsquo;t wait to see you at gRPConf 2024!&lt;/p></description></item><item><title>Blog: Celebrate gRPC Day</title><link>https://grpc.io/blog/grpc-day-2023/</link><pubDate>Tue, 12 Mar 2024 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/grpc-day-2023/</guid><description>
&lt;p>The gRPC core engineering team is excited to share a new video playlist that accelerates your getting started with gRPC and helps you better understand recently introduced innovations such as gRPC Microservices Observability in GCP (for the full announcement, see &lt;a href="https://cloud.google.com/blog/products/networking/introducing-grpc-observability-for-microservices" target="_blank" rel="noopener">blog&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> and &lt;a href="https://cloud.google.com/stackdriver/docs/solutions/grpc" target="_blank" rel="noopener">codelab&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;p>The materials are for any audience, including individuals starting their gRPC journey as well as established gRPC coders, and place the core technologies of gRPC at your fingertips.&lt;/p>
&lt;p>The video series includes the following clips:&lt;/p>
&lt;ol>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=inaVnx84E2E&amp;amp;list=PLcTqM9n_dieOaX2BcrP0B1imr6Acyhn-G&amp;amp;index=1&amp;amp;t=37s" target="_blank" rel="noopener">gRPC Day Primer: The State of gRPC | Neil Abogado&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=njC24ts24Pg&amp;amp;list=PLcTqM9n_dieOaX2BcrP0B1imr6Acyhn-G&amp;amp;index=2" target="_blank" rel="noopener">gRPC in 5 minutes | Eric Anderson &amp;amp; Ivy Zhuang&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=cSGBbwvW1y4&amp;amp;list=PLcTqM9n_dieOaX2BcrP0B1imr6Acyhn-G&amp;amp;index=3" target="_blank" rel="noopener">Getting Started with gRPC | Easwar Swaminathan &amp;amp; Arvind Bright&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=S4EW5_PhRQY&amp;amp;list=PLcTqM9n_dieOaX2BcrP0B1imr6Acyhn-G&amp;amp;index=4" target="_blank" rel="noopener">Observability for Microservices with gRPC | Vindhya Ningegowda &amp;amp; Sanjay Pujare&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=WmF0X0frWH0&amp;amp;list=PLcTqM9n_dieOaX2BcrP0B1imr6Acyhn-G&amp;amp;index=5" target="_blank" rel="noopener">Observability Visualization for gRPC Microservices in GCP | Vindhya Ningegowda&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=B8gfu5bs2Pw&amp;amp;list=PLcTqM9n_dieOaX2BcrP0B1imr6Acyhn-G&amp;amp;index=6" target="_blank" rel="noopener">Leveling Up your Service Mesh with gRPC | Ivy Zhuang &amp;amp; Richard Belleville&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=Z3X6kD_1SFo&amp;amp;list=PLcTqM9n_dieOaX2BcrP0B1imr6Acyhn-G&amp;amp;index=7" target="_blank" rel="noopener">Supporting xDS in the gRPC Client Architecture | Mark Roth&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;/ol>
&lt;p>Individuals new to gRPC should start with sessions #1-3, while seasoned gRPC developers can jump into the advanced topics covered by videos #4-7.&lt;/p>
&lt;p>Checkout the YouTube playlist &lt;a href="https://www.youtube.com/playlist?list=PLcTqM9n_dieOaX2BcrP0B1imr6Acyhn-G" target="_blank" rel="noopener">gRPC Day&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> to start watching!&lt;/p></description></item><item><title>Blog: Can gRPC replace REST and WebSockets for Web Application Communication?</title><link>https://grpc.io/blog/postman-grpcweb/</link><pubDate>Mon, 04 Dec 2023 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/postman-grpcweb/</guid><description>
&lt;div class="alert alert-info" role="alert">
Welcome to this guest blog entry from our friends at
&lt;a href="https://www.postman.com/" target="_blank" rel="noopener">Postman&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>!
&lt;/div>
&lt;p>In the rapidly evolving landscape of web development, efficiency and
performance often stand at the forefront of adoption of new technologies.
The work being done with the &lt;a href="https://github.com/grpc/grpc-web" target="_blank" rel="noopener">gRPC-Web&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
library marks a pivotal shift in how developers can utilize the speed and
power of &lt;a href="https://grpc.io/" target="_blank" rel="noopener">gRPC&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> into client-server communication in web
applications by replacing REST and some aspects of WebSockets. Let’s look at a
comparative analysis with traditional RESTful calls and WebSocket connections,
and offer practical code samples with gRPC-Web to draw comparisons in each approach.&lt;/p>
&lt;h2 id="understanding-grpc-web-and-its-place-in-modern-web-development">Understanding gRPC-Web and Its Place in Modern Web Development&lt;/h2>
&lt;p>The genesis of gRPC-Web lies in the quest for more responsive, low-latency web
applications. It extends the capabilities of gRPC – a high-performance,
open-source universal RPC framework – to the browser, enabling direct
communication with gRPC services normally designated to server-to-server
communication. gRPC is structured around a serialization format called &lt;a href="https://protobuf.dev/" target="_blank" rel="noopener">Protocol
Buffers (Protobuf)&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, which facilitates smaller payloads
and well-defined interface descriptions that streamline the development process.&lt;/p>
&lt;p>Before diving into the technicalities, let’s examine the potential shift that
gRPC-Web represents. Unlike the native gRPC protocol, which requires HTTP/2,
gRPC-Web relaxes this requirement, allowing it to support any HTTP/* protocols
available in a browser environment. In a WebSocket scenario, a persistent
connection is maintained for full-duplex communication, but WebSockets can
introduce complexity in managing various connection states. gRPC-Web offers a
compelling alternative with its server streaming capabilities, leading to a
more efficient real-time data flow. At present, gRPC-Web does not support
client-side streaming due to browser constraints.&lt;/p>
&lt;h2 id="the-mechanics-of-grpc-web-how-it-works">The Mechanics of gRPC-Web: How It Works&lt;/h2>
&lt;p>To integrate gRPC-Web into your web application, a specific architecture must be
adopted. At the heart of this architecture lies the &lt;a href="https://www.envoyproxy.io/" target="_blank" rel="noopener">Envoy
proxy&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, which serves as a bridge between the web
application and the gRPC server (this is necessary to allow abstraction of
network protocols). Envoy translates the gRPC-Web calls into gRPC calls,
handling the HTTP/1.1 to HTTP/2 conversion, allowing browsers to enjoy the
benefits of gRPC.&lt;/p>
&lt;p>Let&amp;rsquo;s break down the steps involved in this communication model:&lt;/p>
&lt;ol>
&lt;li>The browser initiates a gRPC-Web client call.&lt;/li>
&lt;li>The Envoy proxy receives the call, which includes the Protobuf-defined
request.&lt;/li>
&lt;li>Envoy then translates this into an HTTP/2 gRPC call and forwards it to the
gRPC server.&lt;/li>
&lt;li>The gRPC server processes the request and returns the response to Envoy.&lt;/li>
&lt;li>Envoy converts the gRPC response back into gRPC-Web format and sends it to
the client.&lt;/li>
&lt;/ol>
&lt;p>Using this proxy system, gRPC-Web facilitates a robust client-server interaction
that is performant, and offers data clarity and precision thanks to the strong
data typing of Protobuf.&lt;/p>
&lt;h2 id="the-theory-of-transitioning-from-rest-to-grpc-web">The Theory of Transitioning from REST to gRPC-Web&lt;/h2>
&lt;p>For developers accustomed to REST, the leap to gRPC-Web may seem challenging.
The transition can be smooth with a proper understanding of the involved
components and a step-by-step approach.&lt;/p>
&lt;p>Consider a typical RESTful fetch call:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>fetch(&lt;span style="color:#c30">&amp;#39;https://api.example.com/data&amp;#39;&lt;/span>, {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> method&lt;span style="color:#555">:&lt;/span> &lt;span style="color:#c30">&amp;#39;GET&amp;#39;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> headers&lt;span style="color:#555">:&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c30">&amp;#39;Accept&amp;#39;&lt;/span>&lt;span style="color:#555">:&lt;/span> &lt;span style="color:#c30">&amp;#39;application/json&amp;#39;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>})
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>.then(response =&amp;gt; response.json())
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>.then(data =&amp;gt; console.log(data))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>.&lt;span style="color:#069;font-weight:bold">catch&lt;/span>(error =&amp;gt; console.error(&lt;span style="color:#c30">&amp;#39;Error:&amp;#39;&lt;/span>, error));
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The above code retrieves JSON data from a RESTful API service. Notice the use of
the fetch API, HTTP method, and content type headers. The response is processed
as a JSON object, and error handling is baked into the promise chain. What is
not indicated in this code is the data validation that is needed to ensure the
data you received in the payload matches an expected schema, and that the data
received in the schema is properly set in the data type you require, and the
user experience of handling erroneous data.&lt;/p>
&lt;p>Let&amp;rsquo;s reimagine this with gRPC-Web:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">const&lt;/span> { ExampleRequest, ExampleResponse } &lt;span style="color:#555">=&lt;/span> require(&lt;span style="color:#c30">&amp;#39;./generated/example_pb.js&amp;#39;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">const&lt;/span> { ExampleServiceClient } &lt;span style="color:#555">=&lt;/span> require(&lt;span style="color:#c30">&amp;#39;./generated/example_grpc_web_pb.js&amp;#39;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">const&lt;/span> client &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> ExampleServiceClient(&lt;span style="color:#c30">&amp;#39;https://api.example.com&amp;#39;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">const&lt;/span> request &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> ExampleRequest();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>client.getExampleData(request, {}, (err, response) =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">if&lt;/span> (err) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> console.error(&lt;span style="color:#c30">&amp;#39;Error:&amp;#39;&lt;/span>, err);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#069;font-weight:bold">else&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> console.log(response.toObject());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>});
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>In this gRPC-Web example, we begin by importing the necessary Protobuf
definitions and client stub. A client instance is created, specifying the
service URL. We construct a request object, and the getExampleData method is
called on the client, passing the request and a callback function for handling
the response or error.&lt;/p>
&lt;p>Notice the stark difference in approach: gRPC-Web calls are strongly-typed, and
serialization/deserialization is handled by the library, not manually by the
developer. This type safety and automation can drastically reduce the potential
for human error and streamline the development process. If you receive an
object, it has already been fully validated.&lt;/p>
&lt;h2 id="advantages-of-grpc-web-over-rest">Advantages of gRPC-Web Over REST&lt;/h2>
&lt;p>While REST has been the cornerstone of web APIs for years, its simplicity can
sometimes be a limitation when it comes to complex web applications. While
gRPC-Web can &lt;a href="https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md#protocol-differences-vs-grpc-over-http2" target="_blank" rel="noopener">work with any HTTP/*
protocols&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
supported in the browser, gRPC-Web leverages many HTTP/2 features, bringing a
host of improvements. Here are some advantages of HTTP/2 and gRPC-Web:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>It works with existing services:&lt;/strong> There’s nothing new to build other than the
Envoy proxy, so implementing gRPC-Web will allow you to access any existing
gRPC service. This can be an advantage for applications, including mobile
apps, utilizing JavaScript libraries.&lt;/li>
&lt;li>&lt;strong>Type Safety:&lt;/strong> With gRPC-Web, both requests and responses are strongly typed
based on the Protobuf definitions. This contract between the client and
server is explicit, reducing the likelihood of miscommunication and bugs.&lt;/li>
&lt;li>&lt;strong>Efficient Serialization:&lt;/strong> Protobuf, the serialization format used by gRPC, is
more efficient than JSON or XML, leading to quicker serialization and
smaller message sizes. This can be particularly beneficial for performance
and can lead to cost savings in terms of bandwidth. HTTP/1.1 allows data to
be sent in text mode or binary mode, but not both. HTTP/2 is binary-only and
encoding/decoding binary into text is less error-prone than
encoding/decoding a binary file into text to send a mixed payload over REST.&lt;/li>
&lt;li>&lt;strong>Clear API Contracts:&lt;/strong> Using Protobuf for service definition creates a clear,
language-agnostic API contract. This can be used to generate client and
server code in multiple languages, providing a seamless experience for
developers.&lt;/li>
&lt;/ul>
&lt;h2 id="setting-up-a-grpc-web-environment">Setting Up a gRPC-Web Environment&lt;/h2>
&lt;p>Getting started with gRPC-Web will require defining services and message
payloads using Protobuf, setting up the gRPC backend service (or &lt;a href="https://blog.postman.com/postman-mocking-magic-for-grpcs/" target="_blank" rel="noopener">a mock server
for the time being&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>),
and configuring an Envoy proxy to translate between gRPC-Web and gRPC.&lt;/p>
&lt;p>First, you define your service in a .proto file:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-proto" data-lang="proto">&lt;span style="display:flex;">&lt;span>syntax &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#c30">&amp;#34;proto3&amp;#34;&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#069;font-weight:bold">package&lt;/span> &lt;span style="color:#0cf;font-weight:bold">example&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#069;font-weight:bold">service&lt;/span> ExampleService {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#069;font-weight:bold">rpc&lt;/span> GetExampleData(ExampleRequest) &lt;span style="color:#069;font-weight:bold">returns&lt;/span> (ExampleResponse);&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>}&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#069;font-weight:bold">message&lt;/span> &lt;span style="color:#0a8;font-weight:bold">ExampleRequest&lt;/span> {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#078;font-weight:bold">string&lt;/span> query &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">1&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>}&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#069;font-weight:bold">message&lt;/span> &lt;span style="color:#0a8;font-weight:bold">ExampleResponse&lt;/span> {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#069;font-weight:bold">repeated&lt;/span> &lt;span style="color:#078;font-weight:bold">string&lt;/span> data &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">1&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>}&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This &lt;code>.proto&lt;/code> file defines a simple service with a single RPC method,
&lt;code>GetExampleData&lt;/code>, along with the request and response message formats. Since the
operation sends a single &lt;code>ExampleRequest&lt;/code> message in the request, and expects to
receive a single &lt;code>ExampleResponse&lt;/code> message in the response, this unary RPC call
mimics a RESTful request.&lt;/p>
&lt;p>Next, generate the client stub code for your service using the protoc
command-line tool with the appropriate gRPC-Web plugin. (&lt;a href="https://blog.postman.com/postman-mocking-magic-for-grpcs/" target="_blank" rel="noopener">Here is an
example&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> from the
gRPC-Web quickstart documentation). This process will create the JavaScript
client files you&amp;rsquo;ll need to make gRPC-Web calls from the browser.&lt;/p>
&lt;p>After your gRPC server is implemented in the language of your choice, you&amp;rsquo;ll
configure an Envoy proxy. &lt;a href="https://blog.postman.com/postman-mocking-magic-for-grpcs/" target="_blank" rel="noopener">Here is another
example&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> from the
gRPC-Web quickstart documentation.&lt;/p>
&lt;p>Here is some YAML syntax of an Envoy configuration which enables gRPC-Web as
part of the larger configuration linked above.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#309;font-weight:bold">http_filters&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>- &lt;span style="color:#309;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>envoy.filters.http.grpc_web&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>- &lt;span style="color:#309;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>envoy.filters.http.router&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>With these elements in place, you can start making gRPC-Web calls from your web
application.&lt;/p>
&lt;h2 id="defining-service-methods-with-protobuf">Defining Service Methods with Protobuf&lt;/h2>
&lt;p>When defining your service methods, Protobuf acts as the single source of truth
by defining the message structure for requests and responses. This strict schema
allows for automatic client and server code generation in multiple languages.
For JavaScript in particular, this code generation streamlines the call process
for the browser client.&lt;/p>
&lt;p>Using the example .proto file above, the generated JavaScript client code would
use these definitions to ensure that only the correct data types are sent and
received. This process handles much of the manual data validation and parsing
that can be error-prone with RESTful services.&lt;/p>
&lt;h2 id="replacing-a-typical-websocket-connection-with-grpc-web">Replacing a Typical WebSocket Connection with gRPC-Web&lt;/h2>
&lt;p>WebSockets provide a full-duplex communication channel over a single long-lived
connection. In scenarios where gRPC-Web cannot fully replace WebSockets due to
its &lt;a href="https://github.com/grpc/grpc-web/blob/master/doc/streaming-roadmap.md#client-streaming-and-half-duplex-streaming" target="_blank" rel="noopener">lack of client streaming
capabilities&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>,
it can still be used for efficient server-to-client streaming.&lt;/p>
&lt;p>Here&amp;rsquo;s a typical WebSocket implementation example:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">const&lt;/span> socket &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> WebSocket(&lt;span style="color:#c30">&amp;#39;ws://example.com/data&amp;#39;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>socket.onmessage &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">function&lt;/span>(event) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">const&lt;/span> receivedData &lt;span style="color:#555">=&lt;/span> JSON.parse(event.data);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> console.log(receivedData);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>};
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>socket.onerror &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">function&lt;/span>(error) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> console.error(&lt;span style="color:#c30">&amp;#39;WebSocket Error:&amp;#39;&lt;/span>, error);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>};
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The WebSocket API is straightforward, but managing the state and lifecycle of
the connection can become complex.&lt;/p>
&lt;p>Now, let&amp;rsquo;s explore how server-side streaming would look with gRPC-Web:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">const&lt;/span> { Empty } &lt;span style="color:#555">=&lt;/span> require(&lt;span style="color:#c30">&amp;#39;./generated/common_pb.js&amp;#39;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">const&lt;/span> { DataServiceClient } &lt;span style="color:#555">=&lt;/span> require(&lt;span style="color:#c30">&amp;#39;./generated/data_grpc_web_pb.js&amp;#39;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">const&lt;/span> client &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> DataServiceClient(&lt;span style="color:#c30">&amp;#39;https://api.example.com&amp;#39;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">const&lt;/span> request &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> Empty();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">const&lt;/span> stream &lt;span style="color:#555">=&lt;/span> client.dataStream(request, {});
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>stream.on(&lt;span style="color:#c30">&amp;#39;data&amp;#39;&lt;/span>, (response) =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> console.log(response.toObject());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>});
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>stream.on(&lt;span style="color:#c30">&amp;#39;error&amp;#39;&lt;/span>, (err) =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> console.error(&lt;span style="color:#c30">&amp;#39;Stream Error:&amp;#39;&lt;/span>, err);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>});
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>stream.on(&lt;span style="color:#c30">&amp;#39;end&amp;#39;&lt;/span>, () =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> console.log(&lt;span style="color:#c30">&amp;#39;Stream ended.&amp;#39;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>});
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>While there is more code involved to replace WebSockets with gRPC-Web, you can
set up a server-side streaming call where the server can continuously send
messages to the client. The client uses event listeners to handle incoming
messages, errors, and the end of the stream. It&amp;rsquo;s a different paradigm than
WebSockets but one that can be more efficient and easier to manage in the
context of supported use cases.&lt;/p>
&lt;p>Many chat applications over WebSockets utilize single client sends and server
streamed events, which gRPC-Web can replace. Even in scenarios where a
multiplayer game was developed, an RPC call of “MoveCharacters” could take a
single message from the browser from where you move your character, and stream
back all of the movements of other players or computer-controlled characters.&lt;/p>
&lt;h2 id="is-it-time-to-replace-rest-and-websockets">Is It Time to Replace REST and WebSockets?&lt;/h2>
&lt;p>This article has begun to scratch the surface of replacing REST and WebSockets
with gRPC-Web, focusing on the reasons for doing so and how to get started with
practical code samples. More work would be needed to fully incorporate error
handling, and to show performance benchmarking, which are beyond the scope of
this document.&lt;/p>
&lt;p>Many technical aspects of gRPC and gRPC-Web, using Envoy, can replace REST and
WebSockets in modern web application development. While there are &lt;a href="https://grpc.io/showcase/" target="_blank" rel="noopener">few
public-facing gRPC APIs&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, it’s a matter of time
before we see more companies adopting the performant nature of HTTP/2 and HTTP/3
based APIs, and consider alternative emerging technologies for web applications.&lt;/p>
&lt;h2 id="grpc-support-in-postman">gRPC Support in Postman&lt;/h2>
&lt;p>If you work with APIs, you probably use Postman. Did you know that &lt;a href="https://blog.postman.com/postman-now-supports-grpc/" target="_blank" rel="noopener">Postman
supports gRPC&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>? Our &lt;a href="https://blog.postman.com/introducing-the-postman-vs-code-extension/" target="_blank" rel="noopener">VS
Code extension supports gRPC
requests&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>,
too, while you’re building your application. We had a great time attending gRPC
Conf this year and meeting with the community. Keep an eye on our blog for
&lt;a href="https://blog.postman.com/?s=grpc" target="_blank" rel="noopener">upcoming updates and articles about gRPC&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. If
you’d like a little history on gRPC, Protobuf, and how they’re used within
Postman, you can also check out our &lt;a href="https://academy.postman.com/grpc-and-postman" target="_blank" rel="noopener">Postman Academy
course&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;p>&lt;em>Technical reviews by &lt;a href="https://twitter.com/kevinswiber" target="_blank" rel="noopener">Kevin Swiber&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> (Postman),
&lt;a href="https://www.linkedin.com/in/eryux/" target="_blank" rel="noopener">Eryu Xia&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> (Google)&lt;/em>&lt;/p></description></item><item><title>Blog: Highlights in gRPConf 2023:Customer Showcase, Developer Engagement, Birds of Feathers Discussions and more.</title><link>https://grpc.io/blog/grpconf-2023-videos/</link><pubDate>Fri, 27 Oct 2023 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/grpconf-2023-videos/</guid><description>
&lt;p>We loved hosting gRPConf 2023 last month in Sunnyvale, California. Thank you to
hundreds of developers from Apple, Cisco, Intel, LinkedIn, Netflix, Salesforce,
to name a few, who joined our special event. We were overwhelmed by the
various topics and advanced use cases around the gRPC ecosystem. If you missed
the opportunity to join in person, here are the video recordings that highlight
the presentations during the day:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://youtu.be/oXv5yzFXgo0" target="_blank" rel="noopener">Keynote gRPC Opening Keynote Abhishek Kumar, Google Arunkumar Jayaraman, Google&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/1PRlQ95T8LY" target="_blank" rel="noopener">Keynote Looking at the Past to Understand our Future Jorge Castro, CNCF&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/E3ez34fdC0k" target="_blank" rel="noopener">Keynote Overview of gRPC Ivy Zhuang, Software Engineer, Google&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/ywrkBqq_LLA" target="_blank" rel="noopener">How Netflix Makes gRPC Easy to Serve, Consume, and Operate Benjamin Fedorka, Netflix&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/U2fgFAuDbGk" target="_blank" rel="noopener">Deep Diving Into gRPC Security A Case Study on API Security Dana White Austin Pearigen&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/TkAn5IYrHyQ" target="_blank" rel="noopener">gRPC Meets Jakarta EE Ron Sigal, Red Hat&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/8HbvEpeu1Lo" target="_blank" rel="noopener">Introducing Protobuf Editions Matt Kulukundis Mike Kruskal, Google&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/8rTIS7PeWW4" target="_blank" rel="noopener">Building and Testing a gRPC API from Scratch Unleash the Potential with Postman W Ian Douglas&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/FbdP2Glh0dw" target="_blank" rel="noopener">What&amp;rsquo;s New in gRPC Security for 2023 Audit Logging and CRL Andrey Ermolov Gregory Cooke, Google&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/Nwby61mIEHA" target="_blank" rel="noopener">Keynote What&amp;rsquo;s New in gRPC Gina Yeh, Google&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/VCq4fsHfFxc" target="_blank" rel="noopener">The Security Evolution of gRPC Services in the Mesh Amim Knabben, VMware&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/_hvdAqid0r0" target="_blank" rel="noopener">Integrating gRPC with the Homa Transport Protocol John Ousterhout, Stanford University&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/e2K5XdIIduE" target="_blank" rel="noopener">Load Testing gRPC Services in Node js Kenny Nguyen, gRPSeek&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://youtu.be/OHU81_TeiLI" target="_blank" rel="noopener">Our Journey Connecting Millions of Containers with gRPC Antoine Tollenaere Sergey Matyukevich&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/grpc-conf-2023-image1.jpg" alt="Conference Gate" id="grpc-conf-2023-image1.jpg" data-toggle="modal" data-target="#modal-grpc-conf-2023-image1.jpg"/>
&lt;div class="modal" id="modal-grpc-conf-2023-image1.jpg">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/grpc-conf-2023-image1.jpg" alt="Conference Gate"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/grpc-conf-2023-image2.jpg" alt="Abhishek Opening Keynote" id="grpc-conf-2023-image2.jpg" data-toggle="modal" data-target="#modal-grpc-conf-2023-image2.jpg"/>
&lt;div class="modal" id="modal-grpc-conf-2023-image2.jpg">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/grpc-conf-2023-image2.jpg" alt="Abhishek Opening Keynote"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/grpc-conf-2023-image6.jpg" alt="Ivy Keynote Talk: gRPC Overview" id="grpc-conf-2023-image6.jpg" data-toggle="modal" data-target="#modal-grpc-conf-2023-image6.jpg"/>
&lt;div class="modal" id="modal-grpc-conf-2023-image6.jpg">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/grpc-conf-2023-image6.jpg" alt="Ivy Keynote Talk: gRPC Overview"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/grpc-conf-2023-image5.jpg" alt="Gina Keynote Talk: What&amp;amp;rsquo;s new in gRPC" id="grpc-conf-2023-image5.jpg" data-toggle="modal" data-target="#modal-grpc-conf-2023-image5.jpg"/>
&lt;div class="modal" id="modal-grpc-conf-2023-image5.jpg">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/grpc-conf-2023-image5.jpg" alt="Gina Keynote Talk: What&amp;amp;rsquo;s new in gRPC"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/grpc-conf-2023-image3.jpg" alt="gRPConf 2023 Audiences" id="grpc-conf-2023-image3.jpg" data-toggle="modal" data-target="#modal-grpc-conf-2023-image3.jpg"/>
&lt;div class="modal" id="modal-grpc-conf-2023-image3.jpg">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/grpc-conf-2023-image3.jpg" alt="gRPConf 2023 Audiences"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/grpc-conf-2023-image4.jpg" alt="gRPConf 2023 Stanford Professor John Ousterhout asks questions" id="grpc-conf-2023-image4.jpg" data-toggle="modal" data-target="#modal-grpc-conf-2023-image4.jpg"/>
&lt;div class="modal" id="modal-grpc-conf-2023-image4.jpg">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/grpc-conf-2023-image4.jpg" alt="gRPConf 2023 Stanford Professor John Ousterhout asks questions"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>We received a wealth of feedbacks from everyone throughout the day which has
helped us shape our future roadmap. Stay tuned to gRPC on many platforms for new
releases, announcements and events:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.youtube.com/@grpcio" target="_blank" rel="noopener">gRPC YouTube Channel&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.meetup.com/grpcio/" target="_blank" rel="noopener">gRPC Meetup Group&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://grpc.io" target="_blank" rel="noopener">Website&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://grpc.io/blog/" target="_blank" rel="noopener">Blog&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/grpc" target="_blank" rel="noopener">GitHub&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://groups.google.com/g/grpc-io" target="_blank" rel="noopener">Google Group Forum&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://twitter.com/grpcio" target="_blank" rel="noopener">Twitter&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Blog: Announcing gRPConf 2023!</title><link>https://grpc.io/blog/grpconf-2023-announcement/</link><pubDate>Wed, 05 Jul 2023 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/grpconf-2023-announcement/</guid><description>
&lt;p>&lt;strong>gRPConf 2023 is happening!&lt;/strong>&lt;/p>
&lt;p>&lt;a href="https://events.linuxfoundation.org/grpc-conf/" target="_blank" rel="noopener">Register now for $50&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> | &lt;a href="https://events.linuxfoundation.org/grpc-conf/program/cfp/" target="_blank" rel="noopener">Submit a Talk&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/p>
&lt;p>Join us at the Google Cloud Campus on September 20, 2023 for a full day of talks, demos, case studies, and code labs. Experts will discuss real-world implementations of gRPC, best practices for developers, and deep dives into specific topics. This is a must-attend event for anyone using gRPC in their applications today, and those considering gRPC for their enterprise microservices.&lt;/p>
&lt;p>There will be ample time to meet project leads and key members of the gRPC ecosystem, network with peers, and ask questions. This will be a great opportunity for us to hear from members of the larger gRPC community and gain valuable feedback on the entire gRPC ecosystem.&lt;/p>
&lt;p>If you’re interested in speaking at gRPConf, please &lt;a href="https://events.linuxfoundation.org/grpc-conf/program/cfp/" target="_blank" rel="noopener">submit a proposal&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. The deadline is July 9, 2023. Spots are still available and topics might include:&lt;/p>
&lt;ul>
&lt;li>gRPC in-production&lt;/li>
&lt;li>User Stories + Case Studies&lt;/li>
&lt;li>Implementation&lt;/li>
&lt;li>Ecosystem + Tooling&lt;/li>
&lt;li>Codelabs&lt;/li>
&lt;/ul>
&lt;p>Speakers who are chosen will be notified by August 1, 2023, and a full schedule announcement will follow shortly after.&lt;/p>
&lt;p>Early bird registration is now open and is only $50. To register or find more information about the event, check out the event page &lt;a href="https://events.linuxfoundation.org/grpc-conf/" target="_blank" rel="noopener">here&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. For any other questions please contact us at &lt;a href="mailto:grpconf@google.com">grpconf@google.com&lt;/a>&lt;/p>
&lt;p>We hope to see you all there!&lt;/p></description></item><item><title>Blog: gRPConf 2023 Schedule</title><link>https://grpc.io/blog/grpconf-2023-schedule/</link><pubDate>Wed, 05 Jul 2023 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/grpconf-2023-schedule/</guid><description>
&lt;p>Hello gRPC Community!&lt;/p>
&lt;p>We are excited to announce that the gRPConf 2023 schedule is now live. We have a schedule with 19 total sessions (5 keynote, 14 breakout) led by a strong group of experts that are using gRPC across a variety of applications and companies. Their experiences and expertise will provide huge value for all attendees whether you are already using gRPC or are still considering it. There will be something for everyone as the talks will span topics such as tooling, implementations, production use, and user stories.&lt;/p>
&lt;p>In addition to our lineup of speakers, this year’s conference is designed to provide plenty of time to hear from the community as well. We’ll be providing breakfast, lunch, and an evening reception to give everyone the chance to network, meet project leads, and ask questions. The feedback gathered from the larger gRPC community is incredibly valuable, so we’ve also built in time for “Birds of a Feather” discussions where we can have more targeted discussions moderated by gRPC team leaders.&lt;/p>
&lt;p>You can view the entire schedule &lt;a href="https://events.linuxfoundation.org/grpc-conf/program/schedule/" target="_blank" rel="noopener">here&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. Early Bird Registration is also still open for $50 until September 6th. If you’re interested in joining us please &lt;a href="https://events.linuxfoundation.org/grpc-conf/register/" target="_blank" rel="noopener">register now&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;p>We’ll see you on September 20th!&lt;/p></description></item><item><title>Blog: gRPC performance benchmarks on GKE</title><link>https://grpc.io/blog/performance-benchmarks-gke/</link><pubDate>Tue, 01 Mar 2022 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/performance-benchmarks-gke/</guid><description>
&lt;p>&lt;a href="https://grpc.io/docs/guides/benchmarking">gRPC performance benchmarks&lt;/a> have now been transitioned to run on
GKE, with similar results but much increased flexibility.&lt;/p>
&lt;h2 id="background">Background&lt;/h2>
&lt;p>gRPC performance testing requires a test driver and workers (one or more clients
and a server), as described in &lt;a href="https://grpc.io/docs/guides/benchmarking">gRPC performance benchmarks&lt;/a>. Each
test may have a different configuration, or &lt;em>scenario&lt;/em>, that is passed to the
driver and specified as a JSON file. Previously, the driver was run by the
continuous integration process, and the workers were run on long-lived GCE VMs.
This gave rise to several limitations:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Tests ran sequentially and were difficult to parallelize, since they ran on
(the same) fixed VMs.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The state of the VMs was not guaranteed to be the same at the start of each
test.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Running manual experiments required configuring new VMs, which was a manual
process, or reusing existing VMs, with the risks of collision with other
users and of having VMs in an unknown state.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h2 id="benchmarking-on-kubernetes">Benchmarking on Kubernetes&lt;/h2>
&lt;p>The core of the current framework is a &lt;a href="https://github.com/grpc/test-infra/blob/master/cmd/controller/main.go" target="_blank" rel="noopener">custom controller&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> for managing
Kubernetes resources of kind &lt;a href="https://github.com/grpc/test-infra/blob/master/config/crd/bases/e2etest.grpc.io_loadtests.yaml" target="_blank" rel="noopener">LoadTest&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. This controller must be
deployed to a Kubernetes cluster before load tests can be run on it. The
controller is implemented with &lt;a href="https://kubebuilder.io" target="_blank" rel="noopener">kubebuilder&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. The code for the controller is
stored in the &lt;a href="https://github.com/grpc/test-infra" target="_blank" rel="noopener">Test Infra&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> repository. For further documentation on
individual LoadTest fields, see the &lt;a href="https://github.com/grpc/test-infra/blob/master/api/v1/loadtest_types.go" target="_blank" rel="noopener">LoadTest
implementation&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;p>LoadTest configurations specify driver, client and server pods to be created for
the test. Once the configuration is applied to the cluster (for instance, with
&lt;code>kubectl apply -f&lt;/code>), the controller will create the pods and the test will run.
If multiple configurations are applied to the cluster, the controller will
create pods as long as there are resources available, allowing tests to run in
parallel.&lt;/p>
&lt;p>&lt;a href="https://github.com/grpc/test-infra/blob/master/config/samples/README.md" target="_blank" rel="noopener">Examples&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> include basic configurations that can be applied directly,
and templates that require additional steps and parameter substitution.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Basic configurations rely on &lt;strong>clone&lt;/strong>, &lt;strong>build&lt;/strong> and &lt;strong>runtime&lt;/strong> worker
images that are bundled with each release of the controller. The clone and
build images are used to build gRPC binaries that are passed to the runtime
container. These configurations are suitable as examples and for one-off
testing.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Template configurations rely on worker images that are built before starting
the tests. These &lt;strong>prebuilt images&lt;/strong> include the gRPC binary, eliminating the
need to clone and build before each test. Template substitution is used to
point to the location of the worker images. These configurations are suitable
for running a batch of tests on the same gRPC version, or for running the same
test repeatedly.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>In addition to the controller, the &lt;a href="https://github.com/grpc/test-infra" target="_blank" rel="noopener">Test Infra&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> repository contains a
set of &lt;a href="https://github.com/grpc/test-infra/blob/master/tools/README.md" target="_blank" rel="noopener">tools&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, including a test runner and tools to build and delete prebuilt
worker images, as well as a &lt;a href="#dashboard">dashboard&lt;/a> implementation.&lt;/p>
&lt;p>The tools related to prebuilt workers use &lt;code>gcloud&lt;/code> internally and are dependent
on GKE. Other than that, all components of the framework are built on Kubernetes
itself and independent of GKE. That is, it should be possible to deploy the
controller and run tests on a custom Kubernetes cluster or on another cloud
provider&amp;rsquo;s Kubernetes offering.&lt;/p>
&lt;h2 id="cluster-setup">Cluster setup&lt;/h2>
&lt;p>The cluster running benchmark jobs must be configured with node pools
dimensioned for the number of simultaneous tests that it should support. The
controller uses &lt;code>pool&lt;/code> as a node selector for the various pod types. Worker pods
have mutual anti-affinity, so one node is required per pod.&lt;/p>
&lt;p>For example, the node pools that are used in our continuous integration setup
are configured as follows:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Pool name&lt;/th>
&lt;th style="text-align:right">Node count&lt;/th>
&lt;th style="text-align:left">Machine type&lt;/th>
&lt;th style="text-align:left">Kubernetes labels&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">system&lt;/td>
&lt;td style="text-align:right">2&lt;/td>
&lt;td style="text-align:left">e2-standard-8&lt;/td>
&lt;td style="text-align:left">default-system-pool:true, pool:system&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">drivers-ci&lt;/td>
&lt;td style="text-align:right">8&lt;/td>
&lt;td style="text-align:left">e2-standard-2&lt;/td>
&lt;td style="text-align:left">pool:drivers-ci&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">workers-c2-8core-ci&lt;/td>
&lt;td style="text-align:right">8&lt;/td>
&lt;td style="text-align:left">c2-standard-8&lt;/td>
&lt;td style="text-align:left">pool:workers-c2-8core-ci&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">workers-c2-30core-ci&lt;/td>
&lt;td style="text-align:right">8&lt;/td>
&lt;td style="text-align:left">c2-standard-30&lt;/td>
&lt;td style="text-align:left">pool:workers-c2-30core-ci&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Since each scenario in our tests requires one driver and two workers, this
configuration supports four simultaneous tests on 8-core machines and four on
30-core machines. Drivers require few resources, and do not have mutual
anti-affinity. We find it convenient to schedule them on two-core machines with
a node count set to the required number of drivers, rather than on a larger
shared machine, because that allows the driver pool to be resized together with
the worker pools. The controller itself is scheduled in the &lt;code>system&lt;/code> pool.&lt;/p>
&lt;p>In addition to the pools used in continuous integration, our cluster contains
additional node pools that can be used for ad hoc testing:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Pool name&lt;/th>
&lt;th style="text-align:right">Node count&lt;/th>
&lt;th style="text-align:left">Machine type&lt;/th>
&lt;th style="text-align:left">Kubernetes labels&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">drivers&lt;/td>
&lt;td style="text-align:right">8&lt;/td>
&lt;td style="text-align:left">e2-standard-8&lt;/td>
&lt;td style="text-align:left">default-driver-pool:true, pool:drivers&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">workers-8core&lt;/td>
&lt;td style="text-align:right">8&lt;/td>
&lt;td style="text-align:left">e2-standard-8&lt;/td>
&lt;td style="text-align:left">default-worker-pool:true, pool:workers-8core&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">workers-32core&lt;/td>
&lt;td style="text-align:right">8&lt;/td>
&lt;td style="text-align:left">e2-standard-32&lt;/td>
&lt;td style="text-align:left">pool:workers-32core&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Some pools are labeled with &lt;code>default-*-pool&lt;/code> labels. These labels specify which
pool to use if it is not specified in the LoadTest configuration. With the
configuration above, these tests (for instance, the tests specified in the
&lt;a href="https://github.com/grpc/test-infra/blob/master/config/samples/README.md" target="_blank" rel="noopener">examples&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>) will use the &lt;code>drivers&lt;/code> and &lt;code>workers-8core&lt;/code> pools, and not
interfere with continuous integration jobs. The default labels are defined as
part of the controller build: if they are not set, the controller will only run
tests where the &lt;code>pool&lt;/code> labels are specified explicitly.&lt;/p>
&lt;h2 id="controller-deployment">Controller deployment&lt;/h2>
&lt;p>The steps for building and deploying a controller are described in the
&lt;a href="https://github.com/grpc/test-infra/blob/master/doc/deployment.md" target="_blank" rel="noopener">deployment documentation&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;h2 id="continuous-integration">Continuous integration&lt;/h2>
&lt;p>Our continuous integration setup is described in the &lt;a href="https://github.com/grpc/grpc/blob/master/tools/run_tests/performance/README.md#grpc-oss-benchmarks" target="_blank" rel="noopener">gRPC OSS benchmarks
README&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> in the &lt;a href="https://github.com/grpc/grpc" target="_blank" rel="noopener">gRPC Core&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> repository. The main continuous integration job
uses the script &lt;a href="https://github.com/grpc/grpc/blob/master/tools/internal_ci/linux/grpc_e2e_performance_gke.sh" target="_blank" rel="noopener">grpc_e2e_performance_gke.sh&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> to generate the data presented
on the dashboard linked to the &lt;a href="https://grpc.io/docs/guides/benchmarking">gRPC performance benchmarks&lt;/a> page.&lt;/p>
&lt;p>Each continuous integration run has three phases:&lt;/p>
&lt;ol>
&lt;li>Generate test configurations.&lt;/li>
&lt;li>Build and push worker images.&lt;/li>
&lt;li>Run the tests.&lt;/li>
&lt;/ol>
&lt;p>Each continuous integration run executes 122 tests using the 8-core worker pool,
and 98 test using the 30-core worker pool. Each test runs one test scenario.
Tests using C++, C#, Java and Python workers run on both pools. Tests using
Node.js, PHP and Ruby workers run only on the 8-core pool.
&lt;a href="#config-generation">Config generation&lt;/a> for all these combinations takes
negligible time (~1s).&lt;/p>
&lt;p>The configurations used in continuous integration require worker images that
include the gRPC binaries to be tested. These images depend only on the worker&amp;rsquo;s
language, so these &lt;a href="#prebuilt-images">prebuilt images&lt;/a> are built in advance and
pushed to an image repository. This process takes approximately 20 minutes.&lt;/p>
&lt;p>A &lt;a href="#test-runner">test runner&lt;/a> manages the rate at which tests are applied to the
cluster, collects test results and logs, and deletes tests once they complete
successfully. Two tests at a time are allowed to run on each pool. This phase
takes approximately 50 minutes to complete.&lt;/p>
&lt;p>Each test scenario is configured to take 30s to run, plus a 5s warm-up period
(15s for Java). This places a lower bound on the time needed to run each test.
The observed run time of the 122 tests in the 8-core pool (16 of them in Java),
running two tests at a time, implies that the overhead introduced by pod
creation and deletion is modest, at ~12.8s per test.&lt;/p>
&lt;h3 id="config-generation">Config generation&lt;/h3>
&lt;p>Since we are running hundreds of tests that mostly share the same components
(driver and workers for the various languages), it becomes necessary to generate
configurations that includes repetitive driver and worker configurations and
differ only in the scenario being tested. In addition, each configuration must
have a unique name, since that is a requirement for resources applied to a
Kubernetes cluster.&lt;/p>
&lt;p>We handle these issues by &lt;a href="https://github.com/grpc/grpc/blob/master/tools/run_tests/performance/README.md#generating-load-test-configurations" target="_blank" rel="noopener">generating load test configurations&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> with a tool.
The tool is stored in the &lt;a href="https://github.com/grpc/grpc" target="_blank" rel="noopener">gRPC Core&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> repository, where test scenarios are also
defined.&lt;/p>
&lt;h3 id="prebuilt-images">Prebuilt images&lt;/h3>
&lt;p>The configurations generated for continuous integration use a set of prebuilt
images. These images are built and pushed to an image repository before running
tests. The images are deleted at the end of each test run.&lt;/p>
&lt;p>For details on the tools used to prepare and delete images, see &lt;a href="https://github.com/grpc/test-infra/blob/master/tools/README.md#using-prebuilt-images-with-grpc-oss-benchmarks" target="_blank" rel="noopener">Using prebuilt
images with gRPC OSS benchmarks&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;h3 id="test-runner">Test runner&lt;/h3>
&lt;p>The &lt;a href="https://github.com/grpc/test-infra/blob/master/tools/README.md#test-runner" target="_blank" rel="noopener">test runner&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> takes the test configurations generated previously, applies
each configuration to the cluster, polls each LoadTest resource for completion,
collects artifacts such as results and pod logs, and (optionally) deletes
resources once each test completes successfully.&lt;/p>
&lt;p>The test runner maintains separate &lt;em>queues&lt;/em> for tests that require the same
resources on the cluster (e.g. 8-core or 30-core worker nodes). Tests
configurations belonging to the same queue are not applied ot the cluster at
once, but according to a &lt;em>concurrency level&lt;/em> set for each queue. Our continuous
integration tests run in two queues (corresponding to 8-core and 30-core worker
nodes). The concurrency level of each queue is set to two.&lt;/p>
&lt;p>Once a configuration is applied to the cluster, the controller creates client,
driver and server pods to run the test, monitors test execution, and updates the
status of the LoadTest resource.&lt;/p>
&lt;p>The design of the test runner can be explained as follows:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>The use of the test runner allows the continuous integration job to wait for
all tests to complete, collect tests artifacts, and prepare a report with
results.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The use of separate queues (indicated by annotations in each test
configuration) allows tests that do not require the same cluster resources to
be managed independently of each other.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The use of limited concurrency levels reduces the number of tests applied to
the cluster at a time. This has several benefits:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>The load on the test runner is reduced, since there are fewer LoadTest
resources on the cluster at a time, and the runner polls these resources
periodically for completion. The polling interval in our continuous
integration is set to 5s.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The load on the controller is reduced, since there are fewer LoadTest
resources at a time for it to control.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Each test can have a shorter timeout period, since the time takes for the
controller to start each test is more predictable. Timeouts are necessary
to account for error cases where client or server pods hang and prevent
the test from completing. These cases are rare but can accumulate and
consume cluster resources, preventing other tests from running. Tests in
our continuous integration have a timeout of 15 minutes.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The concurrency level can be set lower than the capacity of the cluster,
allowing a user to run a batch of tests without preventing other users
from running tests simultaneously.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;p>The option of deleting each test once it completes successfully (and after
results and logs are collected) provides better control of the lifecycle of
each test.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>The default behavior of the controller is to keep a LoadTest resource and
associated pods on the cluster until it reaches a set TTL, and then delete
it. Our continuous integration specifies a TTL of 24h for each test.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Pods belonging to a completed LoadTest are in terminated state, and so
consume no resources on the cluster. However, terminated pods can be
garbage-collected at any time.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>If we let pods belonging to all completed tests stay in our continuous
integration cluster, we find that they are garbage-collected within one
hour.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>If we delete LoadTest resources for tests that complete successfully, the
associated pods are also deleted. In this case, the pods belonging to
&lt;em>unsuccessful&lt;/em> tests, which are few in number and may be useful for
debugging, stay on the cluster until the 24h TTL is reached.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ol>
&lt;h3 id="dashboard">Dashboard&lt;/h3>
&lt;p>Test results from continuous integration are saved to &lt;a href="https://cloud.google.com/bigquery" target="_blank" rel="noopener">BigQuery&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. The
data stored in BigQuery is then replicated to a Postgres database for
visualization on a dashboard.&lt;/p>
&lt;p>The code for the dashboard, as well as the configuration of the main continuous
integration dashboard, are stored in the &lt;a href="https://github.com/grpc/test-infra" target="_blank" rel="noopener">Test Infra&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> repository.
This brings the following benefits:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>The main dashboard is maintained by updating the stored configuration,
instead of updating it directly in the UI.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Users can deploy their own dashboard, using their own configuration.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>This contrasts with the dashboard for the previous benchmarks, built using
Perfkit Explorer, which was maintained by updating it directly in the UI, and
could not be easily replicated by users.&lt;/p>
&lt;p>For details, see &lt;a href="https://github.com/grpc/test-infra/tree/master/dashboard/README.md" target="_blank" rel="noopener">dashboard implementation&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;p>&lt;a href="https://grafana-dot-grpc-testing.appspot.com" target="_blank" rel="noopener">
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/blog/performance-benchmarks-gke/dashboard.png" alt="Dashboard snapshot" id="dashboard" data-toggle="modal" data-target="#modal-dashboard"/>
&lt;div class="modal" id="modal-dashboard">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/blog/performance-benchmarks-gke/dashboard.png" alt="Dashboard snapshot"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;span class="hk-no-external-icon">&lt;/span>&lt;/a>&lt;/p>
&lt;h2 id="results">Results&lt;/h2>
&lt;p>The following observations can be made on the results and user experience of the
gRPC benchmarking on GKE:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Performance metrics (latency, QPS, etc.) produce the same or better results
as the old benchmarks on GCE.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The overhead of pod creation and deletion for each test in GKE is small (less
than 15s) in our benchmarking cluster.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Test images are dockerized and started again for each test, resulting in
several benefits:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Results are more consistent.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Runtime errors are rare.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>System is split into well-defined components, resulting in simpler
upgrades.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Tests can be easily parallelized, resulting in faster execution times.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Experiments are easier to perform.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ol>
&lt;p>Examples of best practices and insights derived from experimentation:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Use &lt;code>c2&lt;/code> instances for clients and servers (instance types matter a lot for
the observed latency and its variance and also for the measured throughput).&lt;/p>
&lt;/li>
&lt;li>
&lt;p>GKE pod-to-pod networking only has a very small overhead over raw GCE
networking. You can get raw GCE networking performance by setting
&lt;code>hostnetworking:true&lt;/code> for the benchmark pods.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>For Java under Docker, the JVM may not be able to detect the number of
available processors automatically. This can lead to very pessimistic
results, since gRPC uses the detected number of processors for sizing thread
pools for processing events. A workaround is to set the number of processors
explicitly. This workaround is implemented
&lt;a href="https://github.com/grpc/test-infra/pull/231" target="_blank" rel="noopener">here&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h2 id="running-your-own">Running your own&lt;/h2>
&lt;p>The code in the &lt;a href="https://github.com/grpc/test-infra" target="_blank" rel="noopener">Test Infra&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> repository allows any user to create a
cluster, deploy a controller, run gRPC benchmarks, and display results on their
own dashboards. If you are interested in performance, and run your own
benchmarks, &lt;a href="https://groups.google.com/g/grpc-io" target="_blank" rel="noopener">let us know!&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/p></description></item><item><title>Blog: Running gRPC and Protobuf on ARM64 (on Linux)</title><link>https://grpc.io/blog/grpc-on-arm64/</link><pubDate>Wed, 23 Jun 2021 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/grpc-on-arm64/</guid><description>
&lt;p>ARM processors have recently been gaining importance in many areas of compute, including those that were traditionally considered to be an x86_64-only domain. Thanks to the momentum around the ARM ecosystem, we can expect adoption of ARM platforms to grow significantly. The same is true for providing software that supports ARM-based platforms.&lt;/p>
&lt;p>Since the main purpose of gRPC and protocol buffers is to interconnect distributed systems, their role in supporting ARM compute is especially important. With the emergence of ARM Cloud computing, we expect many systems will actually be hybrid compositions of x86 and ARM servers, mixing and matching the qualities of each ecosystem as needed. gRPC and protocol buffers are the ideal building blocks that can enable users to build systems that span multiple architectures seamlessly.&lt;/p>
&lt;p>To meet the very high demand from gRPC users to support ARM, the gRPC team has decided to support selected ARM-based platforms officially and fully. Some time ago, we started an effort to test everything and fix any problems we encounter. &lt;strong>Today, we are happy to announce that gRPC and protocol buffers implementations in C++, C#, Go, Java, Node, PHP, Python and Ruby are ready for production workloads for ARM64 Linux&lt;/strong> (see more details below).&lt;/p>
&lt;p>The current state of things is best described by a list of general areas we completed:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Bugfixes/improvements:&lt;/strong> We put a number of fixes in place to make sure gRPC and protobuf work reliably on ARM64 Linux.&lt;/li>
&lt;li>&lt;strong>Package &amp;amp; Distribution:&lt;/strong> For the languages that provide binary architecture-specific packages, we added ARM64 Linux packages, and we started publishing them on every release as part of our standard release process. Having ready-to-use binary packages greatly improves the developer experience. For languages that don&amp;rsquo;t ship binary packages, we tested that the build works as expected and that one can install gRPC and protobuf on ARM64 Linux without problems.&lt;/li>
&lt;li>&lt;strong>Continuous Testing:&lt;/strong> We invested significant resources setting up continuous testing ensuring that gRPC and protobuf are fully tested and prevent any future regressions. Testing large projects with many tests and support for multiple languages was definitely a challenge, especially since the open source ecosystem for testing on ARM architecture is still in its infancy, but we successfully tested gRPC and protobuf with a combination of cross-compilation, emulated tests and running tests on real hardware.&lt;/li>
&lt;/ul>
&lt;h2 id="overview-of-grpc-and-protobuf-support-on-arm64-linux">Overview of gRPC and Protobuf support on ARM64 Linux&lt;/h2>
&lt;p>In the following table you can see the detailed status broken down by language. Each entry summarizes the support level for both gRPC and Protobuf on ARM64 Linux.&lt;/p>
&lt;table>
&lt;tr>
&lt;td style="white-space: nowrap">Language&lt;/td>
&lt;td style="white-space: nowrap">continuously tested&lt;/td>
&lt;td>distribution/packages&lt;/td>
&lt;td>additional info&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>C++&lt;/td>
&lt;td style="background: #90ee90;">✔️&lt;/td>
&lt;td style="background: #90ee90;">Build from source using cmake or bazel (same approach as on x86_64)&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>C#&lt;/td>
&lt;td style="background: #90ee90;">✔️&lt;/td>
&lt;td style="background: #90ee90;">Grpc.Core nuget packages now have aarch64 Linux support (starting from &lt;code>v2.38.1&lt;/code>)&lt;/td>
&lt;td>Grpc.Tools nuget package has now support for codegen on aarch64 Linux&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Go&lt;/td>
&lt;td style="background: #90ee90;">✔️ &lt;sup>1&lt;/sup>&lt;/td>
&lt;td style="background: #90ee90;">Use the standard way of installing libraries in golang (same experience as on x86_64)&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Java&lt;/td>
&lt;td style="background: #90ee90;">✔️&lt;/td>
&lt;td style="background: #90ee90;">Maven artifacts published with each release work well on aarch64 Linux&lt;/td>
&lt;td>aarch64 protoc and grpc-java protoc plugin are published with each release&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="white-space: nowrap">Node/Javascript&lt;/td>
&lt;td style="background: #90ee90;">✔️&lt;/td>
&lt;td style="background: #90ee90;">Use existing npm packages (they are platform-independent)&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>PHP&lt;/td>
&lt;td style="background: #90ee90;">✔️&lt;/td>
&lt;td style="background: #90ee90;">Existing PECL and composer packages work well on aarch64 Linux&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Python&lt;/td>
&lt;td style="background: #90ee90;">✔️&lt;/td>
&lt;td style="background: #90ee90;">Pre-built wheels for aarch64 Linux are published with each release (starting from &lt;code>v1.38.1&lt;/code>)&lt;/td>
&lt;td>grpcio-tools package has now support for codegen on aarch64 Linux&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Ruby&lt;/td>
&lt;td style="background: #90ee90;">✔️&lt;/td>
&lt;td style="background: #ffcccb;">Pre-built native gems for aarch64 Linux not available yet. In order to use grpc-ruby and protobuf-ruby, users need to build the gems from source&lt;/td>
&lt;td>Continuous tests are in place and they are passing consistently, but we don't yet provide pre-built packages. gRPC and protobuf in ruby are safe to use, but the installation experience is suboptimal&lt;/td>
&lt;/tr>
&lt;/table>
&lt;p>&lt;em>&lt;sup>1&lt;/sup> continuous testing is in place for grpc-go and in-progress for protobuf-go. protobuf-go has been tested on aarch64 manually and has been found to work reliably.&lt;/em>&lt;/p>
&lt;h3 id="arm64--aarch64--armv8-terminology">ARM64 / aarch64 / ARMv8 terminology&lt;/h3>
&lt;p>While the terms ARM64, aarch64 and ARMv8 denote slightly different things, in practice they are often used interchangeably. For purposes of this article, they all mean essentially the same thing and they can be treated as synonyms.&lt;/p>
&lt;h3 id="official-arm64-support-is-currently-linux-only">Official ARM64 support is currently Linux-only&lt;/h3>
&lt;p>At this point we only officially support gRPC and Protobuf on ARM64 on Linux. We do realize that there&amp;rsquo;s demand for ARM64 support for other platforms as well (e.g. MacOS X with the new Apple M1 Silicon), but some of these platforms come with significant challenges (provisioning the hardware, lack of emulation, etc). Rather than delaying the ARM64 support release due to these complications, it made more sense to stay focused on delivering official ARM64 support to Linux first - so there we go.&lt;/p>
&lt;h2 id="appendix-list-of-changesfixesimprovements">Appendix: list of changes/fixes/improvements&lt;/h2>
&lt;p>&lt;code>grpc/grpc&lt;/code> repository&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/grpc/grpc/pull/25258" target="_blank" rel="noopener">https://github.com/grpc/grpc/pull/25258&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/grpc/grpc/pull/25418" target="_blank" rel="noopener">https://github.com/grpc/grpc/pull/25418&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/grpc/grpc/pull/25453" target="_blank" rel="noopener">https://github.com/grpc/grpc/pull/25453&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/grpc/grpc/pull/25517" target="_blank" rel="noopener">https://github.com/grpc/grpc/pull/25517&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/grpc/grpc/pull/25602" target="_blank" rel="noopener">https://github.com/grpc/grpc/pull/25602&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/grpc/grpc/pull/25717" target="_blank" rel="noopener">https://github.com/grpc/grpc/pull/25717&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/grpc/grpc/pull/25928" target="_blank" rel="noopener">https://github.com/grpc/grpc/pull/25928&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/grpc/grpc/pull/26136" target="_blank" rel="noopener">https://github.com/grpc/grpc/pull/26136&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/grpc/grpc/pull/26409" target="_blank" rel="noopener">https://github.com/grpc/grpc/pull/26409&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/grpc/grpc/pull/26416" target="_blank" rel="noopener">https://github.com/grpc/grpc/pull/26416&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/grpc/grpc/pull/26430" target="_blank" rel="noopener">https://github.com/grpc/grpc/pull/26430&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>&lt;code>grpc/grpc-java&lt;/code> repository&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/grpc/grpc-java/pull/8113" target="_blank" rel="noopener">https://github.com/grpc/grpc-java/pull/8113&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/grpc/grpc-java/pull/7812" target="_blank" rel="noopener">https://github.com/grpc/grpc-java/pull/7812&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/grpc/grpc-java/pull/7822" target="_blank" rel="noopener">https://github.com/grpc/grpc-java/pull/7822&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>&lt;code>grpc/grpc-go&lt;/code> repostitory&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/grpc/grpc-go/pull/4344" target="_blank" rel="noopener">https://github.com/grpc/grpc-go/pull/4344&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>&lt;code>protocolbuffers/protobuf&lt;/code> repository&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/protocolbuffers/protobuf/pull/8280" target="_blank" rel="noopener">https://github.com/protocolbuffers/protobuf/pull/8280&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/protocolbuffers/protobuf/pull/8391" target="_blank" rel="noopener">https://github.com/protocolbuffers/protobuf/pull/8391&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/protocolbuffers/protobuf/pull/8392" target="_blank" rel="noopener">https://github.com/protocolbuffers/protobuf/pull/8392&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/protocolbuffers/protobuf/pull/8485" target="_blank" rel="noopener">https://github.com/protocolbuffers/protobuf/pull/8485&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/protocolbuffers/protobuf/pull/8501" target="_blank" rel="noopener">https://github.com/protocolbuffers/protobuf/pull/8501&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/protocolbuffers/protobuf/pull/8544" target="_blank" rel="noopener">https://github.com/protocolbuffers/protobuf/pull/8544&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/protocolbuffers/protobuf/pull/8638" target="_blank" rel="noopener">https://github.com/protocolbuffers/protobuf/pull/8638&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Blog: The future of gRPC in C# belongs to grpc-dotnet</title><link>https://grpc.io/blog/grpc-csharp-future/</link><pubDate>Sat, 01 May 2021 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/grpc-csharp-future/</guid><description>
&lt;p>&lt;strong>Update 2023-10-02: The maintenance period for &lt;code>Grpc.Core&lt;/code> has been extended again, until at least October 2024. See &lt;a href="https://groups.google.com/g/grpc-io/c/iEalUhV4VrU" target="_blank" rel="noopener">announcement&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> for up to date info on &lt;code>Grpc.Core&lt;/code>.&lt;/strong>&lt;/p>
&lt;p>&lt;strong>Update 2022-05-03: The maintenance period for &lt;code>Grpc.Core&lt;/code> has been extended until May 2023. See &lt;a href="https://groups.google.com/g/grpc-io/c/OTj5mb1qzb0" target="_blank" rel="noopener">announcement&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> for more info on the future of &lt;code>Grpc.Core&lt;/code>.&lt;/strong>&lt;/p>
&lt;p>&lt;strong>TL;DR&lt;/strong> grpc-dotnet (the
&lt;a href="https://www.nuget.org/packages/Grpc.Net.Client/" target="_blank" rel="noopener">Grpc.Net.Client&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> and
&lt;a href="https://www.nuget.org/packages/Grpc.AspNetCore.Server/" target="_blank" rel="noopener">Grpc.AspNetCore.Server&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
nuget packages) is now the recommended gRPC implementation for .NET/C#. The
original gRPC C# implementation (the Grpc.Core nuget package) will enter
maintenance mode and won&amp;rsquo;t be getting any new features and will only receive
important bug fixes and security fixes going forward. The ultimate plan is to
phase out Grpc.Core completely at some point in the future. This announcement
describes the reasons why we have decided to do so and lays out the plan in more
detail.&lt;/p>
&lt;p>In September 2019 we &lt;a href="https://grpc.io/blog/grpc-on-dotnetcore/">announced&lt;/a>
general availability of a new &lt;a href="https://github.com/grpc/grpc-dotnet" target="_blank" rel="noopener">gRPC C#
implementation&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> that is no longer based on
the gRPC C core native library and that&amp;rsquo;s using the HTTP/2 protocol
implementation that was added in .NET Core 3 and ASP.NET Core 3. We refer to
this implementation as &amp;ldquo;grpc-dotnet&amp;rdquo;.&lt;/p>
&lt;p>When we were introducing the grpc-dotnet implementation, we announced that both
gRPC C# implementations (the new pure C# grpc-dotnet implementation and the
original gRPC C# implementation based on C core native library) would co-exist
side by side, letting the users choose which implementation works best for them.
That made a lot of sense since grpc-dotnet was brand new back then and required
a just-released .NET Core framework, while the original gRPC C# implementation
had been stable for a long time, had lots of users and worked on even very old
.NET Framework versions. Things needed some time to settle.&lt;/p>
&lt;p>Since then, the new grpc-dotnet implementation has come a long way: it has been
adopted by many users and became very popular, it has been used by a lot of
applications in production environments, and has also added a lot of interesting
new features. In addition, its main prerequisite, the .NET Core 3 framework, has
been around for a while now and its adoption numbers are growing.&lt;/p>
&lt;p>At the same time, while the &lt;a href="https://github.com/grpc/grpc/tree/master/src/csharp" target="_blank" rel="noopener">original gRPC C#
implementation&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> (often
referred to as &amp;ldquo;Grpc.Core&amp;rdquo;, the name of its nuget package) definitely has its
place and it is hugely popular, we are now nearing a point where some of the
design decisions that made perfect sense back in 2016 (when gRPC C# was released
as GA) no longer have the weight they used to. For example, we decided to base
the gRPC C# implementation on a native library because in 2016, there was no
usable C# HTTP/2 library that we could depend on. By depending on the C core
native library instead, we were able to deliver a stable, high performance gRPC
library much faster than if we had to implement everything in C# from scratch.
But from today&amp;rsquo;s perspective, taking a native dependency doesn&amp;rsquo;t make that much
sense anymore since HTTP/2 support is now built into the .NET Core framework.
The benefits of having a native dependency are diminishing, while the
maintenance burden of having one is staying the same.&lt;/p>
&lt;p>Out of the two stable C# implementations, the grpc-dotnet implementation is
definitely the one that has more future potential. It is a more modern
implementation that is well-integrated with the modern versions of .NET and it&amp;rsquo;s
likely going to be more aligned with where the C# community will be a few years
from now. It is also a pure C# implementation (no native components), which
makes it much more contribution friendly, leads to better debuggability and it
is simply also something that C# enthusiasts like to see.&lt;/p>
&lt;p>Because the maintenance costs of having two official implementations of gRPC for
C# are nontrivial and because grpc-dotnet seems to be the best choice for all
users in the long run, we would like to &lt;strong>announce the intent to phase out the
original gRPC C# implementation (nuget package Grpc.Core) in favor of the more
modern and more forward-looking grpc-dotnet implementation&lt;/strong>.&lt;/p>
&lt;p>The details of the plan are described in the following sections, along with
further explanation why it makes sense. To help understand the consequences of
the decision to phase out Grpc.Core, we have also come up with a list of
frequently asked questions and provided answers to them.&lt;/p>
&lt;h3 id="what-makes-grpc-dotnet-the-preferred-implementation">What makes grpc-dotnet the preferred implementation&lt;/h3>
&lt;p>Simply said, grpc-dotnet seems to be a better bet for the future. Some of the
most important points were already mentioned. Here is a more detailed list of
reasons why we believe grpc-dotnet will serve the users&amp;rsquo; needs better:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>It&amp;rsquo;s a more modern implementation, based on features of the recent version of
the .NET framework. As such, it will probably be the more viable one of the
two implementations in the future.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>It&amp;rsquo;s more aligned with where the C# / .NET community is now and in the future.
Staying aligned with where the community is heading seems to be the best bet
for the future of gRPC in C#.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The implementation is much more agile and contribution friendly - because it&amp;rsquo;s
internally based on well known primitives / APIs (ASP.NET core serving APIs
and HTTP2 client) and it&amp;rsquo;s implemented in pure C#, the code is much more
accessible to C# developers (both to users that just want to understand how
things work and to potential contributors who would author PRs). The
grpc-dotnet codebase is relatively small, it takes seconds to build, running
the tests is easy and quick. In the long run, easier development and
contribution friendliness should make up for some of the features that are
missing today and make it a superior choice for the users &amp;ndash; that is,
lowering the barrier to
contribute and fix/improve stuff translates into more stuff being fixed and
better user experience after some time.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Having a library that is implemented in pure C# is something that&amp;rsquo;s generally
favored by the .NET community, compared to an implementation that depends on a
native component. While C# has good support for interoperating with native
libraries, it is a technique that most C# developers are not familiar with and
it looks like a black box to them. Native interop is tricky to get it right
and has many downsides (e.g. more complicated development and build process,
complex debugging, hard to maintain, hard to get community contributions, hard
to provide support for multiple platforms). With Grpc.Core we were able to
overcome most of these challenges (so things work these days), but it has been
a lot of effort, the solutions are sometimes complex and fragile and
maintaining it is costly and requires a lot of expertise.&lt;/p>
&lt;p>NOTE: the Google.Protobuf library for C# is already written purely in C# (no
native components), so having a pure C# implementation of gRPC gets rid of
native components from developers&amp;rsquo; microservice stack completely&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="why-not-keep-grpccore-forever">Why not keep Grpc.Core forever?&lt;/h3>
&lt;p>Developing two implementations of gRPC in C# isn&amp;rsquo;t free. It costs valuable
resources and we believe that the engineering time would be better spent on
making gRPC in C# easier to use and on adding new features (and fixing bugs of
course), rather than needing to work on two different codebases that both serve
the same purpose. Also, having two separate implementations necessarily
fragments the user base to some extent and splits the contributors&amp;rsquo; efforts into
two. Also just the simple act of users needing to choose which of the two
implementations they want to bet on comes with uncertainty and inherent risk
(none of which we want for our users).&lt;/p>
&lt;p>By making grpc-dotnet the recommended implementation and by making the Grpc.Core
implementation &amp;ldquo;maintenance only&amp;rdquo; (and eventually phasing it out), we are aiming
to achieve the following goals:&lt;/p>
&lt;ul>
&lt;li>Free up engineering resources to work on better features and better usability.&lt;/li>
&lt;li>Unify the gRPC C# user base. This will lead to directing all community work
and contributions toward a single implementation. It also removes the inherent
friction caused by the user needing to choose which of the two official
implementations to use.&lt;/li>
&lt;li>Address some of the well known pain points of Grpc.Core that would be too
difficult to address by other means.&lt;/li>
&lt;li>Futureproof C#/.NET implementation of gRPC by staying aligned with the .NET
community.&lt;/li>
&lt;/ul>
&lt;h3 id="the-plan">The plan&lt;/h3>
&lt;p>&lt;strong>Phase 1: Grpc.Core becomes &amp;ldquo;Maintenance Only&amp;rdquo;&lt;/strong>&lt;/p>
&lt;p>&lt;strong>When: Effective immediately (May 2021)&lt;/strong>&lt;/p>
&lt;p>From now on, we are no longer going to provide new features or enhancements for
Grpc.Core. Important bugs and security issues will continue to be addressed in a
normal way.&lt;/p>
&lt;p>We will publish Grpc.Core releases normally, with the usual 6 weekly cadence.&lt;/p>
&lt;p>The releases will be based on the newest grpc C core native library build, so
all new features that don&amp;rsquo;t require C# specific work will also be included.&lt;/p>
&lt;p>&lt;strong>Phase 2: Grpc.Core becomes &amp;ldquo;Deprecated&amp;rdquo;&lt;/strong>&lt;/p>
&lt;p>&lt;strong>When: 1 year from now (May 2022)&lt;/strong>&lt;/p>
&lt;p>Once this milestone is reached, Grpc.Core will no longer be officially supported
and all the users will be strongly advised to only use grpc-dotnet from this
point onwards.&lt;/p>
&lt;p>The Grpc.Core nuget packages will remain available in the nuget.org repository,
but no more fixes will be provided (= not even security fixes).&lt;/p>
&lt;p>&lt;strong>Future of Grpc.Tools and Grpc.Core.Api nuget packages&lt;/strong>&lt;/p>
&lt;p>Both packages will continue to be fully supported, since they are strictly
speaking not part of Grpc.Core and they are also used by grpc-dotnet.&lt;/p>
&lt;ul>
&lt;li>the Grpc.Tools nuget package which provides the codegen build integration for
C# projects will continue to be supported (and will potentially get
improvements) &amp;ndash; as it&amp;rsquo;s used by both Grpc.Core and grpc-dotnet. This package
is independent of C core.&lt;/li>
&lt;li>Grpc.Core.Api package is a prerequisite for grpc-dotnet so it will potentially
evolve over time as well (but it&amp;rsquo;s a pure C# API only package and since it
only contains the public API surface, changes are very infrequent)&lt;/li>
&lt;/ul>
&lt;h3 id="q--a">Q &amp;amp; A&lt;/h3>
&lt;p>&lt;strong>I&amp;rsquo;m a current Grpc.Core user, what does this mean for me?&lt;/strong>&lt;/p>
&lt;p>While we are going to continue supporting Grpc.Core for a while (see the
deprecation schedule for details), you&amp;rsquo;ll have to migrate your project to
grpc-dotnet if you wish to continue getting updates and bug fixes in the future.&lt;/p>
&lt;p>&lt;strong>How do I migrate my existing project to grpc-dotnet?&lt;/strong>&lt;/p>
&lt;p>Since Grpc.Core and grpc-dotnet are two distinct libraries, there are going to
be some code changes necessary in your project. Since both implementations share
the same API for invoking and handling RPCs (we&amp;rsquo;ve intentionally designed them
to be that way), we believe that the code changes necessary should be fairly
minimal. For many applications you&amp;rsquo;ll simply need to change the way you
configure your gRPC channels and servers; that is usually only a small portion
of your app&amp;rsquo;s implementation and tends to be separate from the business logic.&lt;/p>
&lt;p>For more tips on how to migrate from Grpc.Core to grpc-dotnet, see &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/grpc/migration" target="_blank" rel="noopener">Migrating
gRPC services from C-core to ASP.NET
Core&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;p>We plan to publish a more detailed migration guide in the future to facilitate
the migration from Grpc.Core to grpc-dotnet.&lt;/p>
&lt;p>&lt;strong>I&amp;rsquo;d like to use gRPC in C# for a new project. Which implementation should I choose?&lt;/strong>&lt;/p>
&lt;p>We strongly recommend only using grpc-dotnet for new projects. We are going to
stop supporting Grpc.Core in the future.&lt;/p>
&lt;p>&lt;strong>Does this mean I need to stop using Grpc.Core right now?&lt;/strong>&lt;/p>
&lt;p>No, Grpc.Core will continue to be supported for a while (see the deprecation
schedule). There should be enough time for you to assess the situation and plan
your migration.&lt;/p>
&lt;p>&lt;strong>I&amp;rsquo;m not using gRPC directly in my code, but I&amp;rsquo;m using the Google Cloud Client Libraries (which do use Grpc.Core under the hood). How does this impact me?&lt;/strong>&lt;/p>
&lt;p>This deprecation does not currently impact existing users of Google Cloud Client
Libraries.&lt;/p>
&lt;p>Since Grpc.Core is an integral part of these client libraries, security and bug
fixes for Grpc.Core will continue to be provided for Google Cloud Client
Libraries.&lt;/p>
&lt;p>The client libraries for which the extended support will be provided:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/googleapis/google-cloud-dotnet" target="_blank" rel="noopener">Google Cloud Libraries for .NET&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/googleads/google-ads-dotnet/" target="_blank" rel="noopener">Google Ads Client Library for .NET&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Note that the extended support of Grpc.Core will only be provided for Grpc.Core
when used as part of these client libraries. For other use cases than the Google
Cloud Client Libraries, Grpc.Core won&amp;rsquo;t be officially supported past the
deprecation date and users must migrate existing workloads to grpc-dotnet before
the deprecation happens.&lt;/p>
&lt;p>&lt;strong>Where can I find the list of supported features?&lt;/strong>&lt;/p>
&lt;p>Our &lt;a href="https://github.com/grpc/grpc-dotnet/blob/master/doc/implementation_comparison.md" target="_blank" rel="noopener">documentation on
github&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
has a comparison of supported features.&lt;/p>
&lt;p>&lt;strong>I have an important Grpc.Core use case that is not covered by this document.&lt;/strong>&lt;/p>
&lt;p>We welcome your feedback! Write to us through the &lt;a href="https://groups.google.com/g/grpc-io" target="_blank" rel="noopener">grpc-io&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> Google Group, or
any other of the main &lt;a href="https://grpc.io/community/">gRPC community channels&lt;/a>.&lt;/p></description></item><item><title>Blog: Analyzing gRPC messages using Wireshark</title><link>https://grpc.io/blog/wireshark/</link><pubDate>Wed, 03 Feb 2021 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/wireshark/</guid><description>
&lt;p>&lt;a href="https://www.wireshark.org" target="_blank" rel="noopener">Wireshark&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> is an open source network protocol
analyzer that can be used for protocol development, network troubleshooting, and
education. Wireshark lets you analyze gRPC messages that are transferred over
the network, and learn about the binary format of these messages.&lt;/p>
&lt;p>In this post, you&amp;rsquo;ll learn how to configure and use the Wireshark &lt;a href="https://gitlab.com/wireshark/wireshark/-/wikis/gRPC" target="_blank" rel="noopener">gRPC
dissector&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> and the &lt;a href="https://gitlab.com/wireshark/wireshark/-/wikis/Protobuf" target="_blank" rel="noopener">Protocol Buffers (Protobuf) dissector&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, which are
protocol-specific components that allow you to analyze gRPC messages with
Wireshark.&lt;/p>
&lt;h2 id="features">Features&lt;/h2>
&lt;p>The main features of the gRPC and Protobuf dissectors are the following:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Support dissecting (decoding) gRPC messages serialized in the
&lt;a href="https://developers.google.com/protocol-buffers/docs/encoding" target="_blank" rel="noopener">protocol buffer wire format&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> or as JSON&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Support dissecting gRPC messages of unary, server streaming, client streaming,
and bidirectional streaming RPC calls&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Enhanced dissection of serialized protocol buffers data by allowing
you to do the following:&lt;/p>
&lt;ul>
&lt;li>Load relevant &lt;code>.proto&lt;/code> files&lt;/li>
&lt;li>Register your own subdissectors for protocol buffer fields of type &lt;code>byte&lt;/code> or
&lt;code>string&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="capturing-grpc-traffic">Capturing gRPC traffic&lt;/h2>
&lt;p>This post focuses on the analysis of captured gRPC messages. To learn how to
store network traffic in &lt;em>capture files&lt;/em>, see &lt;a href="https://www.wireshark.org/docs/wsug_html_chunked/ChapterCapture.html" target="_blank" rel="noopener">Capturing Live Network Data&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
from the &lt;a href="https://www.wireshark.org/docs/wsug_html_chunked/" target="_blank" rel="noopener">Wireshark User’s Guide&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;div class="alert alert-info" role="alert">
&lt;h4 class="alert-heading">Note&lt;/h4>
Currently, Wireshark can only parse &lt;strong>plain text&lt;/strong> gRPC messages. While
&lt;a href="https://gitlab.com/wireshark/wireshark/-/wikis/tls" target="_blank" rel="noopener">Wireshark supports TLS dissection&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, it requires per-session secret keys. As
of the time of writing, the only &lt;a href="https://grpc.io/docs/languages/go">Go gRPC&lt;/a> supports the exporting such keys.
To learn how to export keys using Go gRPC &amp;ndash; and other languages as support
becomes available &amp;ndash; see &lt;a href="https://gitlab.com/wireshark/wireshark/-/wikis/How-to-Export-TLS-Master-keys-of-gRPC" target="_blank" rel="noopener">How to Export TLS Master keys of gRPC&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.
&lt;/div>
&lt;h2 id="example">Example&lt;/h2>
&lt;p>Let&amp;rsquo;s walk through the setup necessary to analyze previously-captured messages
that were generated by a slightly extended version of the &lt;em>address book&lt;/em> app
used in the &lt;a href="https://developers.google.com/protocol-buffers/docs/tutorials" target="_blank" rel="noopener">Protocol Buffers tutorials&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;h3 id="address-book-proto-files">Address book &lt;code>.proto&lt;/code> files&lt;/h3>
&lt;p>The app&amp;rsquo;s main protocol file is &lt;code>addressbook.proto&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-protobuf" data-lang="protobuf">&lt;span style="display:flex;">&lt;span>syntax &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#c30">&amp;#34;proto3&amp;#34;&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#069;font-weight:bold">package&lt;/span> &lt;span style="color:#0cf;font-weight:bold">tutorial&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#069;font-weight:bold">import&lt;/span> &lt;span style="color:#c30">&amp;#34;google/protobuf/timestamp.proto&amp;#34;&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#069;font-weight:bold">message&lt;/span> &lt;span style="color:#0a8;font-weight:bold">Person&lt;/span> {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#078;font-weight:bold">string&lt;/span> name &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">1&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#078;font-weight:bold">int32&lt;/span> id &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">2&lt;/span>; &lt;span style="color:#09f;font-style:italic">// Unique ID number for this person.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#078;font-weight:bold">string&lt;/span> email &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">3&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#069;font-weight:bold">enum&lt;/span> PhoneType {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> MOBILE &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">0&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> HOME &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">1&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> WORK &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">2&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> }&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#069;font-weight:bold">message&lt;/span> &lt;span style="color:#0a8;font-weight:bold">PhoneNumber&lt;/span> {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#078;font-weight:bold">string&lt;/span> number &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">1&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> PhoneType type &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">2&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> }&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#069;font-weight:bold">repeated&lt;/span> PhoneNumber phone &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">4&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> google.protobuf.Timestamp last_updated &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">5&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#078;font-weight:bold">bytes&lt;/span> portrait_image &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">6&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>}&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#069;font-weight:bold">message&lt;/span> &lt;span style="color:#0a8;font-weight:bold">AddressBook&lt;/span> {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#069;font-weight:bold">repeated&lt;/span> Person people &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">1&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>}&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This file is identical to the &lt;a href="https://github.com/protocolbuffers/protobuf/blob/master/examples/addressbook.proto" target="_blank" rel="noopener">Protocol Buffers tutorial version&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>,
except for the additional &lt;code>portrait_image&lt;/code> field.&lt;/p>
&lt;p>Note the &lt;code>import&lt;/code> statement at the top of the file, it is used to import
&lt;code>Timestamp&lt;/code>, which is one of many &lt;a href="https://developers.google.com/protocol-buffers/docs/reference/google.protobuf" target="_blank" rel="noopener">Protocol Buffers Well-Known Types&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;p>Our variant of the app also defines a &lt;em>person-search&lt;/em> service that can be used
to search for address book entries based on selected &lt;code>Person&lt;/code> attributes. The
service is defined in &lt;code>person_search_service.proto&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-protobuf" data-lang="protobuf">&lt;span style="display:flex;">&lt;span>syntax &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#c30">&amp;#34;proto3&amp;#34;&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#069;font-weight:bold">package&lt;/span> &lt;span style="color:#0cf;font-weight:bold">tutorial&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#069;font-weight:bold">import&lt;/span> &lt;span style="color:#c30">&amp;#34;addressbook.proto&amp;#34;&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#069;font-weight:bold">message&lt;/span> &lt;span style="color:#0a8;font-weight:bold">PersonSearchRequest&lt;/span> {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#069;font-weight:bold">repeated&lt;/span> &lt;span style="color:#078;font-weight:bold">string&lt;/span> name &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">1&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#069;font-weight:bold">repeated&lt;/span> &lt;span style="color:#078;font-weight:bold">int32&lt;/span> id &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">2&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#069;font-weight:bold">repeated&lt;/span> &lt;span style="color:#078;font-weight:bold">string&lt;/span> phoneNumber &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">3&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>}&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#069;font-weight:bold">service&lt;/span> PersonSearchService {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#069;font-weight:bold">rpc&lt;/span> Search (PersonSearchRequest) &lt;span style="color:#069;font-weight:bold">returns&lt;/span> (stream Person) {}&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>}&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Because the service uses the &lt;code>Person&lt;/code> type defined in &lt;code>addressbook.proto&lt;/code>,
the address book &lt;code>.proto&lt;/code> is imported at the start of the file.&lt;/p>
&lt;h3 id="setting-protobuf-search-paths">Setting protobuf search paths&lt;/h3>
&lt;p>Wireshark gives the most meaningful decodings when it knows about the &lt;code>.proto&lt;/code>
files used by the apps whose messages you are analyzing.&lt;/p>
&lt;p>You can tell Wireshark where to find &lt;code>.proto&lt;/code> files by setting the &lt;strong>Protobuf
Search Paths&lt;/strong> in the preferences accessible from the &lt;strong>Edit&lt;/strong> menu under
&lt;strong>Preferences &amp;gt; Protocols &amp;gt; Protobuf&lt;/strong>.&lt;/p>
&lt;p>If our example app&amp;rsquo;s &lt;code>.proto&lt;/code> files are in the &lt;code>d:/protos/my_proto_files&lt;/code> directory,
and the official Protobuf library directory is
&lt;code>d:/protos/protobuf-3.4.1/include&lt;/code>, then add these two paths as &lt;em>source
directories&lt;/em> like this:&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/blog/wireshark/protobuf_search_paths.png" alt="Protobuf-search-paths dialog" id="protobuf_search_paths" data-toggle="modal" data-target="#modal-protobuf_search_paths"/>
&lt;div class="modal" id="modal-protobuf_search_paths">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/blog/wireshark/protobuf_search_paths.png" alt="Protobuf-search-paths dialog"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>By selecting the &lt;strong>Load all files&lt;/strong> option for the app&amp;rsquo;s protocol directory you
enable preloading of message definitions from the &lt;code>addressbook.proto&lt;/code> and
&lt;code>person_search_service.proto&lt;/code> files.&lt;/p>
&lt;h3 id="loading-a-capture-file">Loading a capture file&lt;/h3>
&lt;p>From the Wireshark &lt;a href="https://gitlab.com/wireshark/wireshark/-/wikis/SampleCaptures" target="_blank" rel="noopener">SampleCaptures page&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, download the following sample gRPC
capture file created by running the app and issuing a search request:
&lt;a href="https://gitlab.com/wireshark/wireshark/-/wikis/uploads/f6fcdceb0248669c0b057bd15d45ab6f/grpc_person_search_protobuf_with_image.pcapng" target="_blank" rel="noopener">grpc_person_search_protobuf_with_image.pcapng&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;p>Select &lt;strong>Open&lt;/strong> from the &lt;strong>File&lt;/strong> menu to load the capture file in Wireshark.
Wireshark displays, in order, all of the network traffic from the capture file
in the &lt;strong>Packet-list pane&lt;/strong> at the top of the window.&lt;/p>
&lt;p>Select an entry from the packet-list pane and Wireshark will decode it and show
its details in the lower pane like this:&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/blog/wireshark/after_file_load.png" alt="Packet-list and packet-detail panes" id="after_file_load" data-toggle="modal" data-target="#modal-after_file_load"/>
&lt;div class="modal" id="modal-after_file_load">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/blog/wireshark/after_file_load.png" alt="Packet-list and packet-detail panes"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>Select an entry from the details pane to see the byte sequence corresponding to
that entry:&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/blog/wireshark/packet_bytes.png" alt="Packet bytes" id="packet_bytes" data-toggle="modal" data-target="#modal-packet_bytes"/>
&lt;div class="modal" id="modal-packet_bytes">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/blog/wireshark/packet_bytes.png" alt="Packet bytes"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;h3 id="setting-port-traffic-type">Setting port traffic type&lt;/h3>
&lt;p>The app&amp;rsquo;s server-side port is 50051. The client-side port, which is different
for each RPC call, is 51035 in the sample capture file.&lt;/p>
&lt;p>You need to tell Wireshark that these ports are carrying HTTP2 traffic. Do this
through the &lt;strong>Decode As&lt;/strong> dialog, which you access from the &lt;strong>Analyze&lt;/strong> menu (or
right-click on an entry from the packet-list pane). You only need to register
the server-side port:&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/blog/wireshark/decode_as_dialog.png" alt="Decode-as dialog" id="decode_as_dialog" data-toggle="modal" data-target="#modal-decode_as_dialog"/>
&lt;div class="modal" id="modal-decode_as_dialog">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/blog/wireshark/decode_as_dialog.png" alt="Decode-as dialog"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>Look at the packet-list pane and you&amp;rsquo;ll see that Wireshark is now decoding HTTP2
and gRPC messages:&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/blog/wireshark/http2_grpc.png" alt="Packets are decoded as HTTP2 and gRPC messages" id="http2_grpc" data-toggle="modal" data-target="#modal-http2_grpc"/>
&lt;div class="modal" id="modal-http2_grpc">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/blog/wireshark/http2_grpc.png" alt="Packets are decoded as HTTP2 and gRPC messages"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;h3 id="decoding-the-search-request-message">Decoding the search request message&lt;/h3>
&lt;p>Select the first gRPC message sent to port 50051, it corresponds to the sample&amp;rsquo;s
service request message. This is how Wireshark dissects the gRPC request:&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/blog/wireshark/grpc_protobuf_search_request.png" alt="Decoded search request" id="grpc_protobuf_search_request" data-toggle="modal" data-target="#modal-grpc_protobuf_search_request"/>
&lt;div class="modal" id="modal-grpc_protobuf_search_request">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/blog/wireshark/grpc_protobuf_search_request.png" alt="Decoded search request"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>By examining the HTTP2 message header &lt;code>path&lt;/code> field, you&amp;rsquo;ll see the URL to the
app&amp;rsquo;s service (&lt;code>/tutorial.PersonSearchService&lt;/code>), followed by the name of the
invoked RPC (&lt;code>Search&lt;/code>).&lt;/p>
&lt;p>The &lt;code>content-type&lt;/code>, which is set by the gRPC library, informs Wireshark that the
HTTP2 message content is a gRPC message. By examining the decoded Protocol
Buffers message of the sample gRPC request, you can see that the search request
is for the names &amp;ldquo;Jason&amp;rdquo; and &amp;ldquo;Lily&amp;rdquo;.&lt;/p>
&lt;h3 id="decoding-the-server-streamed-response">Decoding the server-streamed response&lt;/h3>
&lt;p>Since the &lt;code>Search&lt;/code> RPC response is server-streaming, &lt;code>Person&lt;/code> objects can be
returned to the client one after another.&lt;/p>
&lt;p>Select the second &lt;code>Person&lt;/code> message returned in the response stream
to see its details:&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/blog/wireshark/grpc_protobuf_search_response.png" alt="Decoded search response" id="grpc_protobuf_search_response" data-toggle="modal" data-target="#modal-grpc_protobuf_search_response"/>
&lt;div class="modal" id="modal-grpc_protobuf_search_response">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/blog/wireshark/grpc_protobuf_search_response.png" alt="Decoded search response"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>By registering subdissectors, you can have Wireshark further decode fields of
type &lt;code>byte&lt;/code> or &lt;code>string&lt;/code>. For example, to learn how to register a PNG decoder for
the &lt;code>portrait_image&lt;/code> field, see &lt;a href="https://gitlab.com/wireshark/wireshark/-/wikis/Protobuf#protobuf-field-subdissectors" target="_blank" rel="noopener">Protobuf field subdissectors&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;h2 id="history-of-grpc-and-protocol-buffers-support">History of gRPC and Protocol Buffers support&lt;/h2>
&lt;p>Here is a brief annotated list of Wireshark versions as they relate to the
support of gRPC and Protocol Buffers:&lt;/p>
&lt;ul>
&lt;li>v2.6.0: first release of gRPC and Protobuf dissectors, without
support for &lt;code>.proto&lt;/code> files or streaming RPCs.&lt;/li>
&lt;li>v3.2.0: improved dissection of serialized protocol buffers data based on
&lt;code>.proto&lt;/code> files, and support of streaming RPCs.&lt;/li>
&lt;li>v3.3.0: improved and enhanced &lt;code>.proto&lt;/code> file support, such as capture-file
search on protocol buffer field values.&lt;/li>
&lt;li>v3.4.0: Protocol Buffers &lt;a href="https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Timestamp" target="_blank" rel="noopener">Timestamp&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> time is displayed as locale date-time
string.&lt;/li>
&lt;/ul>
&lt;h2 id="learn-more">Learn more&lt;/h2>
&lt;p>Interested in learning more? Start with the &lt;a href="https://www.wireshark.org/docs/wsug_html_chunked/" target="_blank" rel="noopener">Wireshark User’s Guide&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. For more
details concerning the example used in this post, as well as other sample
capture files containing gRPC messages, see the &lt;a href="https://gitlab.com/wireshark/wireshark/-/wikis/gRPC" target="_blank" rel="noopener">gRPC dissector&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> and &lt;a href="https://gitlab.com/wireshark/wireshark/-/wikis/Protobuf" target="_blank" rel="noopener">Protocol
Buffers dissector&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> wiki pages.&lt;/p></description></item><item><title>Blog: Interceptors in gRPC-Web</title><link>https://grpc.io/blog/grpc-web-interceptor/</link><pubDate>Thu, 18 Jun 2020 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/grpc-web-interceptor/</guid><description>
&lt;p>We&amp;rsquo;re pleased to announce support for &lt;em>interceptors&lt;/em> in &lt;a href="https://github.com/grpc/grpc-web" target="_blank" rel="noopener">gRPC-web&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> as of
release &lt;a href="https://github.com/grpc/grpc-web/releases/tag/1.1.0" target="_blank" rel="noopener">1.1.0&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. While the current design is based on gRPC client interceptors
available from other &lt;a href="https://grpc.io/docs/languages/">gRPC languages&lt;/a>, it also includes gRPC-web specific
features that should make interceptors easy to adopt and use alongside modern
web frameworks.&lt;/p>
&lt;h2 id="introduction">Introduction&lt;/h2>
&lt;p>Similar to other gRPC languages, gRPC-web supports &lt;em>unary&lt;/em> and
server-&lt;em>streaming&lt;/em> interceptors. For each kind of interceptor, we&amp;rsquo;ve &lt;a href="https://github.com/grpc/grpc-web/blob/master/javascript/net/grpc/web/interceptor.js" target="_blank" rel="noopener">defined an
interface&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> containing a single &lt;code>intercept()&lt;/code> method:&lt;/p>
&lt;ul>
&lt;li>&lt;code>UnaryInterceptor&lt;/code>&lt;/li>
&lt;li>&lt;code>StreamInterceptor&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>This is how the &lt;code>UnaryInterceptor&lt;/code> interface is declared:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">/*
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">* @interface
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">*/&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">const&lt;/span> UnaryInterceptor &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">function&lt;/span>() {};
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"> * @template REQUEST, RESPONSE
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"> * @param {!Request&amp;lt;REQUEST, RESPONSE&amp;gt;} request
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"> * @param {function(!Request&amp;lt;REQUEST,RESPONSE&amp;gt;):!Promise&amp;lt;!UnaryResponse&amp;lt;RESPONSE&amp;gt;&amp;gt;}
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"> * invoker
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"> * @return {!Promise&amp;lt;!UnaryResponse&amp;lt;RESPONSE&amp;gt;&amp;gt;}
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>UnaryInterceptor.prototype.intercept &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">function&lt;/span>(request, invoker) {};
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The &lt;code>intercept()&lt;/code> method takes two parameters:&lt;/p>
&lt;ul>
&lt;li>A &lt;code>request&lt;/code> of type &lt;a href="https://github.com/grpc/grpc-web/blob/master/javascript/net/grpc/web/request.js" target="_blank" rel="noopener">grpc.web.Request&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>An &lt;code>invoker&lt;/code>, which performs the actual RPC when invoked&lt;/li>
&lt;/ul>
&lt;p>The &lt;code>StreamInterceptor&lt;/code> interface declaration is similar, except that the
&lt;code>invoker&lt;/code> return type is &lt;code>ClientReadableStream&lt;/code> instead of &lt;code>Promise&lt;/code>. For
implementation details, see &lt;a href="https://github.com/grpc/grpc-web/blob/master/javascript/net/grpc/web/interceptor.js" target="_blank" rel="noopener">interceptor.js&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;div class="alert alert-info" role="alert">
&lt;h4 class="alert-heading">Note&lt;/h4>
A &lt;code>StreamInterceptor&lt;/code> can be applied to any RPC with a &lt;code>ClientReadableStream&lt;/code>
return type, whether it&amp;rsquo;s a unary or a server-streaming RPC.
&lt;/div>
&lt;h2 id="what-can-i-do-with-an-interceptor">What can I do with an interceptor?&lt;/h2>
&lt;p>An interceptor allows you to do the following:&lt;/p>
&lt;ul>
&lt;li>Update the original gRPC request before passing it along — for
example, you might inject extra information such as auth headers&lt;/li>
&lt;li>Manipulate the behavior of the original invoker function, such as bypassing
the call so that you can use a cached result instead&lt;/li>
&lt;li>Update the response before it&amp;rsquo;s returned to the client&lt;/li>
&lt;/ul>
&lt;p>You&amp;rsquo;ll see some examples next.&lt;/p>
&lt;h2 id="unary-interceptor-example">Unary interceptor example&lt;/h2>
&lt;p>The code given below illustrates a unary interceptor that does the following:&lt;/p>
&lt;ul>
&lt;li>It prepends a string to the gRPC request message before the RPC.&lt;/li>
&lt;li>It prepends a string to the gRPC response message after it&amp;rsquo;s received.&lt;/li>
&lt;/ul>
&lt;p>This simple unary interceptor is defined as a class that implements the
&lt;code>UnaryInterceptor&lt;/code> interface:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"> * @constructor
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"> * @implements {UnaryInterceptor}
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">const&lt;/span> SimpleUnaryInterceptor &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">function&lt;/span>() {};
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">/** @override */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>SimpleUnaryInterceptor.prototype.intercept &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">function&lt;/span>(request, invoker) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// Update the request message before the RPC.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#069;font-weight:bold">const&lt;/span> reqMsg &lt;span style="color:#555">=&lt;/span> request.getRequestMessage();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> reqMsg.setMessage(&lt;span style="color:#c30">&amp;#39;[Intercept request]&amp;#39;&lt;/span> &lt;span style="color:#555">+&lt;/span> reqMsg.getMessage());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// After the RPC returns successfully, update the response.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#069;font-weight:bold">return&lt;/span> invoker(request).then((response) =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// You can also do something with response metadata here.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> console.log(response.getMetadata());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// Update the response message.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#069;font-weight:bold">const&lt;/span> responseMsg &lt;span style="color:#555">=&lt;/span> response.getResponseMessage();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> responseMsg.setMessage(&lt;span style="color:#c30">&amp;#39;[Intercept response]&amp;#39;&lt;/span> &lt;span style="color:#555">+&lt;/span> responseMsg.getMessage());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">return&lt;/span> response;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> });
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>};
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="stream-interceptor-example">Stream interceptor example&lt;/h2>
&lt;p>More care is needed to intercept server-streamed responses from a
&lt;code>ClientReadableStream&lt;/code> using a &lt;code>StreamInterceptor&lt;/code>. These are the main steps to
follow:&lt;/p>
&lt;ol>
&lt;li>Create a &lt;code>ClientReadableStream&lt;/code>-wrapper class, and use it to intercept
stream events such as the reception of server responses.&lt;/li>
&lt;li>Create a class that implements &lt;code>StreamInterceptor&lt;/code> and that uses the stream
wrapper.&lt;/li>
&lt;/ol>
&lt;p>The following sample stream-wrapper class intercepts responses and prepends a
string to response messages:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"> * A ClientReadableStream wrapper.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"> * @template RESPONSE
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"> * @implements {ClientReadableStream}
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"> * @constructor
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"> * @param {!ClientReadableStream&amp;lt;RESPONSE&amp;gt;} stream
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">const&lt;/span> InterceptedStream &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">function&lt;/span>(stream) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">this&lt;/span>.stream &lt;span style="color:#555">=&lt;/span> stream;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>};
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">/** @override */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>InterceptedStream.prototype.on &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">function&lt;/span>(eventType, callback) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">if&lt;/span> (eventType &lt;span style="color:#555">==&lt;/span> &lt;span style="color:#c30">&amp;#39;data&amp;#39;&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">const&lt;/span> newCallback &lt;span style="color:#555">=&lt;/span> (response) =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// Update the response message.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#069;font-weight:bold">const&lt;/span> msg &lt;span style="color:#555">=&lt;/span> response.getMessage();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> response.setMessage(&lt;span style="color:#c30">&amp;#39;[Intercept response]&amp;#39;&lt;/span> &lt;span style="color:#555">+&lt;/span> msg);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// Pass along the updated response.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> callback(response);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> };
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// Register the new callback.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#069;font-weight:bold">this&lt;/span>.stream.on(eventType, newCallback);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#069;font-weight:bold">else&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// You can also override &amp;#39;status&amp;#39;, &amp;#39;end&amp;#39;, and &amp;#39;error&amp;#39; eventTypes.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#069;font-weight:bold">this&lt;/span>.stream.on(eventType, callback);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">return&lt;/span> &lt;span style="color:#069;font-weight:bold">this&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>};
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">/** @override */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>InterceptedStream.prototype.cancel &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">function&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">this&lt;/span>.stream.cancel();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">return&lt;/span> &lt;span style="color:#069;font-weight:bold">this&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>};
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The &lt;code>intercept()&lt;/code> method of the sample interceptor returns a wrapped stream:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"> * @constructor
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"> * @implements {StreamInterceptor}
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">const&lt;/span> TestStreamInterceptor &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">function&lt;/span>() {};
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">/** @override */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>TestStreamInterceptor.prototype.intercept &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">function&lt;/span>(request, invoker) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">return&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> InterceptedStream(invoker(request));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>};
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="binding-interceptors">Binding interceptors&lt;/h2>
&lt;p>By passing an array of interceptor instances using an appropriate option key,
you can bind interceptors to a client when the client is instantiated:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">const&lt;/span> promiseClient &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> MyServicePromiseClient(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> host, creds, {&lt;span style="color:#c30">&amp;#39;unaryInterceptors&amp;#39;&lt;/span>&lt;span style="color:#555">:&lt;/span> [interceptor1, interceptor2, interceptor3]});
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">const&lt;/span> client &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> MyServiceClient(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> host, creds, {&lt;span style="color:#c30">&amp;#39;streamInterceptors&amp;#39;&lt;/span>&lt;span style="color:#555">:&lt;/span> [interceptor1, interceptor2, interceptor3]});
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;div class="alert alert-info" role="alert">
&lt;h4 class="alert-heading">Note&lt;/h4>
Interceptors are executed in reverse order for request processing, and in
order for response processing, as illustrated here:
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/grpc-web-interceptors.png" alt="Interceptor processing order" id="grpc-web-interceptors" data-toggle="modal" data-target="#modal-grpc-web-interceptors"/>
&lt;div class="modal" id="modal-grpc-web-interceptors">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/grpc-web-interceptors.png" alt="Interceptor processing order"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/div>
&lt;h2 id="feedback">Feedback&lt;/h2>
&lt;p>Found a problem with &lt;code>grpc-web&lt;/code> or need a feature? File an &lt;a href="https://github.com/grpc/grpc-web/issues/new" target="_blank" rel="noopener">issue&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> over the
&lt;a href="https://github.com/grpc/grpc-web" target="_blank" rel="noopener">grpc-web&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> repository. If you have general questions or comments, then
consider posting to the &lt;a href="https://groups.google.com/g/grpc-io" target="_blank" rel="noopener">gRPC mailing list&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> or sending us an email at
&lt;a href="mailto:grpc-web-team@google.com">grpc-web-team@google.com&lt;/a>.&lt;/p></description></item><item><title>Blog: Announcing gRPC-JS 1.0</title><link>https://grpc.io/blog/grpc-js-1.0/</link><pubDate>Mon, 20 Apr 2020 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/grpc-js-1.0/</guid><description>
&lt;p>We are excited to announce the release of version 1.0 of &lt;a href="https://www.npmjs.com/package/@grpc/grpc-js" target="_blank" rel="noopener">&lt;strong>gRPC-JS&lt;/strong>
(@grpc/grpc-js)&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, a pure-TypeScript reimplementation of the original
&lt;a href="https://www.npmjs.com/package/grpc" target="_blank" rel="noopener">Node gRPC library, grpc&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;h2 id="features">Features&lt;/h2>
&lt;p>gRPC-JS supports the following features, which should cover most use cases:&lt;/p>
&lt;ul>
&lt;li>Clients&lt;/li>
&lt;li>Automatic reconnection&lt;/li>
&lt;li>Servers&lt;/li>
&lt;li>Streaming&lt;/li>
&lt;li>Metadata&lt;/li>
&lt;li>Partial compression support: clients can decompress response messages&lt;/li>
&lt;li>Pick first and round robin load balancing policies&lt;/li>
&lt;li>Client Interceptors&lt;/li>
&lt;li>Connection Keepalives&lt;/li>
&lt;li>HTTP Connect support (proxies)&lt;/li>
&lt;/ul>
&lt;h2 id="should-i-use-grpcgrpc-js-or-grpc">Should I use @grpc/grpc-js or grpc?&lt;/h2>
&lt;p>The original Node gRPC library (&lt;a href="https://www.npmjs.com/package/grpc" target="_blank" rel="noopener">grpc&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>) will no longer receive feature
updates and we plan to deprecate it in a year,
so we recommend that you use gRPC-JS, &lt;a href="https://www.npmjs.com/package/@grpc/grpc-js" target="_blank" rel="noopener">@grpc/grpc-js&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;p>However, some advanced features haven&amp;rsquo;t been ported to gRPC-JS yet, such as full
compression support or support for other load balancing policies. If you need
one of these features, you should use the &lt;a href="https://www.npmjs.com/package/grpc" target="_blank" rel="noopener">grpc&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> library, but open a &lt;a href="https://github.com/grpc/grpc-node/issues/new?template=feature_request.md" target="_blank" rel="noopener">feature
request&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> over gRPC-JS to let us know which features you are missing the most.&lt;/p></description></item><item><title>Blog: Kotlin, meet gRPC</title><link>https://grpc.io/blog/kotlin-meet-grpc/</link><pubDate>Thu, 16 Apr 2020 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/kotlin-meet-grpc/</guid><description>
&lt;p>As developers work to modernize applications, they need foundational tools that
are simple and scalable. gRPC is a high-performance, open-source, universal RPC
framework originally developed at Google that developers are adopting in
tremendous numbers, helping them connect services more easily and reliably.
Paired with &lt;a href="https://kotlinlang.org" target="_blank" rel="noopener">Kotlin&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, the second most popular JVM-based programming language
in the world, developers can build everything from mobile apps to cloud
microservices. To help, we&amp;rsquo;ve open-sourced &lt;a href="https://github.com/grpc/grpc-kotlin" target="_blank" rel="noopener">gRPC Kotlin&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> for the JVM, allowing
you to use gRPC with your Kotlin projects.&lt;/p>
&lt;p>For the full announcement, including how to deploy gRPC Kotlin services on
&lt;a href="https://cloud.run" target="_blank" rel="noopener">Cloud Run&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, see the Google Cloud blog, &lt;a href="https://cloud.google.com/blog/products/application-development/use-grpc-with-kotlin" target="_blank" rel="noopener">Kotlin, meet gRPC: a new open-source
project for modern apps&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;p>For more information, see the following &lt;a href="https://grpc.io/docs/languages/kotlin/">Kotlin pages&lt;/a>:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://grpc.io/docs/languages/kotlin/quickstart/">Quick start&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://grpc.io/docs/languages/kotlin/basics/">Basics tutorial&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://grpc.io/docs/languages/kotlin/api/" target="_blank" rel="noopener">API reference&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Blog: gRPC comes to Cloud Run</title><link>https://grpc.io/blog/grpc-cloud-run/</link><pubDate>Tue, 17 Mar 2020 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/grpc-cloud-run/</guid><description>
&lt;p>&lt;a href="https://cloud.google.com/run" target="_blank" rel="noopener">Cloud Run&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> is a serverless platform offered by Google Cloud that lets you run
stateless server containers in a fully managed environment. Most Cloud Run apps
use HTTP JSON REST to serve requests, but since September 2019, apps can also
use unary gRPC services!&lt;/p>
&lt;p>Get all the details from &lt;a href="https://cloud.google.com/blog/products/compute/serve-cloud-run-requests-with-grpc-not-just-http" target="_blank" rel="noopener">Not just for HTTP anymore: gRPC comes to Cloud Run&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p></description></item><item><title>Blog: Improvements to gRPC's CMake Build System</title><link>https://grpc.io/blog/cmake-improvements/</link><pubDate>Mon, 16 Mar 2020 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/cmake-improvements/</guid><description>
&lt;p>For the past few months, &lt;a href="https://www.kitware.com/" target="_blank" rel="noopener">Kitware Inc.&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> has been working with the gRPC team to improve gRPC’s CMake support. The goal of the effort was to modernize gRPC’s CMake build with the most current features and techniques CMake has to offer. This has improved the user experience for gRPC developers choosing to use gRPC’s CMake as a build system. During the effort the CMake build was looked at as a whole, and CMake related issues in GitHub were explored and resolved. A number of improvements were made that will give developers and end users a better experience when building gRPC with CMake.&lt;/p>
&lt;p>One of the more exciting changes is the ability to seamlessly add gRPC to any CMake project and have all of its dependent libraries built using a simple CMake file. Prior to our recent changes this was a multi-step process. The user had to build and install each of gRPC’s dependencies separately, then build and install gRPC before finally building their own project. Now, this can all be done in one step. The following CMake code clones and builds the latest stable release of gRPC as documented &lt;a href="https://github.com/grpc/grpc/blob/master/src/cpp/README.md#cmake" target="_blank" rel="noopener">here&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cmake" data-lang="cmake">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#366">cmake_minimum_required&lt;/span>(&lt;span style="color:#c30">VERSION&lt;/span> &lt;span style="color:#c30">3.15&lt;/span>)&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#366">project&lt;/span>(&lt;span style="color:#c30">my_exe&lt;/span>)&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#366">include&lt;/span>(&lt;span style="color:#c30">FetchContent&lt;/span>)&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#366">FetchContent_Declare&lt;/span>(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c30">gRPC&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c30">GIT_REPOSITORY&lt;/span> &lt;span style="color:#c30">https://github.com/grpc/grpc&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c30">GIT_TAG&lt;/span> &lt;span style="color:#c30">v1.28.0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> )&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#366">set&lt;/span>(&lt;span style="color:#c30">FETCHCONTENT_QUIET&lt;/span> &lt;span style="color:#c30">OFF&lt;/span>)&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#366">FetchContent_MakeAvailable&lt;/span>(&lt;span style="color:#c30">gRPC&lt;/span>)&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#366">add_executable&lt;/span>(&lt;span style="color:#c30">my_exe&lt;/span> &lt;span style="color:#c30">my_exe.cc&lt;/span>)&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#366">target_link_libraries&lt;/span>(&lt;span style="color:#c30">my_exe&lt;/span> &lt;span style="color:#c30">grpc++&lt;/span>)&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>At configure time CMake uses git to clone the gRPC repository using the specified tag. Then gRPC will be added to the current CMake project via &lt;a href="https://cmake.org/cmake/help/latest/command/add_subdirectory.html" target="_blank" rel="noopener">add_subdirectory&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> and built as part of the project.&lt;/p>
&lt;h2 id="what-has-changed">What has changed?&lt;/h2>
&lt;p>We have addressed many of the CMake-related issues on GitHub, with bug fixes, documentation updates, and new features. All the fixes and features are available starting from gRPC 1.28.0 release.&lt;/p>
&lt;ul>
&lt;li>We’ve improved the documentation for &lt;a href="https://github.com/grpc/grpc/blob/master/BUILDING.md" target="_blank" rel="noopener">building gRPC from source&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> and &lt;a href="https://github.com/grpc/grpc/blob/master/src/cpp/README.md#cmake" target="_blank" rel="noopener">adding gRPC as a dependency to your CMake project&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> giving developers several options for using gRPC from CMake from simply linking to a pre-built gRPC to downloading and building gRPC as part of the project.&lt;/li>
&lt;li>The CMake build now generates pkgconfig (*.pc) files in the installation directory, just like the Makefile build. This allows for pkgconfig to correctly find and report a CMake built version of gRPC.&lt;/li>
&lt;li>If you are using CMake v3.13 or newer, you can now &lt;a href="https://github.com/grpc/grpc/blob/master/BUILDING.md#install-after-build" target="_blank" rel="noopener">build &amp;amp; install gRPC and its dependencies in a single step&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, rather than building and installing each component separately.&lt;/li>
&lt;li>The CMake build now has configuration options to enable or disable building of every protoc plugin. For example, running CMake with &lt;code>-DgRPC_BUILD_GRPC_PYTHON_PLUGIN=OFF&lt;/code> will disable building the Python plugin. You can view and edit these options in cmake-gui (or ccmake) as you are configuring your build of gRPC.&lt;/li>
&lt;li>When building and installing gRPC as shared libraries, CMake now sets the .so version so the libraries are correctly versioned. (for example, libgrpc.so.9.0.0, libgrpc++.so.1.27.0-dev, etc).&lt;/li>
&lt;li>We’ve added examples showing how to &lt;a href="https://github.com/grpc/grpc/blob/master/test/distrib/cpp/run_distrib_test_cmake_fetchcontent.sh" target="_blank" rel="noopener">build gRPC using the CMake FetchContent module&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, and how to &lt;a href="https://github.com/grpc/grpc/blob/master/test/distrib/cpp/run_distrib_test_raspberry_pi.sh" target="_blank" rel="noopener">cross-compile gRPC for the Raspberry Pi&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/li>
&lt;li>CMake can now find libc-ares even if c-ares has been built with Autotools instead of CMake. This allows gRPC to be built against the distribution-provided version of c-ares if it has been built with Autotools.&lt;/li>
&lt;li>If gRPC is built without testing enabled, the dependent testing frameworks will automatically be disabled, in order to avoid unnecessary compilation.&lt;/li>
&lt;li>Some issues with parallel builds have been addressed.&lt;/li>
&lt;/ul>
&lt;p>As a bonus, there is one extra change that wasn&amp;rsquo;t technically part of this effort, but also contributes to simpler and easier cmake build:&lt;/p>
&lt;ul>
&lt;li>To build the boringssl dependency, a much more &lt;a href="https://github.com/grpc/grpc/pull/21527" target="_blank" rel="noopener">lightweight cmake build is now used&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, which eliminates some odd build-time dependencies (e.g. &lt;code>golang&lt;/code>).&lt;/li>
&lt;/ul></description></item><item><title>Blog: .NET Core ❤ gRPC</title><link>https://grpc.io/blog/grpc-on-dotnetcore/</link><pubDate>Mon, 23 Sep 2019 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/grpc-on-dotnetcore/</guid><description>
&lt;p>The .NET team at Microsoft has been working in close collaboration with the gRPC team since November 2018 on a new fully managed implementation of gRPC for .NET Core.&lt;/p>
&lt;p>We&amp;rsquo;re pleased to announce that &lt;strong>grpc-dotnet&lt;/strong> is now available with .NET Core 3.0 today!&lt;/p>
&lt;h2 id="how-to-get-it">How to get it?&lt;/h2>
&lt;p>&lt;strong>grpc-dotnet&lt;/strong> packages have just been released to &lt;a href="https://www.nuget.org/profiles/grpc-packages" target="_blank" rel="noopener">NuGet.org&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> and are already available for use in your projects. These packages also require the latest .NET Core 3.0 shared framework. You can download the .NET Core 3.0 SDK for your dev machine and build servers from the &lt;a href="https://aka.ms/netcore3download" target="_blank" rel="noopener">.NET Core 3.0 download page&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> to acquire the shared framework.&lt;/p>
&lt;h2 id="getting-started">Getting Started&lt;/h2>
&lt;p>As gRPC is now a first-class citizen in .NET ecosystem, gRPC templates are included as part of the .NET SDK. To get started, navigate to a console window after installing the SDK and run the following commands.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>dotnet new grpc -o GrpcGreeter
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#366">cd&lt;/span> GrpcGreeter
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>dotnet run
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>To create a gRPC client and test with the newly created gRPC Greeter service, you can &lt;a href="https://docs.microsoft.com/aspnet/core/tutorials/grpc/grpc-start" target="_blank" rel="noopener">follow the rest of this tutorial here&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;h2 id="doesnt-grpc-already-work-with-net-core">Doesn&amp;rsquo;t gRPC already work with .NET Core?&lt;/h2>
&lt;p>There are currently two official implementations of gRPC for .NET:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/grpc/grpc/tree/master/src/csharp" target="_blank" rel="noopener">&lt;strong>Grpc.Core&lt;/strong>&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>: The original gRPC C# implementation based on the native gRPC Core library.&lt;/li>
&lt;li>&lt;a href="https://github.com/grpc/grpc-dotnet" target="_blank" rel="noopener">&lt;strong>grpc-dotnet&lt;/strong>&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>: The new implementation written entirely in C# with no native dependencies and based on the newly released .NET Core 3.0.&lt;/li>
&lt;/ul>
&lt;p>The implementations coexist side-by-side and each has its own advantages in terms of available features, integrations, supported platforms, maturity level and performance. Both implementations share the same API for invoking and handling RPCs, thus limiting the lock-in and enabling users to choose the implementation that satisfies their needs the best.&lt;/p>
&lt;h2 id="whats-new">What&amp;rsquo;s new?&lt;/h2>
&lt;p>Unlike the existing C-Core based implementation (&lt;a href="https://github.com/grpc/grpc/tree/master/src/csharp" target="_blank" rel="noopener">Grpc.Core&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>), the new libraries (&lt;a href="https://github.com/grpc/grpc-dotnet" target="_blank" rel="noopener">grpc-dotnet&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>) make use of the existing networking primitives in the .NET Core Base Class Libraries (BCL). The diagram below highlights the difference between the existing &lt;strong>Grpc.Core&lt;/strong> library and the new &lt;strong>grpc-dotnet&lt;/strong> libraries.&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/grpc-dotnet.svg" alt="gRPC .NET Stack" id="grpc-dotnet.svg" data-toggle="modal" data-target="#modal-grpc-dotnet.svg"/>
&lt;div class="modal" id="modal-grpc-dotnet.svg">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/grpc-dotnet.svg" alt="gRPC .NET Stack"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>On the server side, the &lt;code>Grpc.AspNetCore.Server&lt;/code> package integrates into ASP.NET Core, allowing developers to benefit from ecosystem of common cross-cutting concerns of logging, configuration, dependency injection, authentication, authorization etc. which have already been solved by ASP.NET Core. Popular libraries in the ASP.NET ecosystem such as &lt;a href="https://github.com/aspnet/EntityFrameworkCore" target="_blank" rel="noopener">Entity Framework Core (ORM)&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, &lt;a href="https://github.com/serilog/serilog" target="_blank" rel="noopener">Serilog (Logging library)&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, and &lt;a href="https://github.com/IdentityServer/IdentityServer4" target="_blank" rel="noopener">Identity Server&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> among others now work seamlessly with gRPC.&lt;/p>
&lt;p>On the client side, the &lt;code>Grpc.Net.Client&lt;/code> package builds upon the familiar &lt;code>HttpClient&lt;/code> API that ships as part of .NET Core. As with the server, gRPC clients greatly benefit from the ecosystem of packages that build upon &lt;code>HttpClient&lt;/code>. It is now possible to use existing packages such as &lt;a href="https://github.com/App-vNext/Polly" target="_blank" rel="noopener">&lt;strong>Polly&lt;/strong>(Resilience and fault-handling library)&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> and &lt;a href="https://docs.microsoft.com/aspnet/core/fundamentals/http-requests" target="_blank" rel="noopener">HttpClientFactory(manage HTTPClient lifetimes)&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> with gRPC clients.&lt;/p>
&lt;p>The diagram below captures the exhaustive list of all new .NET packages for gRPC and their relationship with the existing packages.&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/grpc-dotnet-packages.svg" alt="grpc-dotnet packages" id="grpc-dotnet-packages.svg" data-toggle="modal" data-target="#modal-grpc-dotnet-packages.svg"/>
&lt;div class="modal" id="modal-grpc-dotnet-packages.svg">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/grpc-dotnet-packages.svg" alt="grpc-dotnet packages"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>In addition to the newly published packages that ship as part of &lt;strong>grpc-dotnet&lt;/strong>, we&amp;rsquo;ve also made improvements that benefit both stacks. Visual Studio 2019 ships with language grammar support for protobuf files and automatic generation of gRPC server/client code upon saving a protobuf file without requiring full project rebuilds due to design-time builds.&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/grpc-visualstudio.png" alt="gRPC in Visual Studio 2019" id="grpc-visualstudio" data-toggle="modal" data-target="#modal-grpc-visualstudio"/>
&lt;div class="modal" id="modal-grpc-visualstudio">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/grpc-visualstudio.png" alt="gRPC in Visual Studio 2019"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;h2 id="feedback">Feedback&lt;/h2>
&lt;p>We&amp;rsquo;re excited about improving the gRPC experience for .NET developers. Give it a try and let us know about feature ideas or bugs you may encounter using the &lt;a href="https://github.com/grpc/grpc-dotnet/issues" target="_blank" rel="noopener">grpc-dotnet issue tracker&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p></description></item><item><title>Blog: Dear gRPC</title><link>https://grpc.io/blog/hello-pancakes/</link><pubDate>Fri, 08 Mar 2019 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/hello-pancakes/</guid><description>
&lt;p>Dear gRPC,&lt;/p>
&lt;p>We messed up. We are so sorry that we missed your birthday this year. Last year we celebrated &lt;a href="https://twitter.com/grpcio/status/968618209803931648" target="_blank" rel="noopener">with cake&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> and fanfare, but this year we dropped the ball. Please don&amp;rsquo;t think that we love you any less.&lt;/p>
&lt;p>You&amp;rsquo;re 4 now and that&amp;rsquo;s a big milestone! You&amp;rsquo;re part of so much amazing technology at companies like Salesforce, Netflix, Spotify, Fanatics, and of course, Google. In fact just this week the &lt;a href="https://ads-developers.googleblog.com/2019/03/upgrade-to-new-google-ads-api-to-get.html" target="_blank" rel="noopener">biggest API Google has&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> went production-ready with gRPC.&lt;/p>
&lt;p>We&amp;rsquo;re proud of you, gRPC, and we&amp;rsquo;re going to make this up to you. For starters - we got you a puppy! He&amp;rsquo;s an adorable &lt;strong>G&lt;/strong>olden &lt;strong>R&lt;/strong>etriever and his name is &lt;strong>P&lt;/strong>an&lt;strong>C&lt;/strong>akes. He loves to run back and forth with toys, packets, or messages. He&amp;rsquo;s super active and no matter how much we train him, we just can&amp;rsquo;t get him to REST. PanCakes is going to be your best friend, and ambassador.&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://raw.githubusercontent.com/grpc/grpc-community/main/PanCakes/Pancakes_Birthday.png" alt="gRPC Mascot PanCakes" id="Pancakes_Birthday" data-toggle="modal" data-target="#modal-Pancakes_Birthday"/>
&lt;div class="modal" id="modal-Pancakes_Birthday">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://raw.githubusercontent.com/grpc/grpc-community/main/PanCakes/Pancakes_Birthday.png" alt="gRPC Mascot PanCakes"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>Even though it&amp;rsquo;s a bit late, we still want to throw you a party, gRPC. Our friends at CNCF have planned a &lt;a href="https://events.linuxfoundation.org/events/grpconf-2019/" target="_blank" rel="noopener">big event&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> for you on March 21, and there&amp;rsquo;s going to be lots of people there! They&amp;rsquo;ll be sharing stories about the cool things they&amp;rsquo;ve built, and meeting new people. It&amp;rsquo;s an entire day all about you, and everyone there is going to learn so much. There will be other puppies who can play with PanCakes! Some of the amazing dogs from &lt;a href="http://www.cci.org/" target="_blank" rel="noopener">Canine Companions for Independence&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> will be there to greet conference attendees and share how they help their humans live a more independent life.&lt;/p>
&lt;p>We are so excited to see what this year holds for you, gRPC!&lt;/p>
&lt;p>~ gRPC Maintainers&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://raw.githubusercontent.com/grpc/grpc-community/main/PanCakes/Pancakes_Birthday_4.png" alt="gRPC Mascot PanCakes" id="Pancakes_Birthday_4" data-toggle="modal" data-target="#modal-Pancakes_Birthday_4"/>
&lt;div class="modal" id="modal-Pancakes_Birthday_4">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://raw.githubusercontent.com/grpc/grpc-community/main/PanCakes/Pancakes_Birthday_4.png" alt="gRPC Mascot PanCakes"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p></description></item><item><title>Blog: The state of gRPC in the browser</title><link>https://grpc.io/blog/state-of-grpc-web/</link><pubDate>Tue, 08 Jan 2019 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/state-of-grpc-web/</guid><description>
&lt;p>gRPC 1.0 was released in August 2016 and has since grown to become one of the
premier technical solutions for application communications. It has been adopted
by startups, enterprise companies, and open source projects worldwide.
Its support for polyglot environments, focus on performance, type safety, and
developer productivity has transformed the way developers design their
architectures.&lt;/p>
&lt;p>So far the benefits have largely only been available to mobile
app and backend developers, whilst frontend developers have had to continue to
rely on JSON REST interfaces as their primary means of information exchange.
However, with the release of gRPC-Web, gRPC is poised to become a valuable
addition in the toolbox of frontend developers.&lt;/p>
&lt;p>In this post, I&amp;rsquo;ll describe some of the history of gRPC in the browser, explore
the state of the world today, and share some thoughts on the future.&lt;/p>
&lt;h1 id="beginnings">Beginnings&lt;/h1>
&lt;p>In the summer of 2016, both a team at Google and
Improbable&lt;sup id="a1">&lt;a href="#f1">1&lt;/a>&lt;/sup> independently started working on
implementing something that could be called &amp;ldquo;gRPC for the browser&amp;rdquo;. They soon
discovered each other&amp;rsquo;s existence and got together to define a
spec&lt;sup id="a2">&lt;a href="#f2">2&lt;/a>&lt;/sup> for the new protocol.&lt;/p>
&lt;h2 id="the-grpc-web-spec">The gRPC-Web Spec&lt;/h2>
&lt;p>It is currently impossible to implement the HTTP/2 gRPC
spec&lt;sup id="a3">&lt;a href="#f3">3&lt;/a>&lt;/sup> in the browser, as there is simply no browser
API with enough fine-grained control over the requests. For example: there is
no way to force the use of HTTP/2, and even if there was, raw HTTP/2 frames are
inaccessible in browsers. The gRPC-Web spec starts from the point of view of the
HTTP/2 spec, and then defines the differences. These notably include:&lt;/p>
&lt;ul>
&lt;li>Supporting both HTTP/1.1 and HTTP/2.&lt;/li>
&lt;li>Sending of gRPC trailers at the very end of request/response bodies as
indicated by a new bit in the gRPC message header&lt;sup id="a4">&lt;a href="#f4">4&lt;/a>&lt;/sup>.&lt;/li>
&lt;li>A mandatory proxy for translating between gRPC-Web requests and gRPC HTTP/2
responses.&lt;/li>
&lt;/ul>
&lt;h2 id="the-tech">The Tech&lt;/h2>
&lt;p>The basic idea is to have the browser send normal HTTP requests (with Fetch or
XHR) and have a small proxy in front of the gRPC server to translate the
requests and responses to something the browser can use.&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/grpc-web-proxy.png" alt="The role of the gRPC-Web proxy" id="grpc-web-proxy" data-toggle="modal" data-target="#modal-grpc-web-proxy"/>
&lt;div class="modal" id="modal-grpc-web-proxy">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/grpc-web-proxy.png" alt="The role of the gRPC-Web proxy"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;h1 id="the-two-implementations">The Two Implementations&lt;/h1>
&lt;p>The teams at Google and Improbable both went on to implement the spec in two
different repositories&lt;sup id="a5">&lt;a href="#f5">5&lt;/a>,&lt;/sup>&lt;sup id="a6">&lt;a href="#f6">6&lt;/a>&lt;/sup>,
and with slightly different implementations, such that neither entirely
conformed to the spec, and for a long time neither was compatible with the
other&amp;rsquo;s proxy&lt;sup id="a7">&lt;a href="#f7">7&lt;/a>,&lt;/sup>&lt;sup id="a8">&lt;a href="#f8">8&lt;/a>&lt;/sup>.&lt;/p>
&lt;p>The Improbable gRPC-Web client&lt;sup id="a9">&lt;a href="#f9">9&lt;/a>&lt;/sup> is implemented in
TypeScript and available on npm as &lt;code>@improbable-eng/grpc-web&lt;/code>&lt;sup id="a10">&lt;a href="#f10">10&lt;/a>&lt;/sup>.
There is also a Go proxy available, both as a package that can be imported into
existing Go gRPC servers&lt;sup id="a11">&lt;a href="#f11">11&lt;/a>&lt;/sup>, and as a standalone
proxy that can be used to expose an arbitrary gRPC server to a gRPC-Web
frontend&lt;sup id="a12">&lt;a href="#f12">12&lt;/a>&lt;/sup>.&lt;/p>
&lt;p>The Google gRPC-Web client&lt;sup id="a13">&lt;a href="#f13">13&lt;/a>&lt;/sup> is implemented in
JavaScript using the Google Closure library&lt;sup id="a14">&lt;a href="#f14">14&lt;/a>&lt;/sup> base.
It is available on npm as &lt;code>grpc-web&lt;/code>&lt;sup id="a15">&lt;a href="#f15">15&lt;/a>&lt;/sup>. It originally
shipped with a proxy implemented as an NGINX
extension&lt;sup id="a16">&lt;a href="#f16">16&lt;/a>&lt;/sup>, but has since doubled down on an Envoy
proxy HTTP filter&lt;sup id="a17">&lt;a href="#f17">17&lt;/a>&lt;/sup>, which is available in all
versions since v1.4.0.&lt;/p>
&lt;h2 id="feature-sets">Feature Sets&lt;/h2>
&lt;p>The gRPC HTTP/2 implementations all support the four method types: unary,
server-side, client-side, and bi-directional streaming. However, the gRPC-Web
spec does not mandate any client-side or bi-directional streaming support
specifically, only that it will be implemented once WHATWG
Streams&lt;sup id="a18">&lt;a href="#f18">18&lt;/a>&lt;/sup> are implemented in browsers.&lt;/p>
&lt;p>The Google client supports unary and server-side streaming, but only when used
with the &lt;code>grpcwebtext&lt;/code> mode. Only unary requests are fully supported in the
&lt;code>grpcweb&lt;/code> mode. These two modes specify different ways to encode the protobuf
payload in the requests and responses.&lt;/p>
&lt;p>The Improbable client supports both unary and server-side streaming, and has an
implementation that automatically chooses between XHR and Fetch based on the
browser capabilities.&lt;/p>
&lt;p>Here’s a table that summarizes the different features supported:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Client / Feature&lt;/th>
&lt;th>Transport&lt;/th>
&lt;th>Unary&lt;/th>
&lt;th>Server-side streams&lt;/th>
&lt;th>Client-side &amp;amp; bi-directional streaming&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Improbable&lt;/td>
&lt;td>Fetch/XHR ️&lt;/td>
&lt;td>✔️&lt;/td>
&lt;td>✔️&lt;/td>
&lt;td>❌&lt;sup id="a19">&lt;a href="#f19">19&lt;/a>&lt;/sup>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Google (&lt;code>grpcwebtext&lt;/code>)&lt;/td>
&lt;td>XHR ️&lt;/td>
&lt;td>✔️&lt;/td>
&lt;td>✔️&lt;/td>
&lt;td>❌&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Google (&lt;code>grpcweb&lt;/code>)&lt;/td>
&lt;td>XHR ️&lt;/td>
&lt;td>✔️&lt;/td>
&lt;td>❌&lt;sup id="a20">&lt;a href="#f20">20&lt;/a>&lt;/sup>&lt;/td>
&lt;td>❌&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>For more information on this table, please see
&lt;a href="https://github.com/johanbrandhorst/grpc-web-compatibility-test" target="_blank" rel="noopener">my compatibility test repo on github&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;p>The compatibility tests may evolve into some automated test framework to enforce
and document the various compatibilities in the future.&lt;/p>
&lt;h2 id="compatibility-issues">Compatibility Issues&lt;/h2>
&lt;p>Of course, with two different proxies also come compatibility issues.
Fortunately, these have recently been ironed out, so you can expect to use
either client with either proxy.&lt;/p>
&lt;h1 id="the-future">The Future&lt;/h1>
&lt;p>The Google implementation announced version 1.0 and general availability in
October 2018&lt;sup id="a21">&lt;a href="#f21">21&lt;/a>&lt;/sup> and has published a road map of future
goals&lt;sup id="a22">&lt;a href="#f22">22&lt;/a>&lt;/sup>, including:&lt;/p>
&lt;ul>
&lt;li>An efficient JSON-like message encoding&lt;/li>
&lt;li>In-process proxies for Node, Python, Java and more&lt;/li>
&lt;li>Integration with popular frameworks (React, Angular, Vue)&lt;/li>
&lt;li>Fetch API transport for memory efficient streaming&lt;/li>
&lt;li>Bi-directional streaming support&lt;/li>
&lt;/ul>
&lt;p>Google is looking for feedback on what features are important to the community,
so if you think any of these are particularly valuable to you, then please fill
in their survey&lt;sup id="a23">&lt;a href="#f23">23&lt;/a>&lt;/sup>.&lt;/p>
&lt;p>Recent talks between the two projects have agreed on promoting the Google client
and Envoy proxy as preferred solutions for new users. The Improbable client and
proxy will remain as alternative implementations of the spec without the
Google Closure dependency, but should be considered experimental. A migration
guide will be produced for existing users to move to the Google client, and the
teams are working together to converge the generated APIs.&lt;/p>
&lt;h1 id="conclusion">Conclusion&lt;/h1>
&lt;p>The Google client will continue to have new features and fixes implemented at a
steady pace, with a team dedicated to its success, and it being the official
gRPC client. It doesn’t have Fetch API support like the Improbable client, but
if this is an important feature for the community, it will be added. The Google
team and the greater community are collaborating on the official client to the
benefit of the gRPC community at large. Since the GA announcement the community
contributions to the Google gRPC-Web repo has increased dramatically.&lt;/p>
&lt;p>When choosing between the two proxies, there&amp;rsquo;s no difference in capability, so
it becomes a matter of your deployment model. Envoy will suit some
scenarios, while an in-process Go proxy has its own advantages.&lt;/p>
&lt;p>If you’re getting started with gRPC-Web today, first try the Google client. It
has strict API compatibility guarantees and is built on the rock-solid Google
Closure library base used by Gmail and Google Maps. If you &lt;em>need&lt;/em> Fetch API
memory efficiency or experimental websocket client-side and bi-directional
streaming, the Improbable client is a good choice, and it will continue to be
used and maintained by Improbable for the foreseeable future.&lt;/p>
&lt;p>Either way, gRPC-Web is an excellent choice for web developers. It brings the
portability, performance, and engineering of a sophisticated protocol into the
browser, and marks an exciting time for frontend developers!&lt;/p>
&lt;h2 id="references">References&lt;/h2>
&lt;ol>
&lt;li>&lt;a id="f1">&lt;/a> &lt;a href="https://improbable.io/games/blog/grpc-web-moving-past-restjson-towards-type-safe-web-apis" target="_blank" rel="noopener">improbable.io/games/blog/grpc-web-moving-past-restjson-towards-type-safe-web-apis&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> &lt;a href="#a1">↩&lt;/a>&lt;/li>
&lt;li>&lt;a id="f2">&lt;/a> &lt;a href="https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md" target="_blank" rel="noopener">github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> &lt;a href="#a2">↩&lt;/a>&lt;/li>
&lt;li>&lt;a id="f3">&lt;/a> &lt;a href="https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md" target="_blank" rel="noopener">github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> &lt;a href="#a3">↩&lt;/a>&lt;/li>
&lt;li>&lt;a id="f4">&lt;/a> &lt;a href="https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md#protocol-differences-vs-grpc-over-http2" target="_blank" rel="noopener">github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md#protocol-differences-vs-grpc-over-http2&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> &lt;a href="#a4">↩&lt;/a>&lt;/li>
&lt;li>&lt;a id="f5">&lt;/a> &lt;a href="https://github.com/improbable-eng/grpc-web" target="_blank" rel="noopener">github.com/improbable-eng/grpc-web&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> &lt;a href="#a5">↩&lt;/a>&lt;/li>
&lt;li>&lt;a id="f6">&lt;/a> &lt;a href="https://github.com/grpc/grpc-web" target="_blank" rel="noopener">github.com/grpc/grpc-web&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> &lt;a href="#a6">↩&lt;/a>&lt;/li>
&lt;li>&lt;a id="f7">&lt;/a> &lt;a href="https://github.com/improbable-eng/grpc-web/issues/162" target="_blank" rel="noopener">github.com/improbable-eng/grpc-web/issues/162&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> &lt;a href="#a7">↩&lt;/a>&lt;/li>
&lt;li>&lt;a id="f8">&lt;/a> &lt;a href="https://github.com/grpc/grpc-web/issues/91" target="_blank" rel="noopener">github.com/grpc/grpc-web/issues/91&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> &lt;a href="#a8">↩&lt;/a>&lt;/li>
&lt;li>&lt;a id="f9">&lt;/a> &lt;a href="https://github.com/improbable-eng/grpc-web/tree/master/client/grpc-web" target="_blank" rel="noopener">github.com/improbable-eng/grpc-web/tree/master/client/grpc-web&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> &lt;a href="#a9">↩&lt;/a>&lt;/li>
&lt;li>&lt;a id="f10">&lt;/a> &lt;a href="https://www.npmjs.com/package/@improbable-eng/grpc-web" target="_blank" rel="noopener">npmjs.com/package/@improbable-eng/grpc-web&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> &lt;a href="#a10">↩&lt;/a>&lt;/li>
&lt;li>&lt;a id="f11">&lt;/a> &lt;a href="https://github.com/improbable-eng/grpc-web/tree/master/go/grpcweb" target="_blank" rel="noopener">github.com/improbable-eng/grpc-web/tree/master/go/grpcweb&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> &lt;a href="#a11">↩&lt;/a>&lt;/li>
&lt;li>&lt;a id="f12">&lt;/a> &lt;a href="https://github.com/improbable-eng/grpc-web/tree/master/go/grpcwebproxy" target="_blank" rel="noopener">github.com/improbable-eng/grpc-web/tree/master/go/grpcwebproxy&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> &lt;a href="#a12">↩&lt;/a>&lt;/li>
&lt;li>&lt;a id="f13">&lt;/a> &lt;a href="https://github.com/grpc/grpc-web/tree/master/javascript/net/grpc/web" target="_blank" rel="noopener">github.com/grpc/grpc-web/tree/master/javascript/net/grpc/web&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> &lt;a href="#a13">↩&lt;/a>&lt;/li>
&lt;li>&lt;a id="f14">&lt;/a> &lt;a href="https://developers.google.com/closure" target="_blank" rel="noopener">developers.google.com/closure&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> &lt;a href="#a14">↩&lt;/a>&lt;/li>
&lt;li>&lt;a id="f15">&lt;/a> &lt;a href="https://www.npmjs.com/package/grpc-web" target="_blank" rel="noopener">npmjs.com/package/grpc-web&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> &lt;a href="#a15">↩&lt;/a>&lt;/li>
&lt;li>&lt;a id="f16">&lt;/a> &lt;a href="https://github.com/grpc/grpc-web/tree/master/net/grpc/gateway" target="_blank" rel="noopener">github.com/grpc/grpc-web/tree/master/net/grpc/gateway&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> &lt;a href="#a16">↩&lt;/a>&lt;/li>
&lt;li>&lt;a id="f17">&lt;/a> &lt;a href="https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/grpc_web_filter" target="_blank" rel="noopener">envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/grpc_web_filter&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> &lt;a href="#a17">↩&lt;/a>&lt;/li>
&lt;li>&lt;a id="f18">&lt;/a> &lt;a href="https://streams.spec.whatwg.org" target="_blank" rel="noopener">streams.spec.whatwg.org&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> &lt;a href="#a18">↩&lt;/a>&lt;/li>
&lt;li>&lt;a id="f19">&lt;/a> The Improbable client supports client-side and
bi-directional streaming with an experimental websocket transport. This is
not part of the gRPC-Web spec, and is not recommended for production use. &lt;a href="#a19">↩&lt;/a>&lt;/li>
&lt;li>&lt;a id="f20">&lt;/a> &lt;code>grpcweb&lt;/code> allows server streaming methods to be called, but
it doesn&amp;rsquo;t return data until the stream has closed. &lt;a href="#a20">↩&lt;/a>&lt;/li>
&lt;li>&lt;a id="f21">&lt;/a> &lt;a href="https://grpc.io/blog/grpc-web-ga/">gRPC-Web is Generally Available&lt;/a> &lt;a href="#a21">↩&lt;/a>&lt;/li>
&lt;li>&lt;a id="f22">&lt;/a> &lt;a href="https://github.com/grpc/grpc-web/blob/master/doc/roadmap.md" target="_blank" rel="noopener">github.com/grpc/grpc-web/blob/master/doc/roadmap.md&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> &lt;a href="#a22">↩&lt;/a>&lt;/li>
&lt;li>&lt;a id="f23">&lt;/a> &lt;a href="https://docs.google.com/forms/d/1NjWpyRviohn5jaPntosBHXRXZYkh_Ffi4GxJZFibylM" target="_blank" rel="noopener">docs.google.com/forms/d/1NjWpyRviohn5jaPntosBHXRXZYkh_Ffi4GxJZFibylM&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> &lt;a href="#a23">↩&lt;/a>&lt;/li>
&lt;/ol></description></item><item><title>Blog: Visualizing gRPC Language Stacks</title><link>https://grpc.io/blog/grpc-stacks/</link><pubDate>Tue, 11 Dec 2018 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/grpc-stacks/</guid><description>
&lt;p>Here is a high level overview of the gRPC Stacks. Each of the &lt;strong>10&lt;/strong> default languages supported by gRPC has multiple layers, allowing you to customize what pieces you want in your application.&lt;/p>
&lt;p>There are three main stacks in gRPC: C-core, Go, and Java. Most of the languages are thin wrappers on top of the &lt;a href="https://github.com/grpc/grpc/tree/master/src/core" target="_blank" rel="noopener">C-based&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> gRPC core library:&lt;/p>
&lt;h3 id="wrapped-languages">Wrapped Languages:&lt;/h3>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/grpc-core-stack.svg" alt="gRPC Core Stack" id="grpc-core-stack.svg" data-toggle="modal" data-target="#modal-grpc-core-stack.svg"/>
&lt;div class="modal" id="modal-grpc-core-stack.svg">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/grpc-core-stack.svg" alt="gRPC Core Stack"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>For example, a Python application calls into the generated Python stubs. These calls pass through interceptors, and into the wrapping library where the calls are translated into C calls. The gRPC C-core will encode the RPC as HTTP/2, optionally encrypt the data with TLS, and then write it to the network.&lt;/p>
&lt;p>One of the cool things about gRPC is that you can swap these pieces out. For example, you could use C++ instead, and use an In-Process transport. This would save you from having to go all the way down to the OS network layer. Another example is trying out the QUIC protocol, which allows you to open new connections quickly. Being able to run over a variety of transports based on the environment makes gRPC really flexible.&lt;/p>
&lt;p>For each of the wrapped languages, the default HTTP/2 implementation is built into the C-core library, so there is no need to include an outside one. However, as you can see, it is possible to bring your own (such as with Cronet, the Chrome networking library).&lt;/p>
&lt;h3 id="go">Go&lt;/h3>
&lt;p>In &lt;a href="https://github.com/grpc/grpc-go" target="_blank" rel="noopener">gRPC-Go&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, the stack is much simpler, due to not having to support so many configurations. Here is a high level overview of the Go stack:&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/grpc-go-stack.svg" alt="gRPC Go Stack" id="grpc-go-stack.svg" data-toggle="modal" data-target="#modal-grpc-go-stack.svg"/>
&lt;div class="modal" id="modal-grpc-go-stack.svg">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/grpc-go-stack.svg" alt="gRPC Go Stack"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>The structure is a little different here. Since there is only one language, the flow from the top of the stack to the bottom is more linear. Unlike wrapped languages, gRPC Go can use either its own HTTP/2 implementation, or the Go &lt;code>net/http&lt;/code> package.&lt;/p>
&lt;h3 id="java">Java&lt;/h3>
&lt;p>Here is a high level overview of the &lt;a href="https://github.com/grpc/grpc-java" target="_blank" rel="noopener">gRPC-Java&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> stack:&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/grpc-java-stack.svg" alt="gRPC Java Stack" id="grpc-java-stack.svg" data-toggle="modal" data-target="#modal-grpc-java-stack.svg"/>
&lt;div class="modal" id="modal-grpc-java-stack.svg">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/grpc-java-stack.svg" alt="gRPC Java Stack"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>Again, the structure is a little different. Java supports HTTP/2, QUIC, and In Process like the C-core. Unlike the C-Core though, applications commonly can bypass the generated stubs and interceptors, and speak directly to the Java Core library. Each structure is slightly different based on the needs of each language implementation of gRPC. Also unlike wrapped languages, gRPC Java separates the HTTP/2 implementation into pluggable libraries (such as Netty, OkHttp, or Cronet).&lt;/p></description></item><item><title>Blog: gRPC-Web is Generally Available</title><link>https://grpc.io/blog/grpc-web-ga/</link><pubDate>Tue, 23 Oct 2018 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/grpc-web-ga/</guid><description>
&lt;p>We are excited to announce the GA release of
&lt;a href="https://www.npmjs.com/package/grpc-web" target="_blank" rel="noopener">gRPC-Web&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, a JavaScript client library
that enables web apps to communicate directly with gRPC backend services,
without requiring an HTTP server to act as an intermediary. &amp;ldquo;GA&amp;rdquo; means that
gRPC-Web is now Generally Available and stable and qualified for production use.&lt;/p>
&lt;p>With gRPC-Web, you can now easily build truly end-to-end gRPC application
architectures by defining your client &lt;em>and&lt;/em> server-side data types and service
interfaces with Protocol Buffers. This has been a hotly requested feature for a
while, and we are finally happy to say that it is now ready for production use.
In addition, being able to access gRPC services opens up new an exciting
possibilities for &lt;a href="https://github.com/grpc/grpc-experiments/tree/master/gdebug" target="_blank" rel="noopener">web based
tooling&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> around gRPC.&lt;/p>
&lt;h2 id="the-basics">The Basics&lt;/h2>
&lt;p>gRPC-Web, just like gRPC, lets you define the service &amp;ldquo;contract&amp;rdquo; between client
(web) and backend gRPC services using Protocol Buffers. The client can then be
auto generated. To do this, you have a choice between the &lt;a href="https://developers.google.com/closure/compiler/" target="_blank" rel="noopener">Closure&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> compiler
or the more widely used &lt;a href="https://requirejs.org/docs/commonjs.html" target="_blank" rel="noopener">CommonJS&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.
This development process removes the need to manage concerns such as creating
custom JSON serialization and deserialization logic, wrangling HTTP status codes
(which can vary across REST APIs), managing content type negotiation etc.&lt;/p>
&lt;p>From a broader architectural perspective, gRPC-Web enables end-to-end gRPC. The diagram below illustrates this:&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/grpc-web-arch.png" id="grpc-web-arch" data-toggle="modal" data-target="#modal-grpc-web-arch"/>
&lt;div class="modal" id="modal-grpc-web-arch">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/grpc-web-arch.png" />
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p style="text-align: center"> Figure 1. gRPC with gRPC-Web (left) and gRPC with REST (right)&lt;/p>
&lt;p>In the gRPC-Web universe on the left, a client application speaks Protocol Buffers to a gRPC backend server that speaks Protocol Buffers to other gRPC backend services. In the REST universe on the right, the web app speaks HTTP to a backend REST API server that then speaks Protocol Buffers to backend services.&lt;/p>
&lt;h2 id="advantages-of-using-grpc-web">Advantages of using gRPC-Web&lt;/h2>
&lt;p>gRPC-Web will offer an ever-broader feature set over time, but here’s what’s in 1.0 today:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>End-to-end gRPC&lt;/strong> — Enables you to craft your entire RPC pipeline using Protocol Buffers. Imagine a scenario in which a client request goes to an HTTP server, which then interacts with 5 backend gRPC services. There’s a good chance that you’ll spend as much time building the HTTP interaction layer as you will building the entire rest of the pipeline.&lt;/li>
&lt;li>&lt;strong>Tighter coordination between frontend and backend teams&lt;/strong> — With the entire RPC pipeline defined using Protocol Buffers, you no longer need to have your “microservices teams” alongside your “client team.” The client-backend interaction is just one more gRPC layer amongst others.&lt;/li>
&lt;li>&lt;strong>Easily generate client libraries&lt;/strong> — With gRPC-Web, the server that interacts with the “outside” world, i.e. the membrane connecting your backend stack to the internet, is now a gRPC server instead of an HTTP server, that means that all of your service’s client libraries can be gRPC libraries. Need client libraries for Ruby, Python, Java, and 4 other languages? You no longer need to write HTTP clients for all of them.&lt;/li>
&lt;/ul>
&lt;h2 id="a-grpc-web-example">A gRPC-Web example&lt;/h2>
&lt;p>The previous section illustrated some of the high-level advantages of gRPC-Web for large-scale applications. Now let’s get closer to the metal with an example: a simple TODO app. In gRPC-Web you can start with a simple &lt;code>todos.proto&lt;/code> definition like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-proto" data-lang="proto">&lt;span style="display:flex;">&lt;span>syntax &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#c30">&amp;#34;proto3&amp;#34;&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#069;font-weight:bold">package&lt;/span> &lt;span style="color:#0cf;font-weight:bold">todos&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#069;font-weight:bold">message&lt;/span> &lt;span style="color:#0a8;font-weight:bold">Todo&lt;/span> {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#078;font-weight:bold">string&lt;/span> content &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">1&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#078;font-weight:bold">bool&lt;/span> finished &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">2&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>}&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#069;font-weight:bold">message&lt;/span> &lt;span style="color:#0a8;font-weight:bold">GetTodoRequest&lt;/span> {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#078;font-weight:bold">int32&lt;/span> id &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">1&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>}&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#069;font-weight:bold">service&lt;/span> TodoService {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#069;font-weight:bold">rpc&lt;/span> GetTodoById (GetTodoRequest) &lt;span style="color:#069;font-weight:bold">returns&lt;/span> (Todo);&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>}&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>CommonJS client-side code can be generated from this &lt;code>.proto&lt;/code> definition with the following command:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>protoc echo.proto &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span> --js_out&lt;span style="color:#555">=&lt;/span>&lt;span style="color:#033">import_style&lt;/span>&lt;span style="color:#555">=&lt;/span>commonjs:./output &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span> --grpc-web_out&lt;span style="color:#555">=&lt;/span>&lt;span style="color:#033">import_style&lt;/span>&lt;span style="color:#555">=&lt;/span>commonjs:./output
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now, fetching a list of TODOs from a backend gRPC service is as simple as:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">const&lt;/span> {GetTodoRequest} &lt;span style="color:#555">=&lt;/span> require(&lt;span style="color:#c30">&amp;#39;./todos_pb.js&amp;#39;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">const&lt;/span> {TodoServiceClient} &lt;span style="color:#555">=&lt;/span> require(&lt;span style="color:#c30">&amp;#39;./todos_grpc_web_pb.js&amp;#39;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">const&lt;/span> todoService &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> proto.todos.TodoServiceClient(&lt;span style="color:#c30">&amp;#39;http://localhost:8080&amp;#39;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">const&lt;/span> todoId &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">1234&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">var&lt;/span> getTodoRequest &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> proto.todos.GetTodoRequest();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>getTodoRequest.setId(todoId);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">var&lt;/span> metadata &lt;span style="color:#555">=&lt;/span> {};
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">var&lt;/span> getTodo &lt;span style="color:#555">=&lt;/span> todoService.getTodoById(getTodoRequest, metadata, (err, response) =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">if&lt;/span> (err) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> console.log(err);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#069;font-weight:bold">else&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">const&lt;/span> todo &lt;span style="color:#555">=&lt;/span> response.todo();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">if&lt;/span> (todo &lt;span style="color:#555">==&lt;/span> &lt;span style="color:#069;font-weight:bold">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> console.log(&lt;span style="color:#c30">`A TODO with the ID &lt;/span>&lt;span style="color:#a00">${&lt;/span>todoId&lt;span style="color:#a00">}&lt;/span>&lt;span style="color:#c30"> wasn&amp;#39;t found`&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#069;font-weight:bold">else&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> console.log(&lt;span style="color:#c30">`Fetched TODO with ID &lt;/span>&lt;span style="color:#a00">${&lt;/span>todoId&lt;span style="color:#a00">}&lt;/span>&lt;span style="color:#c30">: &lt;/span>&lt;span style="color:#a00">${&lt;/span>todo.content()&lt;span style="color:#a00">}&lt;/span>&lt;span style="color:#c30">`&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>});
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Once you declare the data types and a service interface, gRPC-Web abstracts away all the boilerplate, leaving you with a clean and human-friendly API (essentially the same API as the current &lt;a href="https://grpc.io/docs/languages/node/">Node.js&lt;/a> for gRPC API, just transferred to the client).&lt;/p>
&lt;p>On the backend, the gRPC server can be written in any language that supports gRPC, such as Go, Java, C++, Ruby, Node.js, and many others. The last piece of the puzzle is the service proxy. From the get-go, gRPC-Web will support &lt;a href="https://envoyproxy.io" target="_blank" rel="noopener">Envoy&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> as the default service proxy, which has a built-in &lt;a href="https://www.envoyproxy.io/docs/envoy/latest/configuration/http_filters/grpc_web_filter#config-http-filters-grpc-web" target="_blank" rel="noopener">envoy.grpc_web filter&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> that you can apply with just a few lines of configuration.&lt;/p>
&lt;h2 id="next-steps">Next Steps&lt;/h2>
&lt;p>Going GA means that the core building blocks are firmly in place and ready for usage in production web applications. But there’s still much more to come for gRPC-Web. Check out the &lt;a href="https://github.com/grpc/grpc-web/blob/master/doc/roadmap.md" target="_blank" rel="noopener">official road map&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> to see what the core team envisions for the near future.&lt;/p>
&lt;p>If you’re interested in contributing to gRPC-Web, there are a few things we would love community help with:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Front-end framework integration&lt;/strong> — Commonly used front-end frameworks like &lt;a href="https://reactjs.org" target="_blank" rel="noopener">React&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, &lt;a href="https://vuejs.org" target="_blank" rel="noopener">Vue&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> and &lt;a href="https://angular.io" target="_blank" rel="noopener">Angular&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> don&amp;rsquo;t yet offer official support for gRPC-Web. But we would love to see these frameworks support it since the integration between these frontend frameworks and gRPC-Web can be a vehicle to deliver user-perceivable performance benefits to applications. If you are interested in building out support for these frontend frameworks, let us know on the &lt;a href="https://groups.google.com/g/grpc-io" target="_blank" rel="noopener">gRPC.io mailing list&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, &lt;a href="https://github.com/grpc/grpc-web/issues" target="_blank" rel="noopener">filing a feature request on github&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> or via the feature survey form below.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Language-specific proxy support&lt;/strong> — As of the GA release, &lt;a href="https://envoyproxy.io" target="_blank" rel="noopener">Envoy&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> is the default proxy for gRPC-Web, offering support via a special module. NGINX is also &lt;a href="https://github.com/grpc/grpc-web/tree/master/net/grpc/gateway/nginx" target="_blank" rel="noopener">supported&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. But we’d also love to see development of in-process proxies for specific languages since they obviate the need for special proxies—such as Envoy and nginx—and would make using gRPC-Web even easier.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>We’d also love to get feature requests from the community. Currently the best way to make feature requests is to fill out the &lt;a href="https://docs.google.com/forms/d/1NjWpyRviohn5jaPntosBHXRXZYkh_Ffi4GxJZFibylM/viewform?edit_requested=true" target="_blank" rel="noopener">gRPC-Web road map features survey&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. When filling up the form, list features you’d like to see and also let us know if you’d like to contribute to the development of those features in the &lt;strong>I’d like to contribute to&lt;/strong> section. The gRPC-Web engineers will be sure to take that information to heart over the course of the project’s development.&lt;/p>
&lt;p>Most importantly, we want to thank all the Alpha and Beta users who have given us feedback, bug reports and pull requests contributions over the course of the past year. We would certainly hope to maintain this momentum and make sure this project brings tangible benefits to the developer community.&lt;/p></description></item><item><title>Blog: A short introduction to Channelz</title><link>https://grpc.io/blog/a-short-introduction-to-channelz/</link><pubDate>Wed, 05 Sep 2018 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/a-short-introduction-to-channelz/</guid><description>
&lt;p>Channelz is a tool that provides comprehensive runtime info about connections at
different levels in gRPC. It is designed to help debug live programs, which may
be suffering from network, performance, configuration issues, etc. The
&lt;a href="https://github.com/grpc/proposal/blob/master/A14-channelz.md" target="_blank" rel="noopener">gRFC&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> provides a
detailed explanation of channelz design and is the canonical reference for all
channelz implementations across languages. The purpose of this blog is to
familiarize readers with channelz service and how to use it for debugging
issues. The context of this post is set in
&lt;a href="https://github.com/grpc/grpc-go" target="_blank" rel="noopener">gRPC-Go&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, but the overall idea should be
applicable across languages. At the time of writing, channelz is available for
&lt;a href="https://github.com/grpc/grpc-go" target="_blank" rel="noopener">gRPC-Go&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> and
&lt;a href="https://github.com/grpc/grpc-java" target="_blank" rel="noopener">gRPC-Java&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. Support for
&lt;a href="https://github.com/grpc/grpc" target="_blank" rel="noopener">C++&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> and wrapped languages is coming soon.&lt;/p>
&lt;p>Let&amp;rsquo;s learn channelz through a simple example which uses channelz to help debug
an issue. The
&lt;a href="https://github.com/grpc/grpc-go/tree/master/examples/helloworld" target="_blank" rel="noopener">helloworld&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
example from our repo is slightly modified to set up a buggy scenario. You can
find the full source code here:
&lt;a href="https://gist.github.com/lyuxuan/515fa6da7e0924b030e29b8be56fd90a" target="_blank" rel="noopener">client&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>,
&lt;a href="https://gist.github.com/lyuxuan/81dd08ca649a6c78a61acc7ab05e0fef" target="_blank" rel="noopener">server&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Client setup:&lt;/strong>
The client will make 100 SayHello RPCs to a specified target and load balance
the workload with the round robin policy. Each call has a 150ms timeout. RPC
responses and errors are logged for debugging purposes.&lt;/p>
&lt;/blockquote>
&lt;p>Running the program, we notice in the log that there are intermittent errors
with error code &lt;strong>DeadlineExceeded&lt;/strong>, as shown in Figure 1.&lt;/p>
&lt;p>However, there&amp;rsquo;s no clue about what is causing the deadline exceeded error and
there are many possibilities:&lt;/p>
&lt;ul>
&lt;li>Network issue, for example: connection lost&lt;/li>
&lt;li>Proxy issue, for example: dropped requests/responses in the middle&lt;/li>
&lt;li>Server issue, for example: lost requests or just slow to respond&lt;/li>
&lt;/ul>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/log.png" id="log" data-toggle="modal" data-target="#modal-log"/>
&lt;div class="modal" id="modal-log">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/log.png" />
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p style="text-align: center"> Figure 1. Program log screenshot&lt;/p>
&lt;p>Let&amp;rsquo;s turn on grpc INFO logging for more debug info and see if we can find
something helpful.&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/logWithInfo.png" id="logWithInfo" data-toggle="modal" data-target="#modal-logWithInfo"/>
&lt;div class="modal" id="modal-logWithInfo">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/logWithInfo.png" />
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p style="text-align: center"> Figure 2. gRPC INFO log&lt;/p>
&lt;p>As shown in Figure 2, the info log indicates that all three connections to the
server are connected and ready for transmitting RPCs. No suspicious event shows
up in the log. One thing that can be inferred from the info log is that all
connections are up all the time, therefore the lost connection hypothesis can be
ruled out.&lt;/p>
&lt;p>To further narrow down the root cause of the issue, we will ask channelz for
help.&lt;/p>
&lt;p>Channelz provides gRPC internal networking machinery stats through a gRPC
service. To enable channelz, users just need to register the channelz service to
a gRPC server in their program and start the server. The code snippet below
shows the API for registering channelz service to a
&lt;a href="https://godoc.org/google.golang.org/grpc#Server" target="_blank" rel="noopener">grpc.Server&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. Note that this
has already been done for our example client.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">import&lt;/span> &lt;span style="color:#c30">&amp;#34;google.golang.org/grpc/channelz/service&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// s is a *grpc.Server
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>service.&lt;span style="color:#c0f">RegisterChannelzServiceToServer&lt;/span>(s)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// call s.Serve() to serve channelz service
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>A web tool called
&lt;a href="https://github.com/grpc/grpc-experiments/tree/master/gdebug" target="_blank" rel="noopener">grpc-zpages&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
has been developed to conveniently serve channelz data through a web page.
First, configure the web app to connect to the gRPC port that&amp;rsquo;s serving the
channelz service (see instructions from the previous link). Then, open the
channelz web page in the browser. You should see a web page like Figure 3. Now
we can start querying channelz!&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/mainpage.png" id="mainpage" data-toggle="modal" data-target="#modal-mainpage"/>
&lt;div class="modal" id="modal-mainpage">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/mainpage.png" />
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p style="text-align: center"> Figure 3. Channelz main page&lt;/p>
&lt;p>As the error is on the client side, let&amp;rsquo;s first click on
&lt;a href="https://github.com/grpc/proposal/blob/master/A14-channelz.md#gettopchannels" target="_blank" rel="noopener">TopChannels&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.
TopChannels is a collection of root channels which don&amp;rsquo;t have parents. In
gRPC-Go, a top channel is a
&lt;a href="https://godoc.org/google.golang.org/grpc#ClientConn" target="_blank" rel="noopener">ClientConn&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> created by the
user through &lt;a href="https://godoc.org/google.golang.org/grpc#NewClient" target="_blank" rel="noopener">NewClient&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>,
and used for making RPC calls. Top channels are of
&lt;a href="https://github.com/grpc/grpc-proto/blob/9b13d199cc0d4703c7ea26c9c330ba695866eb23/grpc/channelz/v1/channelz.proto#L37" target="_blank" rel="noopener">Channel&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
type in channelz, which is an abstraction of a connection that an RPC can be
issued to.&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/topChan1.png" id="topChan1" data-toggle="modal" data-target="#modal-topChan1"/>
&lt;div class="modal" id="modal-topChan1">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/topChan1.png" />
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p style="text-align: center"> Figure 4. TopChannels result&lt;/p>
&lt;p>So we click on the TopChannels, and a page like Figure 4 appears, which lists
all the live top channel(s) with related info.&lt;/p>
&lt;p>As shown in Figure 5, there is only one top channel with id = 2 (Note that text
in square brackets is the reference name of the in memory channel object, which
may vary across languages).&lt;/p>
&lt;p>Looking at the &lt;strong>Data&lt;/strong> section, we can see there are 15 calls failed out of 100
on this channel.&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/topChan2.png" id="topChan2" data-toggle="modal" data-target="#modal-topChan2"/>
&lt;div class="modal" id="modal-topChan2">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/topChan2.png" />
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p style="text-align: center"> Figure 5. Top Channel (id = 2)&lt;/p>
&lt;p>On the right hand side, it shows the channel has no child &lt;strong>Channels&lt;/strong>, 3
&lt;strong>Subchannels&lt;/strong> (as highlighted in Figure 6), and 0 &lt;strong>Sockets&lt;/strong>.&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/topChan3.png" id="topChan3" data-toggle="modal" data-target="#modal-topChan3"/>
&lt;div class="modal" id="modal-topChan3">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/topChan3.png" />
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p style="text-align: center"> Figure 6. Subchannels owned by the Channel (id = 2)&lt;/p>
&lt;p>A
&lt;a href="https://github.com/grpc/grpc-proto/blob/9b13d199cc0d4703c7ea26c9c330ba695866eb23/grpc/channelz/v1/channelz.proto#L61" target="_blank" rel="noopener">Subchannel&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
is an abstraction over a connection and used for load balancing. For example,
you want to send requests to &amp;ldquo;google.com&amp;rdquo;. The resolver resolves &amp;ldquo;google.com&amp;rdquo; to
multiple backend addresses that serve &amp;ldquo;google.com&amp;rdquo;. In this example, the client
is set up with the round robin load balancer, so all live backends are sent
equal traffic. Then the (logical) connection to each backend is represented as a
Subchannel. In gRPC-Go, a
&lt;a href="https://godoc.org/google.golang.org/grpc/balancer#SubConn" target="_blank" rel="noopener">SubConn&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> can be seen
as a Subchannel.&lt;/p>
&lt;p>The three Subchannels owned by the parent Channel means there are three
connections to three different backends for sending the RPCs to. Let&amp;rsquo;s look
inside each of them for more info.&lt;/p>
&lt;p>So we click on the first Subchannel ID (i.e. &amp;ldquo;4[]&amp;rdquo;) listed, and a page like
Figure 7 renders. We can see that all calls on this Subchannel have succeeded.
Thus it&amp;rsquo;s unlikely this Subchannel is related to the issue we are having.&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/subChan4.png" id="subChan4" data-toggle="modal" data-target="#modal-subChan4"/>
&lt;div class="modal" id="modal-subChan4">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/subChan4.png" />
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p style="text-align: center"> Figure 7. Subchannel (id = 4)&lt;/p>
&lt;p>So we go back, and click on Subchannel 5 (i.e. &amp;ldquo;5[]&amp;rdquo;). Again, the web page
indicates that Subchannel 5 also never had any failed calls.&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/subChan6_1.png" id="subChan6_1" data-toggle="modal" data-target="#modal-subChan6_1"/>
&lt;div class="modal" id="modal-subChan6_1">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/subChan6_1.png" />
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p style="text-align: center"> Figure 8. Subchannel (id = 6)&lt;/p>
&lt;p>And finally, we click on Subchannel 6. This time, there&amp;rsquo;s something different.
As we can see in Figure 8, there are 15 out of 34 RPC calls failed on this
Subchannel. And remember that the parent Channel also has exactly 15 failed
calls. Therefore, Subchannel 6 is where the issue comes from. The state of the
Subchannel is &lt;strong>READY&lt;/strong>, which means it is connected and is ready to transmit
RPCs. That rules out network connection problems. To dig up more info, let&amp;rsquo;s
look at the Socket owned by this Subchannel.&lt;/p>
&lt;p>A
&lt;a href="https://github.com/grpc/grpc-proto/blob/9b13d199cc0d4703c7ea26c9c330ba695866eb23/grpc/channelz/v1/channelz.proto#L227" target="_blank" rel="noopener">Socket&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
is roughly equivalent to a file descriptor, and can be generally regarded as the
TCP connection between two endpoints. In grpc-go,
&lt;a href="https://github.com/grpc/grpc-go/blob/ce4f3c8a89229d9db3e0c30d28a9f905435ad365/internal/transport/http2_client.go#L46" target="_blank" rel="noopener">http2Client&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
and
&lt;a href="https://github.com/grpc/grpc-go/blob/ce4f3c8a89229d9db3e0c30d28a9f905435ad365/internal/transport/http2_server.go#L61" target="_blank" rel="noopener">http2Server&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
correspond to Socket. Note that a network listener is also considered a Socket,
and will show up in the channelz Server info.&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/subChan6_2.png" id="subChan6_2" data-toggle="modal" data-target="#modal-subChan6_2"/>
&lt;div class="modal" id="modal-subChan6_2">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/subChan6_2.png" />
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p style="text-align: center"> Figure 9. Subchannel (id = 6) owns Socket (id = 8)&lt;/p>
&lt;p>We click on Socket 8, which is at the bottom of the page (see Figure 9). And we
now see a page like Figure 10.&lt;/p>
&lt;p>The page provides comprehensive info about the socket like the security
mechanism in use, stream count, message count, keepalives, flow control numbers,
etc. The socket options info is not shown in the screenshot, as there are a lot
of them and not related to the issue we are investigating.&lt;/p>
&lt;p>The &lt;strong>Remote Address&lt;/strong> field suggests that the backend we are having a problem
with is &lt;strong>&amp;ldquo;127.0.0.1:10003&amp;rdquo;&lt;/strong>. The stream counts here correspond perfectly to
the call counts of the parent Subchannel. From this, we can know that the server
is not actively sending DeadlineExceeded errors. This is because if the
DeadlineExceeded error is returned by the server, then the streams would all be
successful. A client side stream&amp;rsquo;s success is independent of whether the call
succeeds. It is determined by whether a HTTP2 frame with EOS bit set has been
received (refer to the
&lt;a href="https://github.com/grpc/proposal/blob/master/A14-channelz.md#socket-data" target="_blank" rel="noopener">gRFC&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
for more info). Also, we can see that the number of messages sent is 34, which
equals the number of calls, and it rules out the possibility of the client being
stuck somehow and results in deadline exceeded. In summary, we can narrow down
the issue to the server which serves on 127.0.0.1:10003. It may be that the
server is slow to respond, or some proxy in front of it is dropping requests.&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/socket8.png" id="socket8" data-toggle="modal" data-target="#modal-socket8"/>
&lt;div class="modal" id="modal-socket8">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/socket8.png" />
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p style="text-align: center"> Figure 10. Socket (id = 8)&lt;/p>
&lt;p>As you see, channelz has helped us pinpoint the potential root cause of the
issue with just a few clicks. You can now concentrate on what&amp;rsquo;s happening with
the pinpointed server. And again, channelz may help expedite the debugging at
the server side too.&lt;/p>
&lt;p>We will stop here and let readers explore the server side channelz, which is
simpler than the client side. In channelz, a
&lt;a href="https://github.com/grpc/grpc-proto/blob/9b13d199cc0d4703c7ea26c9c330ba695866eb23/grpc/channelz/v1/channelz.proto#L199" target="_blank" rel="noopener">Server&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
is also an RPC entry point like a Channel, where incoming RPCs arrive and get
processed. In grpc-go, a
&lt;a href="https://godoc.org/google.golang.org/grpc#Server" target="_blank" rel="noopener">grpc.Server&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> corresponds to a
channelz Server. Unlike Channel, Server only has Sockets (both listen socket(s)
and normal connected socket(s)) as its children.&lt;/p>
&lt;p>Here are some hints for the readers:&lt;/p>
&lt;ul>
&lt;li>Look for the server with the address (127.0.0.1:10003).&lt;/li>
&lt;li>Look at the call counts.&lt;/li>
&lt;li>Go to the Socket(s) owned by the server.&lt;/li>
&lt;li>Look at the Socket stream counts and message counts.&lt;/li>
&lt;/ul>
&lt;p>You should notice that the number of messages received by the server socket is
the same as sent by the client socket (Socket 8), which rules out the case of
having a misbehaving proxy (dropping request) in the middle. And the number of
messages sent by the server socket is equal to the messages received at client
side, which means the server was not able to send back the response before
deadline. You may now look at the
&lt;a href="https://gist.github.com/lyuxuan/81dd08ca649a6c78a61acc7ab05e0fef" target="_blank" rel="noopener">server&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> code
to verify whether it is indeed the cause.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Server setup:&lt;/strong>
The server side program starts up three GreeterServers, with two of them using
an implementation
(&lt;a href="https://gist.github.com/lyuxuan/81dd08ca649a6c78a61acc7ab05e0fef#file-main-go-L42" target="_blank" rel="noopener">server&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>)
that imposes no delay when responding to the client, and one using an
implementation
(&lt;a href="https://gist.github.com/lyuxuan/81dd08ca649a6c78a61acc7ab05e0fef#file-main-go-L50" target="_blank" rel="noopener">slowServer&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>)
which injects a variable delay of 100ms - 200ms before sending the response.&lt;/p>
&lt;/blockquote>
&lt;p>As you can see through this demo, channelz helped us quickly narrow down the
possible causes of an issue and is easy to use. For more resources, see the
detailed channelz
&lt;a href="https://github.com/grpc/proposal/blob/master/A14-channelz.md" target="_blank" rel="noopener">gRFC&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. Find us on
GitHub at &lt;a href="https://github.com/grpc/grpc-go" target="_blank" rel="noopener">github.com/grpc/grpc-go&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p></description></item><item><title>Blog: gRPC on HTTP/2 Engineering a Robust, High-performance Protocol</title><link>https://grpc.io/blog/grpc-on-http2/</link><pubDate>Mon, 20 Aug 2018 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/grpc-on-http2/</guid><description>
&lt;p>In a &lt;a href="https://www.cncf.io/blog/2018/07/03/http-2-smarter-at-scale/" target="_blank" rel="noopener">previous article&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, we explored how HTTP/2 dramatically increases network efficiency and enables real-time communication by providing a framework for long-lived connections. In this article, we’ll look at how gRPC builds on HTTP/2’s long-lived connections to create a performant, robust platform for inter-service communication. We will explore the relationship between gRPC and HTTP/2, how gRPC manages HTTP/2 connections, and how gRPC uses HTTP/2 to keep connections alive, healthy, and utilized.&lt;/p>
&lt;h2 id="grpc-semantics">gRPC Semantics&lt;/h2>
&lt;p>To begin, let’s dive into how gRPC concepts relate to HTTP/2 concepts. gRPC introduces three new concepts: &lt;em>channels&lt;/em>&lt;sup id="a1">&lt;a href="#f1">1&lt;/a>&lt;/sup>, &lt;em>remote procedure calls&lt;/em> (RPCs), and &lt;em>messages&lt;/em>. The relationship between the three is simple: each channel may have many RPCs while each RPC may have many messages.&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/channels_mapping_2.png" alt="Channel mapping" id="channels_mapping_2" data-toggle="modal" data-target="#modal-channels_mapping_2"/>
&lt;div class="modal" id="modal-channels_mapping_2">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/channels_mapping_2.png" alt="Channel mapping"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>Let’s take a look at how gRPC semantics relate to HTTP/2:&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/grpc_on_http2_mapping_2.png" alt="gRPC on HTTP/2" id="grpc_on_http2_mapping_2" data-toggle="modal" data-target="#modal-grpc_on_http2_mapping_2"/>
&lt;div class="modal" id="modal-grpc_on_http2_mapping_2">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/grpc_on_http2_mapping_2.png" alt="gRPC on HTTP/2"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>Channels are a key concept in gRPC. Streams in HTTP/2 enable multiple concurrent conversations on a single connection; channels extend this concept by enabling multiple streams over multiple concurrent connections. On the surface, channels provide an easy interface for users to send messages into; underneath the hood, though, an incredible amount of engineering goes into keeping these connections alive, healthy, and utilized.&lt;/p>
&lt;p>Channels represent virtual connections to an endpoint, which in reality may be backed by many HTTP/2 connections. RPCs are associated with a connection (this association is described further on). RPCs are in practice plain HTTP/2 streams. Messages are associated with RPCs and get sent as HTTP/2 data frames. To be more specific, messages are &lt;em>layered&lt;/em> on top of data frames. A data frame may have many gRPC messages, or if a gRPC message is quite large&lt;sup id="a2">&lt;a href="#f2">2&lt;/a>&lt;/sup> it might span multiple data frames.&lt;/p>
&lt;h2 id="resolvers-and-load-balancers">Resolvers and Load Balancers&lt;/h2>
&lt;p>In order to keep connections alive, healthy, and utilized, gRPC utilizes a number of components, foremost among them &lt;em>name resolvers&lt;/em> and &lt;em>load balancers&lt;/em>. The resolver turns names into addresses and then hands these addresses to the load balancer. The load balancer is in charge of creating connections from these addresses and load balancing RPCs between connections.&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/dns_to_load_balancer_mapping_3.png" alt="Resolvers and Load Balancers" id="dns_to_load_balancer_mapping_3" data-toggle="modal" data-target="#modal-dns_to_load_balancer_mapping_3"/>
&lt;div class="modal" id="modal-dns_to_load_balancer_mapping_3">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/dns_to_load_balancer_mapping_3.png" alt="Resolvers and Load Balancers"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/load_balance_round_robins_2.png" alt="Round Robin Load Balancer" id="load_balance_round_robins_2" data-toggle="modal" data-target="#modal-load_balance_round_robins_2"/>
&lt;div class="modal" id="modal-load_balance_round_robins_2">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/load_balance_round_robins_2.png" alt="Round Robin Load Balancer"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>A DNS resolver, for example, might resolve some host name to 13 IP addresses, and then a RoundRobin balancer might create 13 connections - one to each address - and round robin RPCs across each connection. A simpler balancer might simply create a connection to the first address. Alternatively, a user who wants multiple connections but knows that the host name will only resolve to one address might have their balancer create connections against each address 10 times to ensure that multiple connections are used.&lt;/p>
&lt;p>Resolvers and load balancers solve small but crucial problems in a gRPC system. This design is intentional: reducing the problem space to a few small, discrete problems helps users build custom components. These components can be used to fine-tune gRPC to fit each system’s individual needs.&lt;/p>
&lt;h2 id="connection-management">Connection Management&lt;/h2>
&lt;p>Once configured, gRPC will keep the pool of connections - as defined by the resolver and balancer - healthy, alive, and utilized.&lt;/p>
&lt;p>When a connection fails, the load balancer will begin to reconnect using the last known list of addresses&lt;sup id="a3">&lt;a href="#f3">3&lt;/a>&lt;/sup>. Meanwhile, the resolver will begin attempting to re-resolve the list of host names. This is useful in a number of scenarios. If the proxy is no longer reachable, for example, we’d want the resolver to update the list of addresses to not include that proxy’s address. To take another example: DNS entries might change over time, and so the list of addresses might need to be periodically updated. In this manner and others, gRPC is designed for long-term resiliency.&lt;/p>
&lt;p>Once resolution is finished, the load balancer is informed of the new addresses. If addresses have changed, the load balancer may spin down connections to addresses not present in the new list or create connections to addresses that weren’t previously there.&lt;/p>
&lt;h2 id="identifying-failed-connections">Identifying Failed Connections&lt;/h2>
&lt;p>The effectiveness of gRPC&amp;rsquo;s connection management hinges upon its ability to identify failed connections. There are generally two types of connection failures: clean failures, in which the failure is communicated, and the less-clean failure, in which the failure is not communicated.&lt;/p>
&lt;p>Let’s consider a clean, easy-to-observe failure. Clean failures can occur when an endpoint intentionally kills the connection. For example, the endpoint may have gracefully shut down, or a timer may have been exceeded, prompting the endpoint to close the connection. When connections close cleanly, TCP semantics suffice: closing a connection causes the &lt;a href="http://www.tcpipguide.com/free/t_TCPConnectionTermination-2.htm" target="_blank" rel="noopener">FIN handshake&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> to occur. This ends the HTTP/2 connection, which ends the gRPC connection. gRPC will immediately begin reconnecting (as described above). This is quite clean and requires no additional HTTP/2 or gRPC semantics.&lt;/p>
&lt;p>The less clean version is where the endpoint dies or hangs without informing the client. In this case, TCP might undergo retry for as long as 10 minutes before the connection is considered failed. Of course, failing to recognize that the connection is dead for 10 minutes is unacceptable. gRPC solves this problem using HTTP/2 semantics: when configured using KeepAlive, gRPC will periodically send &lt;a href="https://http2.github.io/http2-spec/#PING" target="_blank" rel="noopener">HTTP/2 PING frames&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. These frames bypass flow control and are used to establish whether the connection is alive. If a PING response does not return within a timely fashion, gRPC will consider the connection failed, close the connection, and begin reconnecting (as described above).&lt;/p>
&lt;p>In this way, gRPC keeps a pool of connections healthy and uses HTTP/2 to ascertain the health of connections periodically. All of this behavior is opaque to the user, and message redirecting happens automatically and on the fly. Users simply send messages on a seemingly always-healthy pool of connections.&lt;/p>
&lt;h2 id="keeping-connections-alive">Keeping Connections Alive&lt;/h2>
&lt;p>As mentioned above, KeepAlive provides a valuable benefit: periodically checking the health of the connection by sending an HTTP/2 PING to determine whether the connection is still alive. However, it has another equally useful benefit: signaling liveness to proxies.&lt;/p>
&lt;p>Consider a client sending data to a server through a proxy. The client and server may be happy to keep a connection alive indefinitely, sending data as necessary. Proxies, on the other hand, are often quite resource constrained and may kill idle connections to save resources. Google Cloud Platform (GCP) load balancers disconnect apparently-idle connections after &lt;a href="https://cloud.google.com/compute/docs/troubleshooting#communicatewithinternet" target="_blank" rel="noopener">10 minutes&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, and Amazon Web Services Elastic Load Balancers (AWS ELBs) disconnect them after &lt;a href="https://aws.amazon.com/articles/1636185810492479" target="_blank" rel="noopener">60 seconds&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;p>With gRPC periodically sending HTTP/2 PING frames on connections, the perception of a non-idle connection is created. Endpoints using the aforementioned idle kill rule would pass over killing these connections.&lt;/p>
&lt;h2 id="a-robust-high-performance-protocol">A Robust, High Performance Protocol&lt;/h2>
&lt;p>HTTP/2 provides a foundation for long-lived, real-time communication streams. gRPC builds on top of this foundation with connection pooling, health semantics, efficient use of data frames and multiplexing, and KeepAlive.&lt;/p>
&lt;p>Developers choosing protocols must choose those that meet today’s demands as well as tomorrow’s. They are well served by choosing gRPC, whether it be for resiliency, performance, long-lived or short-lived communication, customizability, or simply knowing that their protocol will scale to extraordinarily massive traffic while remaining efficient all the way. To get going with gRPC and HTTP/2 right away, check out &lt;a href="https://grpc.io/docs/" target="_blank" rel="noopener">gRPC&amp;rsquo;s Getting Started guides&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;h2 id="footnotes">Footnotes&lt;/h2>
&lt;ol>
&lt;li>&lt;a id="f1">&lt;/a> In Go, a gRPC channel is called ClientConn because the word “channel” has a language-specific meaning. &lt;a href="#a1">↩&lt;/a>&lt;/li>
&lt;li>&lt;a id="f2">&lt;/a> gRPC uses the HTTP/2 default max size for a data frame of 16kb. A message over 16kb may span multiple data frames, whereas a message below that size may share a data frame with some number of other messages. &lt;a href="#a2">↩&lt;/a>&lt;/li>
&lt;li>&lt;a id="f3">&lt;/a> This is the behavior of the RoundRobin balancer, but not every load balancer does or must behave this way. &lt;a href="#a3">↩&lt;/a>&lt;/li>
&lt;/ol></description></item><item><title>Blog: gRPC + JSON</title><link>https://grpc.io/blog/grpc-with-json/</link><pubDate>Wed, 15 Aug 2018 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/grpc-with-json/</guid><description>
&lt;p>So you&amp;rsquo;ve bought into this whole RPC thing and want to try it out, but aren&amp;rsquo;t quite sure about Protocol Buffers. Your existing code encodes your own objects, or perhaps you have code that needs a particular encoding. What to do?&lt;/p>
&lt;p>Fortunately, gRPC is encoding agnostic! You can still get a lot of the benefits of gRPC without using Protobuf. In this post we&amp;rsquo;ll go through how to make gRPC work with other encodings and types. Let&amp;rsquo;s try using JSON.&lt;/p>
&lt;p>gRPC is actually a collection of technologies that have high cohesion, rather than a singular, monolithic framework. This means its possible to swap out parts of gRPC and still take advantage of gRPC&amp;rsquo;s benefits. &lt;a href="https://github.com/google/gson" target="_blank" rel="noopener">Gson&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> is a popular library for Java for doing JSON encoding. Let&amp;rsquo;s remove all the protobuf related things and replace them with Gson:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-diff" data-lang="diff">&lt;span style="display:flex;">&lt;span>&lt;span style="background-color:#fcc">- Protobuf wire encoding
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="background-color:#fcc">- Protobuf generated message types
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="background-color:#fcc">- gRPC generated stub types
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="background-color:#fcc">&lt;/span>&lt;span style="background-color:#cfc">+ JSON wire encoding
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="background-color:#cfc">+ Gson message types
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Previously, Protobuf and gRPC were generating code for us, but we would like to use our own types. Additionally, we are going to be using our own encoding too. Gson allows us to bring our own types in our code, but provides a way of serializing those types into bytes.&lt;/p>
&lt;p>Let&amp;rsquo;s continue with the &lt;a href="https://github.com/carl-mastrangelo/kvstore/tree/04-gson-marshaller" target="_blank" rel="noopener">Key-Value&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> store service. We will be modifying the code used my previous &lt;a href="https://grpc.io/blog/optimizing-grpc-part-2/">So You Want to Optimize gRPC&lt;/a> post.&lt;/p>
&lt;h2 id="what-is-a-service-anyways">What is a Service Anyways?&lt;/h2>
&lt;p>From the point of view of gRPC, a &lt;em>Service&lt;/em> is a collection of &lt;em>Methods&lt;/em>. In Java, a method is represented as a &lt;a href="https://grpc.io/grpc-java/javadoc/io/grpc/MethodDescriptor.html" target="_blank" rel="noopener">MethodDescriptor&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. Each &lt;code>MethodDescriptor&lt;/code> includes the name of the method, a &lt;code>Marshaller&lt;/code> for encoding requests, and a &lt;code>Marshaller&lt;/code> for encoding responses. They also include additional detail, such as if the call is streaming or not. For simplicity, we&amp;rsquo;ll stick with unary RPCs which have a single request and single response.&lt;/p>
&lt;p>Since we won&amp;rsquo;t be generating any code, we&amp;rsquo;ll need to write the message classes ourselves. There are four methods, each which have a request and a response type. This means we need to make eight messages:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">static&lt;/span> &lt;span style="color:#069;font-weight:bold">final&lt;/span> &lt;span style="color:#069;font-weight:bold">class&lt;/span> &lt;span style="color:#0a8;font-weight:bold">CreateRequest&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#078;font-weight:bold">byte&lt;/span>&lt;span style="color:#555">[]&lt;/span> key&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#078;font-weight:bold">byte&lt;/span>&lt;span style="color:#555">[]&lt;/span> value&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">static&lt;/span> &lt;span style="color:#069;font-weight:bold">final&lt;/span> &lt;span style="color:#069;font-weight:bold">class&lt;/span> &lt;span style="color:#0a8;font-weight:bold">CreateResponse&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">static&lt;/span> &lt;span style="color:#069;font-weight:bold">final&lt;/span> &lt;span style="color:#069;font-weight:bold">class&lt;/span> &lt;span style="color:#0a8;font-weight:bold">RetrieveRequest&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#078;font-weight:bold">byte&lt;/span>&lt;span style="color:#555">[]&lt;/span> key&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">static&lt;/span> &lt;span style="color:#069;font-weight:bold">final&lt;/span> &lt;span style="color:#069;font-weight:bold">class&lt;/span> &lt;span style="color:#0a8;font-weight:bold">RetrieveResponse&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#078;font-weight:bold">byte&lt;/span>&lt;span style="color:#555">[]&lt;/span> value&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">static&lt;/span> &lt;span style="color:#069;font-weight:bold">final&lt;/span> &lt;span style="color:#069;font-weight:bold">class&lt;/span> &lt;span style="color:#0a8;font-weight:bold">UpdateRequest&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#078;font-weight:bold">byte&lt;/span>&lt;span style="color:#555">[]&lt;/span> key&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#078;font-weight:bold">byte&lt;/span>&lt;span style="color:#555">[]&lt;/span> value&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">static&lt;/span> &lt;span style="color:#069;font-weight:bold">final&lt;/span> &lt;span style="color:#069;font-weight:bold">class&lt;/span> &lt;span style="color:#0a8;font-weight:bold">UpdateResponse&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">static&lt;/span> &lt;span style="color:#069;font-weight:bold">final&lt;/span> &lt;span style="color:#069;font-weight:bold">class&lt;/span> &lt;span style="color:#0a8;font-weight:bold">DeleteRequest&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#078;font-weight:bold">byte&lt;/span>&lt;span style="color:#555">[]&lt;/span> key&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">static&lt;/span> &lt;span style="color:#069;font-weight:bold">final&lt;/span> &lt;span style="color:#069;font-weight:bold">class&lt;/span> &lt;span style="color:#0a8;font-weight:bold">DeleteResponse&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Because GSON uses reflection to determine how the fields in our classes map to the serialized JSON, we don&amp;rsquo;t need to annotate the messages.&lt;/p>
&lt;p>Our client and server logic will use the request and response types, but gRPC needs to know how to produce and consume these messages. To do this, we need to implement a &lt;a href="https://grpc.io/grpc-java/javadoc/io/grpc/MethodDescriptor.Marshaller.html" target="_blank" rel="noopener">Marshaller&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. A marshaller knows how to convert from an arbitrary type to an &lt;code>InputStream&lt;/code>, which is then passed down into the gRPC core library. It is also capable of doing the reverse transformation when decoding data from the network. For GSON, here is what the marshaller looks like:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">static&lt;/span> &lt;span style="color:#555">&amp;lt;&lt;/span>T&lt;span style="color:#555">&amp;gt;&lt;/span> Marshaller&lt;span style="color:#555">&amp;lt;&lt;/span>T&lt;span style="color:#555">&amp;gt;&lt;/span> &lt;span style="color:#c0f">marshallerFor&lt;/span>&lt;span style="color:#555">(&lt;/span>Class&lt;span style="color:#555">&amp;lt;&lt;/span>T&lt;span style="color:#555">&amp;gt;&lt;/span> clz&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Gson gson &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> Gson&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">return&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> Marshaller&lt;span style="color:#555">&amp;lt;&lt;/span>T&lt;span style="color:#555">&amp;gt;()&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#99f">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">public&lt;/span> InputStream &lt;span style="color:#c0f">stream&lt;/span>&lt;span style="color:#555">(&lt;/span>T value&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">return&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> ByteArrayInputStream&lt;span style="color:#555">(&lt;/span>gson&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">toJson&lt;/span>&lt;span style="color:#555">(&lt;/span>value&lt;span style="color:#555">,&lt;/span> clz&lt;span style="color:#555">).&lt;/span>&lt;span style="color:#309">getBytes&lt;/span>&lt;span style="color:#555">(&lt;/span>StandardCharsets&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">UTF_8&lt;/span>&lt;span style="color:#555">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#99f">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">public&lt;/span> T &lt;span style="color:#c0f">parse&lt;/span>&lt;span style="color:#555">(&lt;/span>InputStream stream&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">return&lt;/span> gson&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">fromJson&lt;/span>&lt;span style="color:#555">(&lt;/span>&lt;span style="color:#069;font-weight:bold">new&lt;/span> InputStreamReader&lt;span style="color:#555">(&lt;/span>stream&lt;span style="color:#555">,&lt;/span> StandardCharsets&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">UTF_8&lt;/span>&lt;span style="color:#555">),&lt;/span> clz&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">};&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Given a &lt;code>Class&lt;/code> object for a some request or response, this function will produce a marshaller. Using the marshallers, we can compose a full &lt;code>MethodDescriptor&lt;/code> for each of the four CRUD methods. Here is an example of the Method descriptor for &lt;em>Create&lt;/em>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">static&lt;/span> &lt;span style="color:#069;font-weight:bold">final&lt;/span> MethodDescriptor&lt;span style="color:#555">&amp;lt;&lt;/span>CreateRequest&lt;span style="color:#555">,&lt;/span> CreateResponse&lt;span style="color:#555">&amp;gt;&lt;/span> CREATE_METHOD &lt;span style="color:#555">=&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> MethodDescriptor&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">newBuilder&lt;/span>&lt;span style="color:#555">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> marshallerFor&lt;span style="color:#555">(&lt;/span>CreateRequest&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">class&lt;/span>&lt;span style="color:#555">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> marshallerFor&lt;span style="color:#555">(&lt;/span>CreateResponse&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">class&lt;/span>&lt;span style="color:#555">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">setFullMethodName&lt;/span>&lt;span style="color:#555">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> MethodDescriptor&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">generateFullMethodName&lt;/span>&lt;span style="color:#555">(&lt;/span>SERVICE_NAME&lt;span style="color:#555">,&lt;/span> &lt;span style="color:#c30">&amp;#34;Create&amp;#34;&lt;/span>&lt;span style="color:#555">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">setType&lt;/span>&lt;span style="color:#555">(&lt;/span>MethodType&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">UNARY&lt;/span>&lt;span style="color:#555">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">build&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Note that if we were using Protobuf, we would use the existing Protobuf marshaller, and the
&lt;a href="https://github.com/carl-mastrangelo/kvstore/blob/03-nonblocking-server/build/generated/source/proto/main/grpc/io/grpc/examples/proto/KeyValueServiceGrpc.java#L44" target="_blank" rel="noopener">method descriptors&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
would be generated automatically.&lt;/p>
&lt;h2 id="sending-rpcs">Sending RPCs&lt;/h2>
&lt;p>Now that we can marshal JSON requests and responses, we need to update our
&lt;a href="https://github.com/carl-mastrangelo/kvstore/blob/b225d28c7c2f3c356b0f3753384b3329f2ab5911/src/main/java/io/grpc/examples/KvClient.java#L98" target="_blank" rel="noopener">KvClient&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>,
the gRPC client used in the previous post, to use our MethodDescriptors. Additionally, since we won&amp;rsquo;t be using any Protobuf types, the code needs to use &lt;code>ByteBuffer&lt;/code> rather than &lt;code>ByteString&lt;/code>. That said, we can still use the &lt;code>grpc-stub&lt;/code> package on Maven to issue the RPC. Using the &lt;em>Create&lt;/em> method again as an example, here&amp;rsquo;s how to make an RPC:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span> ByteBuffer key &lt;span style="color:#555">=&lt;/span> createRandomKey&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ClientCall&lt;span style="color:#555">&amp;lt;&lt;/span>CreateRequest&lt;span style="color:#555">,&lt;/span> CreateResponse&lt;span style="color:#555">&amp;gt;&lt;/span> call &lt;span style="color:#555">=&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> chan&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">newCall&lt;/span>&lt;span style="color:#555">(&lt;/span>KvGson&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">CREATE_METHOD&lt;/span>&lt;span style="color:#555">,&lt;/span> CallOptions&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">DEFAULT&lt;/span>&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> KvGson&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">CreateRequest&lt;/span> req &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> KvGson&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">CreateRequest&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> req&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">key&lt;/span> &lt;span style="color:#555">=&lt;/span> key&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">array&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> req&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">value&lt;/span> &lt;span style="color:#555">=&lt;/span> randomBytes&lt;span style="color:#555">(&lt;/span>MEAN_VALUE_SIZE&lt;span style="color:#555">).&lt;/span>&lt;span style="color:#309">array&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ListenableFuture&lt;span style="color:#555">&amp;lt;&lt;/span>CreateResponse&lt;span style="color:#555">&amp;gt;&lt;/span> res &lt;span style="color:#555">=&lt;/span> ClientCalls&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">futureUnaryCall&lt;/span>&lt;span style="color:#555">(&lt;/span>call&lt;span style="color:#555">,&lt;/span> req&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// ...
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>As you can see, we create a new &lt;code>ClientCall&lt;/code> object from the &lt;code>MethodDescriptor&lt;/code>, create the request, and then send it using &lt;code>ClientCalls.futureUnaryCall&lt;/code> in the stub library. gRPC takes care of the rest for us. You can also make blocking stubs or async stubs instead of future stubs.&lt;/p>
&lt;h2 id="receiving-rpcs">Receiving RPCs&lt;/h2>
&lt;p>To update the server, we need to create a key-value service and implementation. Recall that in gRPC, a &lt;em>Server&lt;/em> can handle one or more &lt;em>Services&lt;/em>. Again, what Protobuf would normally have generated for us we need to write ourselves. Here is what the base service looks like:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">static&lt;/span> &lt;span style="color:#069;font-weight:bold">abstract&lt;/span> &lt;span style="color:#069;font-weight:bold">class&lt;/span> &lt;span style="color:#0a8;font-weight:bold">KeyValueServiceImplBase&lt;/span> &lt;span style="color:#069;font-weight:bold">implements&lt;/span> BindableService &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#069;font-weight:bold">abstract&lt;/span> &lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">create&lt;/span>&lt;span style="color:#555">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> KvGson&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">CreateRequest&lt;/span> request&lt;span style="color:#555">,&lt;/span> StreamObserver&lt;span style="color:#555">&amp;lt;&lt;/span>CreateResponse&lt;span style="color:#555">&amp;gt;&lt;/span> responseObserver&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#069;font-weight:bold">abstract&lt;/span> &lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">retrieve&lt;/span>&lt;span style="color:#555">(&lt;/span>&lt;span style="color:#09f;font-style:italic">/*...*/&lt;/span>&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#069;font-weight:bold">abstract&lt;/span> &lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">update&lt;/span>&lt;span style="color:#555">(&lt;/span>&lt;span style="color:#09f;font-style:italic">/*...*/&lt;/span>&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#069;font-weight:bold">abstract&lt;/span> &lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">delete&lt;/span>&lt;span style="color:#555">(&lt;/span>&lt;span style="color:#09f;font-style:italic">/*...*/&lt;/span>&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">/* Called by the Server to wire up methods to the handlers */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#99f">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#069;font-weight:bold">final&lt;/span> ServerServiceDefinition &lt;span style="color:#c0f">bindService&lt;/span>&lt;span style="color:#555">()&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ServerServiceDefinition&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">Builder&lt;/span> ssd &lt;span style="color:#555">=&lt;/span> ServerServiceDefinition&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">builder&lt;/span>&lt;span style="color:#555">(&lt;/span>SERVICE_NAME&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ssd&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">addMethod&lt;/span>&lt;span style="color:#555">(&lt;/span>CREATE_METHOD&lt;span style="color:#555">,&lt;/span> ServerCalls&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">asyncUnaryCall&lt;/span>&lt;span style="color:#555">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">(&lt;/span>request&lt;span style="color:#555">,&lt;/span> responseObserver&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">-&amp;gt;&lt;/span> create&lt;span style="color:#555">(&lt;/span>request&lt;span style="color:#555">,&lt;/span> responseObserver&lt;span style="color:#555">)));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ssd&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">addMethod&lt;/span>&lt;span style="color:#555">(&lt;/span>RETRIEVE_METHOD&lt;span style="color:#555">,&lt;/span> &lt;span style="color:#09f;font-style:italic">/*...*/&lt;/span>&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ssd&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">addMethod&lt;/span>&lt;span style="color:#555">(&lt;/span>UPDATE_METHOD&lt;span style="color:#555">,&lt;/span> &lt;span style="color:#09f;font-style:italic">/*...*/&lt;/span>&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ssd&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">addMethod&lt;/span>&lt;span style="color:#555">(&lt;/span>DELETE_METHOD&lt;span style="color:#555">,&lt;/span> &lt;span style="color:#09f;font-style:italic">/*...*/&lt;/span>&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">return&lt;/span> ssd&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">build&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>KeyValueServiceImplBase&lt;/code> will serve as both the service definition (which describes which methods the server can handle) and as the implementation (which describes what to do for each method). It serves as the glue between gRPC and our application logic. Practically no changes are needed to swap from Proto to GSON in the server code:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">final&lt;/span> &lt;span style="color:#069;font-weight:bold">class&lt;/span> &lt;span style="color:#0a8;font-weight:bold">KvService&lt;/span> &lt;span style="color:#069;font-weight:bold">extends&lt;/span> KvGson&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">KeyValueServiceImplBase&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#99f">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">create&lt;/span>&lt;span style="color:#555">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> KvGson&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">CreateRequest&lt;/span> request&lt;span style="color:#555">,&lt;/span> StreamObserver&lt;span style="color:#555">&amp;lt;&lt;/span>KvGson&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">CreateResponse&lt;/span>&lt;span style="color:#555">&amp;gt;&lt;/span> responseObserver&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ByteBuffer key &lt;span style="color:#555">=&lt;/span> ByteBuffer&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">wrap&lt;/span>&lt;span style="color:#555">(&lt;/span>request&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">key&lt;/span>&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ByteBuffer value &lt;span style="color:#555">=&lt;/span> ByteBuffer&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">wrap&lt;/span>&lt;span style="color:#555">(&lt;/span>request&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">value&lt;/span>&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// ...
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>After implementing all the methods on the server, we now have a fully functioning gRPC Java, JSON encoding RPC system. And to show you there is nothing up my sleeve:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>./gradlew :dependencies | grep -i proto
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"># no proto deps!&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="optimizing-the-code">Optimizing the Code&lt;/h2>
&lt;p>While Gson is not as fast as Protobuf, there&amp;rsquo;s no sense in not picking the low hanging fruit. Running the code we see the performance is pretty slow:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>./gradlew installDist
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#366">time&lt;/span> ./build/install/kvstore/bin/kvstore
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>INFO: Did 215.883 RPCs/s
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>What happened? In the previous &lt;a href="https://grpc.io/blog/optimizing-grpc-part-2/">optimization&lt;/a> post, we saw the Protobuf version do nearly &lt;em>2,500 RPCs/s&lt;/em>. JSON is slow, but not &lt;em>that&lt;/em> slow. We can see what the problem is by printing out the JSON data as it goes through the marshaller:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>{&lt;span style="color:#309;font-weight:bold">&amp;#34;key&amp;#34;&lt;/span>:[&lt;span style="color:#f60">4&lt;/span>,&lt;span style="color:#f60">-100&lt;/span>,&lt;span style="color:#f60">-48&lt;/span>,&lt;span style="color:#f60">22&lt;/span>,&lt;span style="color:#f60">-128&lt;/span>,&lt;span style="color:#f60">85&lt;/span>,&lt;span style="color:#f60">115&lt;/span>,&lt;span style="color:#f60">5&lt;/span>,&lt;span style="color:#f60">56&lt;/span>,&lt;span style="color:#f60">34&lt;/span>,&lt;span style="color:#f60">-48&lt;/span>,&lt;span style="color:#f60">-1&lt;/span>,&lt;span style="color:#f60">-119&lt;/span>,&lt;span style="color:#f60">60&lt;/span>,&lt;span style="color:#f60">17&lt;/span>,&lt;span style="color:#f60">-13&lt;/span>,&lt;span style="color:#f60">-118&lt;/span>]}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>That&amp;rsquo;s not right! Looking at a &lt;code>RetrieveRequest&lt;/code>, we see that the key bytes are being encoded as an array, rather than as a byte string. The wire size is much larger than it needs to be, and may not be compatible with other JSON code. To fix this, let&amp;rsquo;s tell GSON to encode and decode this data as base64 encoded bytes:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">private&lt;/span> &lt;span style="color:#069;font-weight:bold">static&lt;/span> &lt;span style="color:#069;font-weight:bold">final&lt;/span> Gson gson &lt;span style="color:#555">=&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> GsonBuilder&lt;span style="color:#555">().&lt;/span>&lt;span style="color:#309">registerTypeAdapter&lt;/span>&lt;span style="color:#555">(&lt;/span>&lt;span style="color:#078;font-weight:bold">byte&lt;/span>&lt;span style="color:#555">[].&lt;/span>&lt;span style="color:#309">class&lt;/span>&lt;span style="color:#555">,&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> TypeAdapter&lt;span style="color:#555">&amp;lt;&lt;/span>&lt;span style="color:#078;font-weight:bold">byte&lt;/span>&lt;span style="color:#555">[]&amp;gt;()&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#99f">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">write&lt;/span>&lt;span style="color:#555">(&lt;/span>JsonWriter out&lt;span style="color:#555">,&lt;/span> &lt;span style="color:#078;font-weight:bold">byte&lt;/span>&lt;span style="color:#555">[]&lt;/span> value&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#069;font-weight:bold">throws&lt;/span> IOException &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> out&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">value&lt;/span>&lt;span style="color:#555">(&lt;/span>Base64&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">getEncoder&lt;/span>&lt;span style="color:#555">().&lt;/span>&lt;span style="color:#309">encodeToString&lt;/span>&lt;span style="color:#555">(&lt;/span>value&lt;span style="color:#555">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#99f">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#078;font-weight:bold">byte&lt;/span>&lt;span style="color:#555">[]&lt;/span> &lt;span style="color:#c0f">read&lt;/span>&lt;span style="color:#555">(&lt;/span>JsonReader in&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#069;font-weight:bold">throws&lt;/span> IOException &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">return&lt;/span> Base64&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">getDecoder&lt;/span>&lt;span style="color:#555">().&lt;/span>&lt;span style="color:#309">decode&lt;/span>&lt;span style="color:#555">(&lt;/span>in&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">nextString&lt;/span>&lt;span style="color:#555">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}).&lt;/span>&lt;span style="color:#309">create&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Using this in our marshallers, we can see a dramatic performance difference:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>./gradlew installDist
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#366">time&lt;/span> ./build/install/kvstore/bin/kvstore
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>INFO: Did 2,202.2 RPCs/s
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Almost &lt;strong>10x&lt;/strong> faster than before! We can still take advantage of gRPC&amp;rsquo;s efficiency while bringing our own encoders and messages.&lt;/p>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>gRPC lets you use encoders other than Protobuf. It has no dependency on Protobuf and was specially made to work with a wide variety of environments. We can see that with a little extra boilerplate, we can use any encoder we want. While this post only covered JSON, gRPC is compatible with Thrift, Avro, Flatbuffers, Cap’n Proto, and even raw bytes! gRPC lets you be in control of how your data is handled. (We still recommend Protobuf though due to strong backwards compatibility, type checking, and performance it gives you.)&lt;/p>
&lt;p>All the code is available on &lt;a href="https://github.com/carl-mastrangelo/kvstore/tree/04-gson-marshaller" target="_blank" rel="noopener">GitHub&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> if you would like to see a fully working implementation.&lt;/p></description></item><item><title>Blog: Take the gRPC Survey!</title><link>https://grpc.io/blog/take-the-grpc-survey/</link><pubDate>Tue, 14 Aug 2018 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/take-the-grpc-survey/</guid><description>
&lt;h2 id="the-grpc-project-wants-your-feedback">The gRPC Project wants your feedback!&lt;/h2>
&lt;p>The gRPC project is looking for feedback to improve the gRPC experience. To do this, we are running a &lt;a href="http://bit.ly/gRPC18survey" target="_blank" rel="noopener">gRPC user survey&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. We invite you to participate and provide input that will help us better plan and prioritize.&lt;/p>
&lt;h2 id="grpc-user-survey">gRPC User Survey&lt;/h2>
&lt;p>&lt;strong>Who&lt;/strong> : If you currently use gRPC, have used gRPC in the past, or have any interest in it, we would love to hear from you.&lt;/p>
&lt;p>&lt;strong>Where&lt;/strong>: Please take this 15 minute survey by Friday, 24th August.&lt;/p>
&lt;p>&lt;strong>Why&lt;/strong>: gRPC is a broadly applicable project with a variety of use cases. We want to use &lt;a href="http://bit.ly/gRPC18survey" target="_blank" rel="noopener">this survey&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> to help us understand what works well, and what needs to be fixed.&lt;/p>
&lt;h2 id="spread-the-word">Spread the word!&lt;/h2>
&lt;p>Please help us spread the word on this survey by posting it on your social networks and sharing with your friends. Every single feedback is precious, and we would like as much of it as possible!&lt;/p>
&lt;p>Survey Short link: &lt;a href="http://bit.ly/gRPC18survey" target="_blank" rel="noopener">http://bit.ly/gRPC18survey&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/p></description></item><item><title>Blog: Gracefully clean up in gRPC JUnit tests</title><link>https://grpc.io/blog/graceful-cleanup-junit-tests/</link><pubDate>Tue, 26 Jun 2018 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/graceful-cleanup-junit-tests/</guid><description>
&lt;p>It is best practice to always clean up gRPC resources such as client channels, servers, and previously attached Contexts whenever they are no longer needed.&lt;/p>
&lt;p>This is even true for JUnit tests, because otherwise leaked resources may not only linger in your machine forever, but also interfere with subsequent tests. A not-so-bad case is that subsequent tests can&amp;rsquo;t pass because of a leaked resource from the previous test. The worst case is that some subsequent tests pass that wouldn&amp;rsquo;t have passed at all if the previously passed test had not leaked a resource.&lt;/p>
&lt;p>So cleanup, cleanup, cleanup&amp;hellip; and fail the test if any cleanup is not successful.&lt;/p>
&lt;p>A typical example is&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#069;font-weight:bold">class&lt;/span> &lt;span style="color:#0a8;font-weight:bold">MyTest&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">private&lt;/span> Server server&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">private&lt;/span> ManagedChannel channel&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#99f">@After&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">tearDown&lt;/span>&lt;span style="color:#555">()&lt;/span> &lt;span style="color:#069;font-weight:bold">throws&lt;/span> InterruptedException &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// assume channel and server are not null
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> channel&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">shutdownNow&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> server&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">shutdownNow&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// fail the test if cleanup is not successful
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#069;font-weight:bold">assert&lt;/span> channel&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">awaitTermination&lt;/span>&lt;span style="color:#555">(&lt;/span>5&lt;span style="color:#555">,&lt;/span> TimeUnit&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">SECONDS&lt;/span>&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">:&lt;/span> &lt;span style="color:#c30">&amp;#34;channel failed to shutdown&amp;#34;&lt;/span>&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">assert&lt;/span> server&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">awaitTermination&lt;/span>&lt;span style="color:#555">(&lt;/span>5&lt;span style="color:#555">,&lt;/span> TimeUnit&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">SECONDS&lt;/span>&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">:&lt;/span> &lt;span style="color:#c30">&amp;#34;server failed to shutdown&amp;#34;&lt;/span>&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>or to be more graceful&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#069;font-weight:bold">class&lt;/span> &lt;span style="color:#0a8;font-weight:bold">MyTest&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">private&lt;/span> Server server&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">private&lt;/span> ManagedChannel channel&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#99f">@After&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">tearDown&lt;/span>&lt;span style="color:#555">()&lt;/span> &lt;span style="color:#069;font-weight:bold">throws&lt;/span> InterruptedException &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// assume channel and server are not null
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> channel&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">shutdown&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> server&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">shutdown&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// fail the test if cannot gracefully shutdown
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#069;font-weight:bold">try&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">assert&lt;/span> channel&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">awaitTermination&lt;/span>&lt;span style="color:#555">(&lt;/span>5&lt;span style="color:#555">,&lt;/span> TimeUnit&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">SECONDS&lt;/span>&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">:&lt;/span> &lt;span style="color:#c30">&amp;#34;channel cannot be gracefully shutdown&amp;#34;&lt;/span>&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">assert&lt;/span> server&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">awaitTermination&lt;/span>&lt;span style="color:#555">(&lt;/span>5&lt;span style="color:#555">,&lt;/span> TimeUnit&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">SECONDS&lt;/span>&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">:&lt;/span> &lt;span style="color:#c30">&amp;#34;server cannot be gracefully shutdown&amp;#34;&lt;/span>&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span> &lt;span style="color:#069;font-weight:bold">finally&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> channel&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">shutdownNow&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> server&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">shutdownNow&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>However, having to add all this to every test so it shuts down gracefully gives you more work to do, as you need to write the shutdown boilerplate by yourself. Because of this, the gRPC testing library has helper rules to make this job less tedious.&lt;/p>
&lt;p>Initially, a JUnit rule &lt;a href="https://github.com/grpc/grpc-java/blob/v1.1.x/testing/src/main/java/io/grpc/testing/GrpcServerRule.java" target="_blank" rel="noopener">&lt;code>GrpcServerRule&lt;/code>&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> was introduced to eliminate the shutdown boilerplate. This rule creates an In-Process server and channel at the beginning of the test, and shuts them down at the end of test automatically. However, users found this rule too restrictive in that it does not support transports other than In-Process transports, multiple channels to the server, custom channel or server builder options, and configuration inside individual test methods.&lt;/p>
&lt;p>A more flexible JUnit rule &lt;a href="https://github.com/grpc/grpc-java/blob/v1.13.x/testing/src/main/java/io/grpc/testing/GrpcCleanupRule.java" target="_blank" rel="noopener">&lt;code>GrpcCleanupRule&lt;/code>&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> was introduced in gRPC release v1.13, which also eliminates the shutdown boilerplate. However unlike &lt;code>GrpcServerRule&lt;/code>, &lt;code>GrpcCleanupRule&lt;/code> does not create any server or channel automatically at all. Users create and start the server by themselves, and create channels by themselves, just as in plain tests. With this rule, users just need to register every resource (channel or server) that needs to be shut down at the end of test, and the rule will then shut them down gracefully automatically.&lt;/p>
&lt;p>You can register resources either before running test methods&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#069;font-weight:bold">class&lt;/span> &lt;span style="color:#0a8;font-weight:bold">MyTest&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#99f">@Rule&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">public&lt;/span> GrpcCleanupRule grpcCleanup &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> GrpcCleanupRule&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">private&lt;/span> String serverName &lt;span style="color:#555">=&lt;/span> InProcessServerBuilder&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">generateName&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">private&lt;/span> Server server &lt;span style="color:#555">=&lt;/span> grpcCleanup&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">register&lt;/span>&lt;span style="color:#555">(&lt;/span>InProcessServerBuilder
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">forName&lt;/span>&lt;span style="color:#555">(&lt;/span>serverName&lt;span style="color:#555">).&lt;/span>&lt;span style="color:#309">directExecutor&lt;/span>&lt;span style="color:#555">().&lt;/span>&lt;span style="color:#309">addService&lt;/span>&lt;span style="color:#555">(&lt;/span>myServiceImpl&lt;span style="color:#555">).&lt;/span>&lt;span style="color:#309">build&lt;/span>&lt;span style="color:#555">().&lt;/span>&lt;span style="color:#309">start&lt;/span>&lt;span style="color:#555">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">private&lt;/span> ManagedChannel channel &lt;span style="color:#555">=&lt;/span> grpcCleanup&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">register&lt;/span>&lt;span style="color:#555">(&lt;/span>InProcessChannelBuilder
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">forName&lt;/span>&lt;span style="color:#555">(&lt;/span>serverName&lt;span style="color:#555">).&lt;/span>&lt;span style="color:#309">directExecutor&lt;/span>&lt;span style="color:#555">().&lt;/span>&lt;span style="color:#309">build&lt;/span>&lt;span style="color:#555">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>or inside each individual test method&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#069;font-weight:bold">class&lt;/span> &lt;span style="color:#0a8;font-weight:bold">MyTest&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#99f">@Rule&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">public&lt;/span> GrpcCleanupRule grpcCleanup &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> GrpcCleanupRule&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">private&lt;/span> String serverName &lt;span style="color:#555">=&lt;/span> InProcessServerBuilder&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">generateName&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">private&lt;/span> InProcessServerBuilder serverBuilder &lt;span style="color:#555">=&lt;/span> InProcessServerBuilder
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">forName&lt;/span>&lt;span style="color:#555">(&lt;/span>serverName&lt;span style="color:#555">).&lt;/span>&lt;span style="color:#309">directExecutor&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">private&lt;/span> InProcessChannelBuilder channelBuilder &lt;span style="color:#555">=&lt;/span> InProcessChannelBuilder
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">forName&lt;/span>&lt;span style="color:#555">(&lt;/span>serverName&lt;span style="color:#555">).&lt;/span>&lt;span style="color:#309">directExecutor&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#99f">@Test&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">testFooBar&lt;/span>&lt;span style="color:#555">()&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> grpcCleanup&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">register&lt;/span>&lt;span style="color:#555">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> serverBuilder&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">addService&lt;/span>&lt;span style="color:#555">(&lt;/span>myServiceImpl&lt;span style="color:#555">).&lt;/span>&lt;span style="color:#309">build&lt;/span>&lt;span style="color:#555">().&lt;/span>&lt;span style="color:#309">start&lt;/span>&lt;span style="color:#555">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ManagedChannel channel &lt;span style="color:#555">=&lt;/span> grpcCleanup&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">register&lt;/span>&lt;span style="color:#555">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> channelBuilder&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">maxInboundMessageSize&lt;/span>&lt;span style="color:#555">(&lt;/span>1024&lt;span style="color:#555">).&lt;/span>&lt;span style="color:#309">build&lt;/span>&lt;span style="color:#555">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now with &lt;a href="https://github.com/grpc/grpc-java/blob/v1.13.x/testing/src/main/java/io/grpc/testing/GrpcCleanupRule.java" target="_blank" rel="noopener">&lt;code>GrpcCleanupRule&lt;/code>&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> you don&amp;rsquo;t need to worry about graceful shutdown of gRPC servers and channels in JUnit test. So try it out and clean up in your tests!&lt;/p></description></item><item><title>Blog: gRPC Meets .NET SDK And Visual Studio: Automatic Codegen On Build</title><link>https://grpc.io/blog/grpc-dotnet-build/</link><pubDate>Tue, 26 Jun 2018 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/grpc-dotnet-build/</guid><description>
&lt;p>As part of Microsoft&amp;rsquo;s move towards its cross-platform .NET offering, they have
greatly simplified the project file format, and allowed a tight integration of
third-party code generators with .NET projects. We are listening, and now proud
to introduce integrated compilation of Protocol Buffer and gRPC service
&lt;code>.proto&lt;/code> files in .NET C# projects starting with the version 1.17 of the
Grpc.Tools NuGet package, now available from Nuget.org.&lt;/p>
&lt;p>You no longer need to use hand-written scripts to generate code from &lt;code>.proto&lt;/code>
files: The .NET build magic handles this for you. The integrated tools locate
the proto compiler and gRPC plugin, standard Protocol Buffer imports, and track
dependencies before invoking the code generators, so that the generated C#
source files are never out of date, at the same time keeping regeneration to
the minimum required. In essence, &lt;code>.proto&lt;/code> files are treated as first-class
sources in a .NET C# project.&lt;/p>
&lt;h2 id="a-walkthrough">A Walkthrough&lt;/h2>
&lt;p>In this blog post, we&amp;rsquo;ll walk through the simplest and probably the most common
scenario of creating a library from &lt;code>.proto&lt;/code> files using the cross-platform
&lt;code>dotnet&lt;/code> command. We will implement essentially a clone of the &lt;code>Greeter&lt;/code>
library, shared by client and server projects in the &lt;a href="https://github.com/grpc/grpc/tree/master/examples/csharp/Helloworld/Greeter" target="_blank" rel="noopener">C# &lt;code>Helloworld&lt;/code> example
directory
&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;h3 id="create-a-new-project">Create a new project&lt;/h3>
&lt;p>Let&amp;rsquo;s start by creating a new library project.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>~/work$ dotnet new classlib -o MyGreeter
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>The template &lt;span style="color:#c30">&amp;#34;Class library&amp;#34;&lt;/span> was created successfully.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/work$ &lt;span style="color:#366">cd&lt;/span> MyGreeter
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/work/MyGreeter$ ls -lF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>total &lt;span style="color:#f60">12&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>-rw-rw-r-- &lt;span style="color:#f60">1&lt;/span> kkm kkm &lt;span style="color:#f60">86&lt;/span> Nov &lt;span style="color:#f60">9&lt;/span> 16:10 Class1.cs
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>-rw-rw-r-- &lt;span style="color:#f60">1&lt;/span> kkm kkm &lt;span style="color:#f60">145&lt;/span> Nov &lt;span style="color:#f60">9&lt;/span> 16:10 MyGreeter.csproj
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>drwxrwxr-x &lt;span style="color:#f60">2&lt;/span> kkm kkm &lt;span style="color:#f60">4096&lt;/span> Nov &lt;span style="color:#f60">9&lt;/span> 16:10 obj/
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Observe that the &lt;code>dotnet new&lt;/code> command has created the file &lt;code>Class1.cs&lt;/code> that
we won&amp;rsquo;t need, so remove it. Also, we need some &lt;code>.proto&lt;/code> files to compile. For
this exercise, we&amp;rsquo;ll copy an example file &lt;a href="https://github.com/grpc/grpc/blob/master/examples/protos/helloworld.proto" target="_blank" rel="noopener">&lt;code>examples/protos/helloworld.proto&lt;/code>
&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
from the gRPC distribution.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>~/work/MyGreeter$ rm Class1.cs
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/work/MyGreeter$ wget -q https://raw.githubusercontent.com/grpc/grpc/master/examples/protos/helloworld.proto
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>(on Windows, use &lt;code>del Class1.cs&lt;/code>, and, if you do not have the wget command,
just &lt;a href="https://raw.githubusercontent.com/grpc/grpc/master/examples/protos/helloworld.proto" target="_blank" rel="noopener">open the above URL
&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
and use a &lt;em>Save As&amp;hellip;&lt;/em> command from your Web browser).&lt;/p>
&lt;p>Next, add required NuGet packages to the project:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>~/work/MyGreeter$ dotnet add package Grpc
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>info : PackageReference &lt;span style="color:#069;font-weight:bold">for&lt;/span> package &lt;span style="color:#c30">&amp;#39;Grpc&amp;#39;&lt;/span> version &lt;span style="color:#c30">&amp;#39;1.17.0&amp;#39;&lt;/span> added to file &lt;span style="color:#c30">&amp;#39;/home/kkm/work/MyGreeter/MyGreeter.csproj&amp;#39;&lt;/span>.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/work/MyGreeter$ dotnet add package Grpc.Tools
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>info : PackageReference &lt;span style="color:#069;font-weight:bold">for&lt;/span> package &lt;span style="color:#c30">&amp;#39;Grpc.Tools&amp;#39;&lt;/span> version &lt;span style="color:#c30">&amp;#39;1.17.0&amp;#39;&lt;/span> added to file &lt;span style="color:#c30">&amp;#39;/home/kkm/work/MyGreeter/MyGreeter.csproj&amp;#39;&lt;/span>.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/work/MyGreeter$ dotnet add package Google.Protobuf
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>info : PackageReference &lt;span style="color:#069;font-weight:bold">for&lt;/span> package &lt;span style="color:#c30">&amp;#39;Google.Protobuf&amp;#39;&lt;/span> version &lt;span style="color:#c30">&amp;#39;3.6.1&amp;#39;&lt;/span> added to file &lt;span style="color:#c30">&amp;#39;/home/kkm/work/MyGreeter/MyGreeter.csproj&amp;#39;&lt;/span>.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="add-proto-files-to-the-project">Add &lt;code>.proto&lt;/code> files to the project&lt;/h3>
&lt;p>&lt;strong>Next comes an important part.&lt;/strong> First of all, by default, a &lt;code>.csproj&lt;/code> project
file automatically finds all &lt;code>.cs&lt;/code> files in its directory, although
&lt;a href="https://docs.microsoft.com/dotnet/core/tools/csproj#recommendation" target="_blank" rel="noopener">Microsoft now recommends suppressing this globbing
behavior&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>,
so we too decided against globbing &lt;code>.proto&lt;/code> files. Thus the &lt;code>.proto&lt;/code>
files must be added to the project explicitly.&lt;/p>
&lt;p>Second of all, it is important to add a property &lt;code>PrivateAssets=&amp;quot;All&amp;quot;&lt;/code> to the
Grpc.Tools package reference, so that it will not be needlessly fetched by the
consumers of your new library. This makes sense, as the package only contains
compilers, code generators and import files, which are not needed outside of
the project where the &lt;code>.proto&lt;/code> files have been compiled. While not strictly
required in this simple walkthrough, it must be your standard practice to do
that always.&lt;/p>
&lt;p>So edit the file &lt;code>MyGreeter.csproj&lt;/code> to add the &lt;code>helloworld.proto&lt;/code> so that it
will be compiled, and the &lt;code>PrivateAssets&lt;/code> property to the Grpc.Tools package
reference. Your resulting project file should now look like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#309;font-weight:bold">&amp;lt;Project&lt;/span> &lt;span style="color:#309">Sdk=&lt;/span>&lt;span style="color:#c30">&amp;#34;Microsoft.NET.Sdk&amp;#34;&lt;/span>&lt;span style="color:#309;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#309;font-weight:bold">&amp;lt;PropertyGroup&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#309;font-weight:bold">&amp;lt;TargetFramework&amp;gt;&lt;/span>netstandard2.0&lt;span style="color:#309;font-weight:bold">&amp;lt;/TargetFramework&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#309;font-weight:bold">&amp;lt;/PropertyGroup&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#309;font-weight:bold">&amp;lt;ItemGroup&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#309;font-weight:bold">&amp;lt;PackageReference&lt;/span> &lt;span style="color:#309">Include=&lt;/span>&lt;span style="color:#c30">&amp;#34;Google.Protobuf&amp;#34;&lt;/span> &lt;span style="color:#309">Version=&lt;/span>&lt;span style="color:#c30">&amp;#34;3.6.1&amp;#34;&lt;/span> &lt;span style="color:#309;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#309;font-weight:bold">&amp;lt;PackageReference&lt;/span> &lt;span style="color:#309">Include=&lt;/span>&lt;span style="color:#c30">&amp;#34;Grpc&amp;#34;&lt;/span> &lt;span style="color:#309">Version=&lt;/span>&lt;span style="color:#c30">&amp;#34;1.17.0&amp;#34;&lt;/span> &lt;span style="color:#309;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">&amp;lt;!-- The Grpc.Tools package generates C# sources from .proto files during
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"> project build, but is not needed by projects using the built library.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"> It&amp;#39;s IMPORTANT to add the &amp;#39;PrivateAssets=&amp;#34;All&amp;#34;&amp;#39; to this reference: --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#309;font-weight:bold">&amp;lt;PackageReference&lt;/span> &lt;span style="color:#309">Include=&lt;/span>&lt;span style="color:#c30">&amp;#34;Grpc.Tools&amp;#34;&lt;/span> &lt;span style="color:#309">Version=&lt;/span>&lt;span style="color:#c30">&amp;#34;1.17.0&amp;#34;&lt;/span> &lt;span style="color:#309">PrivateAssets=&lt;/span>&lt;span style="color:#c30">&amp;#34;All&amp;#34;&lt;/span> &lt;span style="color:#309;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">&amp;lt;!-- Explicitly include our helloworld.proto file by adding this line: --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#309;font-weight:bold">&amp;lt;Protobuf&lt;/span> &lt;span style="color:#309">Include=&lt;/span>&lt;span style="color:#c30">&amp;#34;helloworld.proto&amp;#34;&lt;/span> &lt;span style="color:#309;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#309;font-weight:bold">&amp;lt;/ItemGroup&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#309;font-weight:bold">&amp;lt;/Project&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="build-it">Build it!&lt;/h3>
&lt;p>At this point you can build the project with the &lt;code>dotnet build&lt;/code> command to
compile the &lt;code>.proto&lt;/code> file and the library assembly. For this walkthrough, we&amp;rsquo;ll
add a logging switch &lt;code>-v:n&lt;/code> to the command, so we can see that the command to
compile the &lt;code>helloworld.proto&lt;/code> file was in fact run. You may find it a good
idea to always do that the very first time you compile a project!&lt;/p>
&lt;p>Note that many output lines are omitted below, as the build output is quite
verbose.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>~/work/MyGreeter$ dotnet build -v:n
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Build started 11/9/18 5:33:44 PM.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 1:7&amp;gt;Project &lt;span style="color:#c30">&amp;#34;/home/kkm/work/MyGreeter/MyGreeter.csproj&amp;#34;&lt;/span> on node &lt;span style="color:#f60">1&lt;/span> &lt;span style="color:#555">(&lt;/span>Build target&lt;span style="color:#555">(&lt;/span>s&lt;span style="color:#555">))&lt;/span>.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 1&amp;gt;_Protobuf_CoreCompile:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> /home/kkm/.nuget/packages/grpc.tools/1.17.0/tools/linux_x64/protoc
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --csharp_out&lt;span style="color:#555">=&lt;/span>obj/Debug/netstandard2.0
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --plugin&lt;span style="color:#555">=&lt;/span>protoc-gen-grpc&lt;span style="color:#555">=&lt;/span>/home/kkm/.nuget/packages/grpc.tools/1.17.0/tools/linux_x64/grpc_csharp_plugin
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --grpc_out&lt;span style="color:#555">=&lt;/span>obj/Debug/netstandard2.0 --proto_path&lt;span style="color:#555">=&lt;/span>/home/kkm/.nuget/packages/grpc.tools/1.17.0/build/native/include
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --proto_path&lt;span style="color:#555">=&lt;/span>. --dependency_out&lt;span style="color:#555">=&lt;/span>obj/Debug/netstandard2.0/da39a3ee5e6b4b0d_helloworld.protodep helloworld.proto
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> CoreCompile:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">[&lt;/span> ... skipping long output ... &lt;span style="color:#555">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> MyGreeter -&amp;gt; /home/kkm/work/MyGreeter/bin/Debug/netstandard2.0/MyGreeter.dll
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Build succeeded.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>If at this point you invoke the &lt;code>dotnet build -v:n&lt;/code> command again, &lt;code>protoc&lt;/code>
would not be invoked, and no C# sources would be compiled. But if you change
the &lt;code>helloworld.proto&lt;/code> source, then its outputs will be regenerated and then
recompiled by the C# compiler during the build. This is a regular dependency
tracking behavior that you expect from modifying any source file.&lt;/p>
&lt;p>Of course, you can also add &lt;code>.cs&lt;/code> files to the same project: It is a regular C#
project building a .NET library, after all. This is done in our &lt;a href="https://github.com/grpc/grpc/tree/master/examples/csharp/RouteGuide/RouteGuide" target="_blank" rel="noopener">RouteGuide
&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
example.&lt;/p>
&lt;h3 id="where-are-the-generated-files">Where are the generated files?&lt;/h3>
&lt;p>You may wonder where the proto compiler and gRPC plugin output C# files are. By
default, they are placed in the same directory as other generated files, such
as objects (termed the &amp;ldquo;intermediate output&amp;rdquo; directory in the .NET build
parlance), under the &lt;code>obj/&lt;/code> directory. This is a regular practice of .NET
builds, so that autogenerated files do not clutter the working directory or
accidentally placed under source control. Otherwise, they are accessible to the
tools like the debugger. You can see other autogenerated sources in that
directory, too:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>~/work/MyGreeter$ find obj -name &lt;span style="color:#c30">&amp;#39;*.cs&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>obj/Debug/netstandard2.0/MyGreeter.AssemblyInfo.cs
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>obj/Debug/netstandard2.0/Helloworld.cs
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>obj/Debug/netstandard2.0/HelloworldGrpc.cs
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>(use &lt;code>dir /s obj\*.cs&lt;/code> if you are following this walkthrough from a Windows
command prompt).&lt;/p>
&lt;h2 id="there-is-more-to-it">There Is More To It&lt;/h2>
&lt;p>While the simplest default behavior is adequate in many cases, there are many
ways to fine-tune your &lt;code>.proto&lt;/code> compilation process in a large project. We
encourage you to read the &lt;a href="https://github.com/grpc/grpc/blob/master/src/csharp/BUILD-INTEGRATION.md" target="_blank" rel="noopener">documentation file BUILD-INTEGRATION.md
&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
for available options if you find that the default arrangement does not suit
your workflow. The package also extends the Visual Studio&amp;rsquo;s Properties window,
so you may set some options per file in the Visual Studio interface.&lt;/p>
&lt;p>&amp;ldquo;Classic&amp;rdquo; &lt;code>.csproj&lt;/code> projects and Mono are also supported.&lt;/p>
&lt;h2 id="share-your-experience">Share Your Experience&lt;/h2>
&lt;p>As with any initial release of a complex feature, we are thrilled to receive
your feedback. Did something not work as expected? Do you have a scenario that
is not easy to cover with the new tools? Do you have an idea how to improve the
workflow in general? Please read the documentation carefully, and then &lt;a href="https://github.com/grpc/grpc/issues" target="_blank" rel="noopener">open an
issue&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> in the gRPC code repository on
GitHub. Your feedback is important to determine the future direction for our
build integration work!&lt;/p></description></item><item><title>Blog: gRPC ❤ Kotlin</title><link>https://grpc.io/blog/kotlin-gradle-projects/</link><pubDate>Tue, 19 Jun 2018 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/kotlin-gradle-projects/</guid><description>
&lt;p>Did you know that gRPC Java now has out of box support for Kotlin projects built with Gradle? &lt;a href="https://kotlinlang.org/" target="_blank" rel="noopener">Kotlin&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> is a modern, statically typed language developed by JetBrains that targets the JVM and Android. It is generally easy for Kotlin programs to interoperate with existing Java libraries. To improve this experience further, we have added support to the &lt;a href="https://github.com/google/protobuf-gradle-plugin/releases" target="_blank" rel="noopener">protobuf-gradle-plugin&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> so that the generated Java libraries are automatically picked up by Kotlin. You can now add the protobuf-gradle-plugin to your Kotlin project, and use gRPC just like you would with a typical Java project.&lt;/p>
&lt;div class="alert alert-success" role="alert">
&lt;h4 class="alert-heading">Native Kotlin support&lt;/h4>
Looking for native Kotlin support of gRPC? See &lt;a href="https://grpc.io/blog/kotlin-meet-grpc/">Kotlin, meet gRPC&lt;/a>.
&lt;/div>
&lt;p>The following examples show you how to configure a project for a JVM application and an Android application using Kotlin.&lt;/p>
&lt;h3 id="kotlin-grpc-client-and-server">Kotlin gRPC client and server&lt;/h3>
&lt;p>The full example can be found &lt;a href="https://github.com/grpc/grpc-java/tree/v1.29.0/examples/example-kotlin" target="_blank" rel="noopener">here&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;p>Configuring gRPC for a Kotlin project is the same as configuring it for a Java project.&lt;/p>
&lt;p>Below is a snippet of the example project&amp;rsquo;s &lt;code>build.gradle&lt;/code> highlighting some Kotlin related sections:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-groovy" data-lang="groovy">&lt;span style="display:flex;">&lt;span>apply &lt;span style="color:#99f">plugin:&lt;/span> &lt;span style="color:#c30">&amp;#39;kotlin&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>apply &lt;span style="color:#99f">plugin:&lt;/span> &lt;span style="color:#c30">&amp;#39;com.google.protobuf&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// Generate IntelliJ IDEA&amp;#39;s .idea &amp;amp; .iml project files.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// protobuf-gradle-plugin automatically registers *.proto and the gen output files
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// to IntelliJ as sources.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// For best results, install the Protobuf and Kotlin plugins for IntelliJ.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>apply &lt;span style="color:#99f">plugin:&lt;/span> &lt;span style="color:#c30">&amp;#39;idea&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>buildscript &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ext&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">kotlin_version&lt;/span> &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#c30">&amp;#39;1.2.21&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> repositories &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> mavenCentral&lt;span style="color:#555">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> dependencies &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> classpath &lt;span style="color:#c30">&amp;#39;com.google.protobuf:protobuf-gradle-plugin:0.8.5&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> classpath &lt;span style="color:#c30">&amp;#34;org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>dependencies &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> compile &lt;span style="color:#c30">&amp;#34;org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// The rest of the projects dep are added below, refer to example URL
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// The standard protobuf block, same as normal gRPC Java projects
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>protobuf &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> protoc &lt;span style="color:#555">{&lt;/span> artifact &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#c30">&amp;#39;com.google.protobuf:protoc:3.5.1-1&amp;#39;&lt;/span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> plugins &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> grpc &lt;span style="color:#555">{&lt;/span> artifact &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#c30">&amp;#34;io.grpc:protoc-gen-grpc-java:${grpcVersion}&amp;#34;&lt;/span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> generateProtoTasks &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> all&lt;span style="color:#555">()*.&lt;/span>&lt;span style="color:#309">plugins&lt;/span> &lt;span style="color:#555">{&lt;/span> grpc &lt;span style="color:#555">{}&lt;/span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now Kotlin source files can use the proto generated messages and gRPC stubs. By default, Kotlin sources should be placed in &lt;code>src/main/kotlin&lt;/code> and &lt;code>src/test/kotlin&lt;/code>. If needed, run &lt;code>./gradlew generateProto generateTestProto&lt;/code> and refresh IntelliJ for the generated sources to appear in the IDE. Finally, run &lt;code>./gradlew installDist&lt;/code> to build the project, and use &lt;code>./build/install/examples/bin/hello-world-client&lt;/code> or &lt;code>./build/install/examples/bin/hello-world-server&lt;/code> to run the example.&lt;/p>
&lt;p>You can read more about configuring Kotlin &lt;a href="https://kotlinlang.org/docs/reference/using-gradle.html" target="_blank" rel="noopener">here&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;h3 id="kotlin-android-grpc-application">Kotlin Android gRPC application&lt;/h3>
&lt;p>The full example can be found &lt;a href="https://github.com/grpc/grpc-java/tree/v1.29.0/examples/example-kotlin/android/helloworld" target="_blank" rel="noopener">here&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;p>Configuring gRPC for a Kotlin Android project is the same as configuring it for a normal Android project.&lt;/p>
&lt;p>In the top level &lt;code>build.gradle&lt;/code> file:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-groovy" data-lang="groovy">&lt;span style="display:flex;">&lt;span>buildscript &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ext&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">kotlin_version&lt;/span> &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#c30">&amp;#39;1.2.21&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> repositories &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> google&lt;span style="color:#555">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> jcenter&lt;span style="color:#555">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> dependencies &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> classpath &lt;span style="color:#c30">&amp;#39;com.android.tools.build:gradle:3.0.1&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> classpath &lt;span style="color:#c30">&amp;#34;com.google.protobuf:protobuf-gradle-plugin:0.8.5&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> classpath &lt;span style="color:#c30">&amp;#34;org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>allprojects &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> repositories &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> google&lt;span style="color:#555">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> jcenter&lt;span style="color:#555">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And in the app module&amp;rsquo;s &lt;code>build.gradle&lt;/code> file:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-groovy" data-lang="groovy">&lt;span style="display:flex;">&lt;span>apply &lt;span style="color:#99f">plugin:&lt;/span> &lt;span style="color:#c30">&amp;#39;com.android.application&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>apply &lt;span style="color:#99f">plugin:&lt;/span> &lt;span style="color:#c30">&amp;#39;kotlin-android&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>apply &lt;span style="color:#99f">plugin:&lt;/span> &lt;span style="color:#c30">&amp;#39;kotlin-android-extensions&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>apply &lt;span style="color:#99f">plugin:&lt;/span> &lt;span style="color:#c30">&amp;#39;com.google.protobuf&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>repositories &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> mavenCentral&lt;span style="color:#555">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>dependencies &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> compile &lt;span style="color:#c30">&amp;#34;org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// refer to full example for remaining deps
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>protobuf &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// The normal gRPC configuration for Android goes here
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>android &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// Android Studio 3.1 does not automatically pick up &amp;#39;src/main/kotlin&amp;#39; as source files
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> sourceSets &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> main&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">java&lt;/span>&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">srcDirs&lt;/span> &lt;span style="color:#555">+=&lt;/span> &lt;span style="color:#c30">&amp;#39;src/main/kotlin&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Just like the non-Android project, run &lt;code>./gradlew generateProto generateProto&lt;/code> to run the proto code generator and &lt;code>./gradlew build&lt;/code> to build the project.&lt;/p>
&lt;p>Finally, test out the Android app by opening the project in Android Studio and selecting &lt;code>Run &amp;gt; Run 'app'&lt;/code>.&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/kotlin-project-android-app.png" alt="Kotlin Android app example" id="kotlin-project-android-app" data-toggle="modal" data-target="#modal-kotlin-project-android-app"/>
&lt;div class="modal" id="modal-kotlin-project-android-app">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/kotlin-project-android-app.png" alt="Kotlin Android app example"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>We are excited about improving the gRPC experience for Kotlin developers. Please add enhancement ideas or bugs to the &lt;a href="https://github.com/google/protobuf-gradle-plugin/issues" target="_blank" rel="noopener">protobuf-gradle-plugin issue tracker&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> or the &lt;a href="https://github.com/grpc/grpc-java/issues" target="_blank" rel="noopener">grpc-java issue tracker&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p></description></item><item><title>Blog: So You Want to Optimize gRPC - Part 2</title><link>https://grpc.io/blog/optimizing-grpc-part-2/</link><pubDate>Mon, 16 Apr 2018 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/optimizing-grpc-part-2/</guid><description>
&lt;p>How fast is gRPC? Pretty fast if you understand how modern clients and servers are built. In
&lt;a href="https://grpc.io/blog/optimizing-grpc-part-1/">part 1&lt;/a>, I showed how to get an easy &lt;strong>60%&lt;/strong> improvement. In this
post I show how to get a &lt;strong>10000%&lt;/strong> improvement.&lt;/p>
&lt;h2 id="setup">Setup&lt;/h2>
&lt;p>As in &lt;a href="https://grpc.io/blog/optimizing-grpc-part-1/">part 1&lt;/a>, we will start with an existing, Java based,
key-value service. The service will offer concurrent access for creating, reading, updating,
and deleting keys and values. All the code can be seen
&lt;a href="https://github.com/carl-mastrangelo/kvstore/tree/03-nonblocking-server" target="_blank" rel="noopener">here&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> if you want to try
it out.&lt;/p>
&lt;h2 id="server-concurrency">Server Concurrency&lt;/h2>
&lt;p>Let&amp;rsquo;s look at the &lt;a href="https://github.com/carl-mastrangelo/kvstore/blob/f422b1b6e7c69f8c07f96ed4ddba64757242352c/src/main/java/io/grpc/examples/KvService.java" target="_blank" rel="noopener">KvService&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
class. This service handles the RPCs sent by the client, making sure that none of them
accidentally corrupt the state of storage. To ensure this, the service uses the &lt;code>synchronized&lt;/code>
keyword to ensure only one RPC is active at a time:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">private&lt;/span> &lt;span style="color:#069;font-weight:bold">final&lt;/span> Map&lt;span style="color:#555">&amp;lt;&lt;/span>ByteBuffer&lt;span style="color:#555">,&lt;/span> ByteBuffer&lt;span style="color:#555">&amp;gt;&lt;/span> store &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> HashMap&lt;span style="color:#555">&amp;lt;&amp;gt;();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#99f">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#069;font-weight:bold">synchronized&lt;/span> &lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">create&lt;/span>&lt;span style="color:#555">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> CreateRequest request&lt;span style="color:#555">,&lt;/span> StreamObserver&lt;span style="color:#555">&amp;lt;&lt;/span>CreateResponse&lt;span style="color:#555">&amp;gt;&lt;/span> responseObserver&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ByteBuffer key &lt;span style="color:#555">=&lt;/span> request&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">getKey&lt;/span>&lt;span style="color:#555">().&lt;/span>&lt;span style="color:#309">asReadOnlyByteBuffer&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ByteBuffer value &lt;span style="color:#555">=&lt;/span> request&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">getValue&lt;/span>&lt;span style="color:#555">().&lt;/span>&lt;span style="color:#309">asReadOnlyByteBuffer&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> simulateWork&lt;span style="color:#555">(&lt;/span>WRITE_DELAY_MILLIS&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">if&lt;/span> &lt;span style="color:#555">(&lt;/span>store&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">putIfAbsent&lt;/span>&lt;span style="color:#555">(&lt;/span>key&lt;span style="color:#555">,&lt;/span> value&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">==&lt;/span> &lt;span style="color:#069;font-weight:bold">null&lt;/span>&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> responseObserver&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">onNext&lt;/span>&lt;span style="color:#555">(&lt;/span>CreateResponse&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">getDefaultInstance&lt;/span>&lt;span style="color:#555">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> responseObserver&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">onCompleted&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">return&lt;/span>&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> responseObserver&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">onError&lt;/span>&lt;span style="color:#555">(&lt;/span>Status&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">ALREADY_EXISTS&lt;/span>&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">asRuntimeException&lt;/span>&lt;span style="color:#555">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>While this code is thread safe, it comes at a high price: only one RPC can ever be active! We
need some way of allowing multiple operations to happen safely at the same time. Otherwise,
the program can&amp;rsquo;t take advantage of all the available processors.&lt;/p>
&lt;h3 id="breaking-the-lock">Breaking the Lock&lt;/h3>
&lt;p>To solve this, we need to know a little more about the &lt;em>semantics&lt;/em> of our RPCs. The more we know
about how the RPCs are supposed to work, the more optimizations we can make. For a key-value
service, we notice that &lt;em>operations to different keys don&amp;rsquo;t interfere with each other&lt;/em>. When
we update key &amp;lsquo;foo&amp;rsquo;, it has no bearing on the value stored for key &amp;lsquo;bar&amp;rsquo;. But, our server is
written such that operations to any key must be synchronized with respect to each other. If we
could make operations to different keys happen concurrently, our server could handle a lot more
load.&lt;/p>
&lt;p>With the idea in place, we need to figure out how to modify the server. The
&lt;code>synchronized&lt;/code> keyword causes Java to acquire a lock on &lt;code>this&lt;/code>, which is the instance of
&lt;code>KvService&lt;/code>. The lock is acquired when the &lt;code>create&lt;/code> method is entered, and released on return.
The reason we need synchronization is to protect the &lt;code>store&lt;/code> Map. Since it is implemented as a
&lt;a href="https://en.wikipedia.org/wiki/Hash_table" target="_blank" rel="noopener">HashMap&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, modifications to it change the internal
arrays. Because the internal state of the &lt;code>HashMap&lt;/code> will be corrupted if not properly
synchronized, we can&amp;rsquo;t just remove the synchronization on the method.&lt;/p>
&lt;p>However, Java offers a solution here: &lt;code>ConcurrentHashMap&lt;/code>. This class offers the ability to
safely access the contents of the map concurrently. For example, in our usage we want to check
if a key is present. If not present, we want to add it, else we want to return an error. The
&lt;code>putIfAbsent&lt;/code> method atomically checks if a value is present, adds it if not, and tells us if
it succeeded.&lt;/p>
&lt;p>Concurrent maps provide stronger guarantees about the safety of &lt;code>putIfAbsent&lt;/code>, so we can swap the
&lt;code>HashMap&lt;/code> to a &lt;code>ConcurrentHashMap&lt;/code> and remove &lt;code>synchronized&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">private&lt;/span> &lt;span style="color:#069;font-weight:bold">final&lt;/span> ConcurrentMap&lt;span style="color:#555">&amp;lt;&lt;/span>ByteBuffer&lt;span style="color:#555">,&lt;/span> ByteBuffer&lt;span style="color:#555">&amp;gt;&lt;/span> store &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> ConcurrentHashMap&lt;span style="color:#555">&amp;lt;&amp;gt;();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#99f">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">create&lt;/span>&lt;span style="color:#555">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> CreateRequest request&lt;span style="color:#555">,&lt;/span> StreamObserver&lt;span style="color:#555">&amp;lt;&lt;/span>CreateResponse&lt;span style="color:#555">&amp;gt;&lt;/span> responseObserver&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ByteBuffer key &lt;span style="color:#555">=&lt;/span> request&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">getKey&lt;/span>&lt;span style="color:#555">().&lt;/span>&lt;span style="color:#309">asReadOnlyByteBuffer&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ByteBuffer value &lt;span style="color:#555">=&lt;/span> request&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">getValue&lt;/span>&lt;span style="color:#555">().&lt;/span>&lt;span style="color:#309">asReadOnlyByteBuffer&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> simulateWork&lt;span style="color:#555">(&lt;/span>WRITE_DELAY_MILLIS&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">if&lt;/span> &lt;span style="color:#555">(&lt;/span>store&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">putIfAbsent&lt;/span>&lt;span style="color:#555">(&lt;/span>key&lt;span style="color:#555">,&lt;/span> value&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">==&lt;/span> &lt;span style="color:#069;font-weight:bold">null&lt;/span>&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> responseObserver&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">onNext&lt;/span>&lt;span style="color:#555">(&lt;/span>CreateResponse&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">getDefaultInstance&lt;/span>&lt;span style="color:#555">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> responseObserver&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">onCompleted&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">return&lt;/span>&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> responseObserver&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">onError&lt;/span>&lt;span style="color:#555">(&lt;/span>Status&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">ALREADY_EXISTS&lt;/span>&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">asRuntimeException&lt;/span>&lt;span style="color:#555">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="if-at-first-you-dont-succeed">If at First You Don&amp;rsquo;t Succeed&lt;/h3>
&lt;p>Updating &lt;code>create&lt;/code> was pretty easy. Doing the same for &lt;code>retrieve&lt;/code> and &lt;code>delete&lt;/code> is easy too.
However, the &lt;code>update&lt;/code> method is a little trickier. Let&amp;rsquo;s take a look at what it&amp;rsquo;s doing:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#99f">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#069;font-weight:bold">synchronized&lt;/span> &lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">update&lt;/span>&lt;span style="color:#555">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> UpdateRequest request&lt;span style="color:#555">,&lt;/span> StreamObserver&lt;span style="color:#555">&amp;lt;&lt;/span>UpdateResponse&lt;span style="color:#555">&amp;gt;&lt;/span> responseObserver&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ByteBuffer key &lt;span style="color:#555">=&lt;/span> request&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">getKey&lt;/span>&lt;span style="color:#555">().&lt;/span>&lt;span style="color:#309">asReadOnlyByteBuffer&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ByteBuffer newValue &lt;span style="color:#555">=&lt;/span> request&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">getValue&lt;/span>&lt;span style="color:#555">().&lt;/span>&lt;span style="color:#309">asReadOnlyByteBuffer&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> simulateWork&lt;span style="color:#555">(&lt;/span>WRITE_DELAY_MILLIS&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ByteBuffer oldValue &lt;span style="color:#555">=&lt;/span> store&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">get&lt;/span>&lt;span style="color:#555">(&lt;/span>key&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">if&lt;/span> &lt;span style="color:#555">(&lt;/span>oldValue &lt;span style="color:#555">==&lt;/span> &lt;span style="color:#069;font-weight:bold">null&lt;/span>&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> responseObserver&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">onError&lt;/span>&lt;span style="color:#555">(&lt;/span>Status&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">NOT_FOUND&lt;/span>&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">asRuntimeException&lt;/span>&lt;span style="color:#555">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">return&lt;/span>&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> store&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">replace&lt;/span>&lt;span style="color:#555">(&lt;/span>key&lt;span style="color:#555">,&lt;/span> oldValue&lt;span style="color:#555">,&lt;/span> newValue&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> responseObserver&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">onNext&lt;/span>&lt;span style="color:#555">(&lt;/span>UpdateResponse&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">getDefaultInstance&lt;/span>&lt;span style="color:#555">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> responseObserver&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">onCompleted&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Updating a key to a new value needs two interactions with the &lt;code>store&lt;/code>:&lt;/p>
&lt;ol>
&lt;li>Check to see if the key exists at all.&lt;/li>
&lt;li>Update the previous value to the new value.&lt;/li>
&lt;/ol>
&lt;p>Unfortunately &lt;code>ConcurrentMap&lt;/code> doesn&amp;rsquo;t have a straightforward method to do this. Since we may not
be the only ones modifying the map, we need to handle the possibility that our assumptions
have changed. We read the old value out, but by the time we replace it, it may have been deleted.&lt;/p>
&lt;p>To reconcile this, let&amp;rsquo;s retry if &lt;code>replace&lt;/code> fails. It returns true if the replace
was successful. (&lt;code>ConcurrentMap&lt;/code> asserts that the operations will not corrupt the internal
structure, but doesn&amp;rsquo;t say that they will succeed!) We will use a do-while loop:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#99f">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">update&lt;/span>&lt;span style="color:#555">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> UpdateRequest request&lt;span style="color:#555">,&lt;/span> StreamObserver&lt;span style="color:#555">&amp;lt;&lt;/span>UpdateResponse&lt;span style="color:#555">&amp;gt;&lt;/span> responseObserver&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// ...
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> ByteBuffer oldValue&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">do&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> oldValue &lt;span style="color:#555">=&lt;/span> store&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">get&lt;/span>&lt;span style="color:#555">(&lt;/span>key&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">if&lt;/span> &lt;span style="color:#555">(&lt;/span>oldValue &lt;span style="color:#555">==&lt;/span> &lt;span style="color:#069;font-weight:bold">null&lt;/span>&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> responseObserver&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">onError&lt;/span>&lt;span style="color:#555">(&lt;/span>Status&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">NOT_FOUND&lt;/span>&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">asRuntimeException&lt;/span>&lt;span style="color:#555">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">return&lt;/span>&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span> &lt;span style="color:#069;font-weight:bold">while&lt;/span> &lt;span style="color:#555">(!&lt;/span>store&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">replace&lt;/span>&lt;span style="color:#555">(&lt;/span>key&lt;span style="color:#555">,&lt;/span> oldValue&lt;span style="color:#555">,&lt;/span> newValue&lt;span style="color:#555">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> responseObserver&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">onNext&lt;/span>&lt;span style="color:#555">(&lt;/span>UpdateResponse&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">getDefaultInstance&lt;/span>&lt;span style="color:#555">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> responseObserver&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">onCompleted&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The code wants to fail if it ever sees null, but never if there is a non-null previous value. One
thing to note is that if &lt;em>another&lt;/em> RPC modifies the value between the &lt;code>store.get()&lt;/code> call and the
&lt;code>store.replace()&lt;/code> call, it will fail. This is a non-fatal error for us, so we will just try again.
Once it has successfully put the new value in, the service can respond back to the user.&lt;/p>
&lt;p>There is one other possibility that could happen: two RPCs could update the same value and
overwrite each other&amp;rsquo;s work. While this may be okay for some applications, it would not be
suitable for APIs that provide transactionality. It is out of scope for this post to show how to
fix this, but be aware it can happen.&lt;/p>
&lt;h2 id="measuring-the-performance">Measuring the Performance&lt;/h2>
&lt;p>In the last post, we modified the client to be asynchronous and use the gRPC ListenableFuture API.
To avoid running out of memory, the client was modified to have at most &lt;strong>100&lt;/strong> active RPCs at a
time. As we now see from the server code, performance was bottlenecked on acquiring locks.
Since we have removed those, we expect to see a 100x improvement. The same amount of work is done
per RPC, but a lot more are happening at the same time. Let&amp;rsquo;s see if our hypothesis holds:&lt;/p>
&lt;p>Before:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>./gradlew installDist
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#366">time&lt;/span> ./build/install/kvstore/bin/kvstore
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Apr 16, &lt;span style="color:#f60">2018&lt;/span> 10:38:42 AM io.grpc.examples.KvRunner runClient
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>INFO: Did 24.067 RPCs/s
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>real 1m0.886s
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>user 0m9.340s
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sys 0m1.660s
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>After:&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-node" data-lang="node">Apr 16, 2018 10:36:48 AM io.grpc.examples.KvRunner runClient
INFO: Did 2,449.8 RPCs/s
real 1m0.968s
user 0m52.184s
sys 0m20.692s
&lt;/code>&lt;/pre>&lt;p>Wow! From 24 RPCs per second to 2,400 RPCs per second. And we didn&amp;rsquo;t have to change our API or
our client. This is why understanding your code and API semantics is important. By exploiting the
properties of the key-value API, namely the independence of operations on different keys, the code
is now much faster.&lt;/p>
&lt;p>One noteworthy artifact of this code is the &lt;code>user&lt;/code> timing in the results. Previously the user time
was only 9 seconds, meaning that the CPU was active only 9 of the 60 seconds the code was running.
Afterwards, the usage went up by more than 5x to 52 seconds. The reason is that more CPU cores are
active. The &lt;code>KvServer&lt;/code> is simulating work by sleeping for a few milliseconds. In a real
application, it would be doing useful work and not have such a dramatic change. Rather than
scaling per the number of RPCs, it would scale per the number of cores. Thus, if your machine had
12 cores, you would expect to see a 12x improvement. Still not bad though!&lt;/p>
&lt;h3 id="more-errors">More Errors&lt;/h3>
&lt;p>If you run this code yourself, you will see a lot more log spam in the form:&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-nocode" data-lang="nocode">Apr 16, 2018 10:38:40 AM io.grpc.examples.KvClient$3 onFailure
INFO: Key not found
io.grpc.StatusRuntimeException: NOT_FOUND
&lt;/code>&lt;/pre>&lt;p>The reason is that the new version of the code makes API level race conditions more apparent.
With 100 times as many RPCs happening, the chance of updates and deletes colliding with each other
is more likely. To solve this we will need to modify the API definition. Stay tuned for the next
post showing how to fix this.&lt;/p>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>There are a lot of opportunities to optimize your gRPC code. To take advantage of these, you
need to understand what your code is doing. This post shows how to convert a lock-based service into
a low-contention, lock-free service. Always make sure to measure before and after your changes.&lt;/p></description></item><item><title>Blog: So You Want to Optimize gRPC - Part 1</title><link>https://grpc.io/blog/optimizing-grpc-part-1/</link><pubDate>Tue, 06 Mar 2018 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/optimizing-grpc-part-1/</guid><description>
&lt;p>A common question with gRPC is how to make it fast. The gRPC library offers users access to high
performance RPCs, but it isn&amp;rsquo;t always clear how to achieve this. Because this question is common
enough I thought I would try to show my thought process when tuning programs.&lt;/p>
&lt;h2 id="setup">Setup&lt;/h2>
&lt;p>Consider a basic key-value service that is used by multiple other programs. The service needs to
be safe for concurrent access in case multiple updates happen at the same time. It needs to be
able to scale up to use the available hardware. Lastly, it needs to be fast. gRPC is a perfect
fit for this type of service; let&amp;rsquo;s look at the best way to implement it.&lt;/p>
&lt;p>For this blog post, I have written an example
&lt;a href="https://github.com/carl-mastrangelo/kvstore" target="_blank" rel="noopener">client and server&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> using gRPC Java. The program is
split into three main classes, and a protobuf file describing the API:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/carl-mastrangelo/kvstore/blob/01-start/src/main/java/io/grpc/examples/KvClient.java" target="_blank" rel="noopener">KvClient&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
is a simulated user of the key value system. It randomly creates, retrieves, updates,
and deletes keys and values. The size of keys and values it uses is also randomly decided
using an &lt;a href="https://en.wikipedia.org/wiki/Exponential_distribution" target="_blank" rel="noopener">exponential distribution&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://github.com/carl-mastrangelo/kvstore/blob/01-start/src/main/java/io/grpc/examples/KvService.java" target="_blank" rel="noopener">KvService&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
is an implementation of the key value service. It is installed by the gRPC Server to handle
the requests issued by the client. To simulate storing the keys and values on disk, it adds
short sleeps while handling the request. Reads and writes will experience a 10 and 50
millisecond delay to make the example act more like a persistent database.&lt;/li>
&lt;li>&lt;a href="https://github.com/carl-mastrangelo/kvstore/blob/01-start/src/main/java/io/grpc/examples/KvRunner.java" target="_blank" rel="noopener">KvRunner&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
orchestrates the interaction between the client and the server. It is the main entry point,
starting both the client and server in process, and waiting for the the client to execute its
work. The runner does work for 60 seconds and then records how many RPCs were completed.&lt;/li>
&lt;li>&lt;a href="https://github.com/carl-mastrangelo/kvstore/blob/01-start/src/main/proto/kvstore.proto" target="_blank" rel="noopener">kvstore.proto&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
is the protocol buffer definition of our service. It describes exactly what clients can expect
from the service. For the sake of simplicity, we will use Create, Retrieve, Update, and Delete
as the operations (commonly known as CRUD). These operations work with keys and values made up
of arbitrary bytes. While they are somewhat REST like, we reserve the right to diverge and
add more complex operations in the future.&lt;/li>
&lt;/ul>
&lt;p>&lt;a href="https://developers.google.com/protocol-buffers/" target="_blank" rel="noopener">Protocol buffers&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> (protos) aren&amp;rsquo;t required to use
gRPC, they are a very convenient way to define service interfaces and generate client and server
code. The generated code acts as glue code between the application logic and the core gRPC
library. We refer to the code called by a gRPC client the &lt;em>stub&lt;/em>.&lt;/p>
&lt;h2 id="starting-point">Starting Point&lt;/h2>
&lt;h3 id="client">Client&lt;/h3>
&lt;p>Now that we know what the program &lt;em>should&lt;/em> do, we can start looking at how the program performs.
As mentioned above, the client makes random RPCs. For example, here is the code that makes the
&lt;a href="https://github.com/carl-mastrangelo/kvstore/blob/f422b1b6e7c69f8c07f96ed4ddba64757242352c/src/main/java/io/grpc/examples/KvClient.java#L80" target="_blank" rel="noopener">creation&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
request:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">private&lt;/span> &lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">doCreate&lt;/span>&lt;span style="color:#555">(&lt;/span>KeyValueServiceBlockingStub stub&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ByteString key &lt;span style="color:#555">=&lt;/span> createRandomKey&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">try&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> CreateResponse res &lt;span style="color:#555">=&lt;/span> stub&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">create&lt;/span>&lt;span style="color:#555">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> CreateRequest&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">newBuilder&lt;/span>&lt;span style="color:#555">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">setKey&lt;/span>&lt;span style="color:#555">(&lt;/span>key&lt;span style="color:#555">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">setValue&lt;/span>&lt;span style="color:#555">(&lt;/span>randomBytes&lt;span style="color:#555">(&lt;/span>MEAN_VALUE_SIZE&lt;span style="color:#555">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">build&lt;/span>&lt;span style="color:#555">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">if&lt;/span> &lt;span style="color:#555">(!&lt;/span>res&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">equals&lt;/span>&lt;span style="color:#555">(&lt;/span>CreateResponse&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">getDefaultInstance&lt;/span>&lt;span style="color:#555">()))&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">throw&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> RuntimeException&lt;span style="color:#555">(&lt;/span>&lt;span style="color:#c30">&amp;#34;Invalid response&amp;#34;&lt;/span>&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span> &lt;span style="color:#069;font-weight:bold">catch&lt;/span> &lt;span style="color:#555">(&lt;/span>StatusRuntimeException e&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">if&lt;/span> &lt;span style="color:#555">(&lt;/span>e&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">getStatus&lt;/span>&lt;span style="color:#555">().&lt;/span>&lt;span style="color:#309">getCode&lt;/span>&lt;span style="color:#555">()&lt;/span> &lt;span style="color:#555">==&lt;/span> Code&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">ALREADY_EXISTS&lt;/span>&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> knownKeys&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">remove&lt;/span>&lt;span style="color:#555">(&lt;/span>key&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> logger&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">log&lt;/span>&lt;span style="color:#555">(&lt;/span>Level&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">INFO&lt;/span>&lt;span style="color:#555">,&lt;/span> &lt;span style="color:#c30">&amp;#34;Key already existed&amp;#34;&lt;/span>&lt;span style="color:#555">,&lt;/span> e&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span> &lt;span style="color:#069;font-weight:bold">else&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">throw&lt;/span> e&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>A random key is created, along with a random value. The request is sent to the server, and the
client waits for the response. When the response is returned, the code checks that it is as
expected, and if not, throws an exception. While the keys are chosen randomly, they need to be
unique, so we need to make sure that each key isn&amp;rsquo;t already in use. To address this, the code
keeps track of keys it has created, so as not to create the same key twice. However, it&amp;rsquo;s
possible that another client already created a particular key, so we log it and move on.
Otherwise, an exception is thrown.&lt;/p>
&lt;p>We use the &lt;strong>blocking&lt;/strong> gRPC API here, which issues a requests and waits for a response.
This is the simplest gRPC stub, but it blocks the thread while running. This means that at most
&lt;strong>one&lt;/strong> RPC can be in progress at a time from the client&amp;rsquo;s point of view.&lt;/p>
&lt;h3 id="server">Server&lt;/h3>
&lt;p>On the server side, the request is received by the
&lt;a href="https://github.com/carl-mastrangelo/kvstore/blob/f422b1b6e7c69f8c07f96ed4ddba64757242352c/src/main/java/io/grpc/examples/KvService.java#L34" target="_blank" rel="noopener">service handler&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">private&lt;/span> &lt;span style="color:#069;font-weight:bold">final&lt;/span> Map&lt;span style="color:#555">&amp;lt;&lt;/span>ByteBuffer&lt;span style="color:#555">,&lt;/span> ByteBuffer&lt;span style="color:#555">&amp;gt;&lt;/span> store &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> HashMap&lt;span style="color:#555">&amp;lt;&amp;gt;();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#99f">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#069;font-weight:bold">synchronized&lt;/span> &lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">create&lt;/span>&lt;span style="color:#555">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> CreateRequest request&lt;span style="color:#555">,&lt;/span> StreamObserver&lt;span style="color:#555">&amp;lt;&lt;/span>CreateResponse&lt;span style="color:#555">&amp;gt;&lt;/span> responseObserver&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ByteBuffer key &lt;span style="color:#555">=&lt;/span> request&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">getKey&lt;/span>&lt;span style="color:#555">().&lt;/span>&lt;span style="color:#309">asReadOnlyByteBuffer&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ByteBuffer value &lt;span style="color:#555">=&lt;/span> request&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">getValue&lt;/span>&lt;span style="color:#555">().&lt;/span>&lt;span style="color:#309">asReadOnlyByteBuffer&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> simulateWork&lt;span style="color:#555">(&lt;/span>WRITE_DELAY_MILLIS&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">if&lt;/span> &lt;span style="color:#555">(&lt;/span>store&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">putIfAbsent&lt;/span>&lt;span style="color:#555">(&lt;/span>key&lt;span style="color:#555">,&lt;/span> value&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">==&lt;/span> &lt;span style="color:#069;font-weight:bold">null&lt;/span>&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> responseObserver&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">onNext&lt;/span>&lt;span style="color:#555">(&lt;/span>CreateResponse&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">getDefaultInstance&lt;/span>&lt;span style="color:#555">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> responseObserver&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">onCompleted&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">return&lt;/span>&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> responseObserver&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">onError&lt;/span>&lt;span style="color:#555">(&lt;/span>Status&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">ALREADY_EXISTS&lt;/span>&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">asRuntimeException&lt;/span>&lt;span style="color:#555">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The service extracts the key and value as &lt;code>ByteBuffer&lt;/code>s from the request. It acquires the lock
on the service itself to make sure concurrent requests don&amp;rsquo;t corrupt the storage. After
simulating the disk access of a write, it stores it in the &lt;code>Map&lt;/code> of keys to values.&lt;/p>
&lt;p>Unlike the client code, the service handler is &lt;strong>non-blocking&lt;/strong>, meaning it doesn&amp;rsquo;t return a
value like a function call would. Instead, it invokes &lt;code>onNext()&lt;/code> on the &lt;code>responseObserver&lt;/code> to
send the response back to the client. Note that this call is also non-blocking, meaning that
the message may not yet have been sent. To indicate we are done with the message, &lt;code>onCompleted()&lt;/code>
is called.&lt;/p>
&lt;h3 id="performance">Performance&lt;/h3>
&lt;p>Since the code is safe and correct, let&amp;rsquo;s see how it performs. For my measurement I&amp;rsquo;m using my
Ubuntu system with a 12 core processor and 32 GB of memory. Let&amp;rsquo;s build and run the code:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>./gradlew installDist
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#366">time&lt;/span> ./build/install/kvstore/bin/kvstore
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Feb 26, &lt;span style="color:#f60">2018&lt;/span> 1:10:07 PM io.grpc.examples.KvRunner runClient
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>INFO: Starting
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Feb 26, &lt;span style="color:#f60">2018&lt;/span> 1:11:07 PM io.grpc.examples.KvRunner runClient
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>INFO: Did 16.55 RPCs/s
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>real 1m0.927s
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>user 0m10.688s
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sys 0m1.456s
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Yikes! For such a powerful machine, it can only do about 16 RPCs per second. It hardly used any
of our CPU, and we don&amp;rsquo;t know how much memory it was using. We need to figure out why it&amp;rsquo;s so
slow.&lt;/p>
&lt;h2 id="optimization">Optimization&lt;/h2>
&lt;h3 id="analysis">Analysis&lt;/h3>
&lt;p>Let&amp;rsquo;s understand what the program is doing before we make any changes. When optimizing, we need
to know where the code is spending its time in order to know what we can optimize. At this early
stage, we don&amp;rsquo;t need profiling tools yet, we can just reason about the program.&lt;/p>
&lt;p>The client is started and serially issues RPCs for about a minute. Each iteration, it &lt;a href="https://github.com/carl-mastrangelo/kvstore/blob/f422b1b6e7c69f8c07f96ed4ddba64757242352c/src/main/java/io/grpc/examples/KvClient.java#L49" target="_blank" rel="noopener">randomly
decides&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
what operation to do:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">doClientWork&lt;/span>&lt;span style="color:#555">(&lt;/span>AtomicBoolean done&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Random random &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> Random&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> KeyValueServiceBlockingStub stub &lt;span style="color:#555">=&lt;/span> KeyValueServiceGrpc&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">newBlockingStub&lt;/span>&lt;span style="color:#555">(&lt;/span>channel&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">while&lt;/span> &lt;span style="color:#555">(!&lt;/span>done&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">get&lt;/span>&lt;span style="color:#555">())&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// Pick a random CRUD action to take.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#078;font-weight:bold">int&lt;/span> command &lt;span style="color:#555">=&lt;/span> random&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">nextInt&lt;/span>&lt;span style="color:#555">(&lt;/span>4&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">if&lt;/span> &lt;span style="color:#555">(&lt;/span>command &lt;span style="color:#555">==&lt;/span> 0&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> doCreate&lt;span style="color:#555">(&lt;/span>stub&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">continue&lt;/span>&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">/* ... */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> rpcCount&lt;span style="color:#555">++;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This means that &lt;strong>at most one RPC can be active at any time&lt;/strong>. Each RPC has to wait for the
previous one to complete. And how long does each RPC take to complete? From reading the server
code, most of the operations are doing a write which takes about 50 milliseconds. At top
efficiency, the most operations this code can do per second is about 20:&lt;/p>
&lt;p>20 queries = 1000ms / (50 ms / query)&lt;/p>
&lt;p>Our code can do about 16 queries in a second, so that seems about right. We can spot check this
assumption by looking at the output of the &lt;code>time&lt;/code> command used to run the code. The server goes
to sleep when running queries in the
&lt;a href="https://github.com/carl-mastrangelo/kvstore/blob/f422b1b6e7c69f8c07f96ed4ddba64757242352c/src/main/java/io/grpc/examples/KvService.java#L88" target="_blank" rel="noopener">simulateWork&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
method. This implies that the program should be mostly idle while waiting for the RPCs to
complete.&lt;/p>
&lt;p>We can confirm this is the case by looking at the &lt;code>real&lt;/code> and &lt;code>user&lt;/code> times of the command above.
They say that the amount of &lt;em>wall clock&lt;/em> time was 1 minute, while the amount of &lt;em>cpu&lt;/em> time
was 10 seconds. My powerful, multicore CPU was only busy 16% of the time. Thus, if we could
get the program to do more work during that time, it seems like we could get more RPCs complete.&lt;/p>
&lt;h3 id="hypothesis">Hypothesis&lt;/h3>
&lt;p>Now we can state clearly what we think is the problem, and propose a solution. One way to speed
up programs is to make sure the CPU is not idling. To do this, we issue work concurrently.&lt;/p>
&lt;p>In gRPC Java, there are three types of stubs: blocking, non-blocking, and listenable future. We
have already seen the blocking stub in the client, and the non-blocking stub in the server. The
listenable future API is a compromise between the two, offering both blocking and non-blocking
like behavior. As long as we don&amp;rsquo;t block a thread waiting for work to complete, we can start
new RPCs without waiting for the old ones to complete.&lt;/p>
&lt;h3 id="experiment">Experiment&lt;/h3>
&lt;p>To test our hypothesis, let&amp;rsquo;s modify the client code to use the listenable future API. This
means that we need to think more about concurrency in our code. For example, when keeping track
of known keys client-side, we need to safely read, modify, and write the keys. We also need to
make sure that in case of an error, we stop making new RPCs (proper error handling will be covered
in a future post). Lastly, we need to update the number of RPCs made concurrently, since the
update could happen in another thread.&lt;/p>
&lt;p>Making all these changes increases the complexity of the code. This is a trade off you will need
to consider when optimizing your code. In general, code simplicity is at odds with optimization.
Java is not known for being terse. That said, the code below is still readable, and program flow
is still roughly from top to bottom in the function. Here is the
&lt;a href="https://github.com/carl-mastrangelo/kvstore/blob/f0113912c01ac4ea48a80bb7a4736ddcb3f21e24/src/main/java/io/grpc/examples/KvClient.java#L92" target="_blank" rel="noopener">doCreate()&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
method revised:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">private&lt;/span> &lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">doCreate&lt;/span>&lt;span style="color:#555">(&lt;/span>KeyValueServiceFutureStub stub&lt;span style="color:#555">,&lt;/span> AtomicReference&lt;span style="color:#555">&amp;lt;&lt;/span>Throwable&lt;span style="color:#555">&amp;gt;&lt;/span> error&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ByteString key &lt;span style="color:#555">=&lt;/span> createRandomKey&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ListenableFuture&lt;span style="color:#555">&amp;lt;&lt;/span>CreateResponse&lt;span style="color:#555">&amp;gt;&lt;/span> res &lt;span style="color:#555">=&lt;/span> stub&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">create&lt;/span>&lt;span style="color:#555">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> CreateRequest&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">newBuilder&lt;/span>&lt;span style="color:#555">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">setKey&lt;/span>&lt;span style="color:#555">(&lt;/span>key&lt;span style="color:#555">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">setValue&lt;/span>&lt;span style="color:#555">(&lt;/span>randomBytes&lt;span style="color:#555">(&lt;/span>MEAN_VALUE_SIZE&lt;span style="color:#555">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">build&lt;/span>&lt;span style="color:#555">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> res&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">addListener&lt;/span>&lt;span style="color:#555">(()&lt;/span> &lt;span style="color:#555">-&amp;gt;&lt;/span> rpcCount&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">incrementAndGet&lt;/span>&lt;span style="color:#555">(),&lt;/span> MoreExecutors&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">directExecutor&lt;/span>&lt;span style="color:#555">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Futures&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">addCallback&lt;/span>&lt;span style="color:#555">(&lt;/span>res&lt;span style="color:#555">,&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> FutureCallback&lt;span style="color:#555">&amp;lt;&lt;/span>CreateResponse&lt;span style="color:#555">&amp;gt;()&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#99f">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">onSuccess&lt;/span>&lt;span style="color:#555">(&lt;/span>CreateResponse result&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">if&lt;/span> &lt;span style="color:#555">(!&lt;/span>result&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">equals&lt;/span>&lt;span style="color:#555">(&lt;/span>CreateResponse&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">getDefaultInstance&lt;/span>&lt;span style="color:#555">()))&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> error&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">compareAndSet&lt;/span>&lt;span style="color:#555">(&lt;/span>&lt;span style="color:#069;font-weight:bold">null&lt;/span>&lt;span style="color:#555">,&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> RuntimeException&lt;span style="color:#555">(&lt;/span>&lt;span style="color:#c30">&amp;#34;Invalid response&amp;#34;&lt;/span>&lt;span style="color:#555">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">synchronized&lt;/span> &lt;span style="color:#555">(&lt;/span>knownKeys&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> knownKeys&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">add&lt;/span>&lt;span style="color:#555">(&lt;/span>key&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#99f">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">onFailure&lt;/span>&lt;span style="color:#555">(&lt;/span>Throwable t&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Status status &lt;span style="color:#555">=&lt;/span> Status&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">fromThrowable&lt;/span>&lt;span style="color:#555">(&lt;/span>t&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">if&lt;/span> &lt;span style="color:#555">(&lt;/span>status&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">getCode&lt;/span>&lt;span style="color:#555">()&lt;/span> &lt;span style="color:#555">==&lt;/span> Code&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">ALREADY_EXISTS&lt;/span>&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">synchronized&lt;/span> &lt;span style="color:#555">(&lt;/span>knownKeys&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> knownKeys&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">remove&lt;/span>&lt;span style="color:#555">(&lt;/span>key&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> logger&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">log&lt;/span>&lt;span style="color:#555">(&lt;/span>Level&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">INFO&lt;/span>&lt;span style="color:#555">,&lt;/span> &lt;span style="color:#c30">&amp;#34;Key already existed&amp;#34;&lt;/span>&lt;span style="color:#555">,&lt;/span> t&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span> &lt;span style="color:#069;font-weight:bold">else&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> error&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">compareAndSet&lt;/span>&lt;span style="color:#555">(&lt;/span>&lt;span style="color:#069;font-weight:bold">null&lt;/span>&lt;span style="color:#555">,&lt;/span> t&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The stub has been modified to be a &lt;code>KeyValueServiceFutureStub&lt;/code>, which produces a &lt;code>Future&lt;/code> when
called instead of the response itself. gRPC Java uses an extension of this called &lt;code>ListenableFuture&lt;/code>,
which allows adding a callback when the future completes. For the sake of this program, we are
not as concerned with getting the response. Instead we care more if the RPC succeeded or not.
With that in mind, the code mainly checks for errors rather than processing the response.&lt;/p>
&lt;p>The first change made is how the number of RPCs is recorded. Instead of incrementing the counter
outside of the main loop, we increment it when the RPC completes.&lt;/p>
&lt;p>Next, we create a new object
for each RPC which handles both the success and failure cases. Because &lt;code>doCreate()&lt;/code> will already
be completed by the time RPC callback is invoked, we need a way to propagate errors other than
by throwing. Instead, we try to update an reference atomically. The main loop will occasionally
check if an error has occurred and stop if there is a problem.&lt;/p>
&lt;p>Lastly, the code is careful to only add a key to &lt;code>knownKeys&lt;/code> when the RPC is actually complete,
and only remove it when known to have failed. We synchronize on the variable to make sure two
threads don&amp;rsquo;t conflict. Note: although the access to &lt;code>knownKeys&lt;/code> is threadsafe, there are still
&lt;a href="https://en.wikipedia.org/wiki/Race_condition" target="_blank" rel="noopener">race conditions&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. It is possible that one thread
could read from &lt;code>knownKeys&lt;/code>, a second thread delete from &lt;code>knownKeys&lt;/code>, and then the first thread
issue an RPC using the first key. Synchronizing on the keys only ensures that it is consistent,
not that it is correct. Fixing this properly is outside of the scope of this post, so instead we
just log the event and move on. You will see a few such log statements if you run this program.&lt;/p>
&lt;h3 id="running-the-code">Running the Code&lt;/h3>
&lt;p>If you start up this program and run it, you&amp;rsquo;ll notice that it doesn&amp;rsquo;t work:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>WARNING: An exception was thrown by io.grpc.netty.NettyClientStream&lt;span style="color:#033">$Sink$1&lt;/span>.operationComplete&lt;span style="color:#555">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>java.lang.OutOfMemoryError: unable to create new native thread
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> at java.lang.Thread.start0&lt;span style="color:#555">(&lt;/span>Native Method&lt;span style="color:#555">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> at java.lang.Thread.start&lt;span style="color:#555">(&lt;/span>Thread.java:714&lt;span style="color:#555">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>What?! Why would I show you code that fails? The reason is that in real life making a change often
doesn&amp;rsquo;t work on the first try. In this case, the program ran out of memory. Odd things begin to
happen when a program runs out of memory. Often, the root cause is hard to find, and red herrings
abound. A confusing error message says &amp;ldquo;unable to create new native thread&amp;rdquo;
even though we didn&amp;rsquo;t create any new threads in our code. Experience is very helpful in fixing
these problems rather than debugging. Since I have debugged many OOMs, I happen to know Java tells
us about the straw that broke the camel&amp;rsquo;s back. Our program started using way more memory, but the
final allocation that failed happened, by chance, to be in thread creation.&lt;/p>
&lt;p>So what happened? &lt;em>There was no pushback to starting new RPCs.&lt;/em> In the blocking version, a new
RPC couldn&amp;rsquo;t start until the last one completed. While slow, it also prevented us from creating
tons of RPCs that we didn&amp;rsquo;t have memory for. We need to account for this in the listenable
future version.&lt;/p>
&lt;p>To solve this, we can apply a self-imposed limit on the number of active RPCs. Before starting a
new RPC, we will try to acquire a permit. If we get one, the RPC can start. If not, we will wait
until one is available. When an RPC completes (either in success or failure), we return the
permit. To &lt;a href="https://github.com/carl-mastrangelo/kvstore/blob/02-future-client/src/main/java/io/grpc/examples/KvClient.java#L94" target="_blank" rel="noopener">accomplish&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
this, we will using a &lt;code>Semaphore&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">private&lt;/span> &lt;span style="color:#069;font-weight:bold">final&lt;/span> Semaphore limiter &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> Semaphore&lt;span style="color:#555">(&lt;/span>100&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">private&lt;/span> &lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">doCreate&lt;/span>&lt;span style="color:#555">(&lt;/span>KeyValueServiceFutureStub stub&lt;span style="color:#555">,&lt;/span> AtomicReference&lt;span style="color:#555">&amp;lt;&lt;/span>Throwable&lt;span style="color:#555">&amp;gt;&lt;/span> error&lt;span style="color:#555">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">throws&lt;/span> InterruptedException &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> limiter&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">acquire&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ByteString key &lt;span style="color:#555">=&lt;/span> createRandomKey&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ListenableFuture&lt;span style="color:#555">&amp;lt;&lt;/span>CreateResponse&lt;span style="color:#555">&amp;gt;&lt;/span> res &lt;span style="color:#555">=&lt;/span> stub&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">create&lt;/span>&lt;span style="color:#555">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> CreateRequest&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">newBuilder&lt;/span>&lt;span style="color:#555">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">setKey&lt;/span>&lt;span style="color:#555">(&lt;/span>key&lt;span style="color:#555">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">setValue&lt;/span>&lt;span style="color:#555">(&lt;/span>randomBytes&lt;span style="color:#555">(&lt;/span>MEAN_VALUE_SIZE&lt;span style="color:#555">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">build&lt;/span>&lt;span style="color:#555">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> res&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">addListener&lt;/span>&lt;span style="color:#555">(()&lt;/span> &lt;span style="color:#555">-&amp;gt;&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> rpcCount&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">incrementAndGet&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> limiter&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">release&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">},&lt;/span> MoreExecutors&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">directExecutor&lt;/span>&lt;span style="color:#555">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">/* ... */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now the code runs successfully, and doesn&amp;rsquo;t run out of memory.&lt;/p>
&lt;h3 id="results">Results&lt;/h3>
&lt;p>Building and running the code again looks a lot better:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>./gradlew installDist
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#366">time&lt;/span> ./build/install/kvstore/bin/kvstore
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Feb 26, &lt;span style="color:#f60">2018&lt;/span> 2:40:47 PM io.grpc.examples.KvRunner runClient
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>INFO: Starting
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Feb 26, &lt;span style="color:#f60">2018&lt;/span> 2:41:47 PM io.grpc.examples.KvRunner runClient
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>INFO: Did 24.283 RPCs/s
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>real 1m0.923s
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>user 0m12.772s
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sys 0m1.572s
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Our code does &lt;strong>46%&lt;/strong> more RPCs per second than previously. We can also see that we used about 20%
more CPU than previously. As we can see our hypothesis turned out to be correct and the fix
worked. All this happened without making any changes to the server. Also, we were able to
measure without using any special profilers or tracers.&lt;/p>
&lt;p>Do the numbers make sense? We expect to issue mutation (create, update, and delete) RPCs each
about with 1/4 probability. Reads are also issue 1/4 of the time, but don&amp;rsquo;t take as long. The
mean RPC time should be about the weighted average RPC time:&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-nocode" data-lang="nocode"> .25 * 50ms (create)
.25 * 10ms (retrieve)
.25 * 50ms (update)
+.25 * 50ms (delete)
------------
40ms
&lt;/code>&lt;/pre>&lt;p>At 40ms on average per RPC, we would expect the number of RPCs per second to be:&lt;/p>
&lt;p>25 queries = 1000ms / (40 ms / query)&lt;/p>
&lt;p>That&amp;rsquo;s approximately what we see with the new code. The server is still serially handling
requests, so it seems like we have more work to do in the future. But for now, our optimizations
seem to have worked.&lt;/p>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>There are a lot of opportunities to optimize your gRPC code. To take advantage of these, you
need to understand what your code is doing, and what your code is supposed to do. This post shows
the very basics of how to approach and think about optimization. Always make sure to measure
before and after your changes, and use these measurements to guide your optimizations.&lt;/p>
&lt;p>In &lt;a href="https://grpc.io/blog/optimizing-grpc-part-2/">Part 2&lt;/a>, we will continue optimizing the server part of the code.&lt;/p></description></item><item><title>Blog: gRPC and Deadlines</title><link>https://grpc.io/blog/deadlines/</link><pubDate>Mon, 26 Feb 2018 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/deadlines/</guid><description>
&lt;p>&lt;strong>TL;DR: Always set a deadline&lt;/strong>. This post explains why we recommend being deliberate about setting deadlines, with useful code snippets to show you how.&lt;/p>
&lt;p>When you use gRPC, the gRPC library takes care of communication, marshalling, unmarshalling, and deadline enforcement. Deadlines allow gRPC clients to specify how long they are willing to wait for an RPC to complete before the RPC is terminated with the error &lt;code>DEADLINE_EXCEEDED&lt;/code>. By default this deadline is a very large number, dependent on the language implementation. How deadlines are specified is also language-dependent. Some language APIs work in terms of a &lt;strong>deadline&lt;/strong>, a fixed point in time by which the RPC should complete. Others use a &lt;strong>timeout&lt;/strong>, a duration of time after which the RPC times out.&lt;/p>
&lt;p>In general, when you don&amp;rsquo;t set a deadline, resources will be held for all in-flight requests, and all requests can potentially reach the maximum timeout. This puts the service at risk of running out of resources, like memory, which would increase the latency of the service, or could crash the entire process in the worst case.&lt;/p>
&lt;p>To avoid this, services should specify the longest default deadline they technically support, and clients should wait until the response is no longer useful to them. For the service this can be as simple as providing a comment in the .proto file. For the client this involves setting useful deadlines.&lt;/p>
&lt;p>There is no single answer to &amp;ldquo;What is a good deadline/timeout value?&amp;rdquo;. Your service might be as simple as the &lt;a href="https://github.com/grpc/grpc/blob/master/examples/protos/helloworld.proto" target="_blank" rel="noopener">Greeter&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> in our quick start guides, in which case 100 ms would be fine. Your service might be as complex as a globally-distributed and strongly consistent database. The deadline for a client query will be different from how long they should wait for you to drop their table.&lt;/p>
&lt;p>So what do you need to consider to make an informed choice of deadline? Factors to take into account include the end to end latency of the whole system, which RPCs are serial, and which can be made in parallel. You should to be able to put numbers on it, even if it&amp;rsquo;s a rough calculation. Engineers need to understand the service and then set a deliberate deadline for the RPCs between clients and servers.&lt;/p>
&lt;p>In gRPC, both the client and server make their own independent and local determination about whether the remote procedure call (RPC) was successful. This means their conclusions may not match! An RPC that finished successfully on the server side can fail on the client side. For example, the server can send the response, but the reply can arrive at the client after their deadline has expired. The client will already have terminated with the status error &lt;code>DEADLINE_EXCEEDED&lt;/code>. This should be checked for and managed at the application level.&lt;/p>
&lt;h2 id="setting-a-deadline">Setting a deadline&lt;/h2>
&lt;p>As a client you should always set a deadline for how long you are willing to
wait for a reply from the server. Here are examples using the Greeting service
from the &lt;a href="https://grpc.io/docs/quickstart/">Quick start&lt;/a> pages:&lt;/p>
&lt;h3 id="c">C++&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cpp" data-lang="cpp">&lt;span style="display:flex;">&lt;span>ClientContext context;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>time_point deadline &lt;span style="color:#555">=&lt;/span> std&lt;span style="color:#555">::&lt;/span>chrono&lt;span style="color:#555">::&lt;/span>system_clock&lt;span style="color:#555">::&lt;/span>now() &lt;span style="color:#555">+&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> std&lt;span style="color:#555">::&lt;/span>chrono&lt;span style="color:#555">::&lt;/span>milliseconds(&lt;span style="color:#f60">100&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>context.set_deadline(deadline);
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="go">Go&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>clientDeadline &lt;span style="color:#555">:=&lt;/span> time.&lt;span style="color:#c0f">Now&lt;/span>().&lt;span style="color:#c0f">Add&lt;/span>(time.&lt;span style="color:#c0f">Duration&lt;/span>(&lt;span style="color:#555">*&lt;/span>deadlineMs) &lt;span style="color:#555">*&lt;/span> time.Millisecond)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ctx, cancel &lt;span style="color:#555">:=&lt;/span> context.&lt;span style="color:#c0f">WithDeadline&lt;/span>(ctx, clientDeadline)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="java">Java&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>response &lt;span style="color:#555">=&lt;/span> blockingStub&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">withDeadlineAfter&lt;/span>&lt;span style="color:#555">(&lt;/span>deadlineMs&lt;span style="color:#555">,&lt;/span> TimeUnit&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">MILLISECONDS&lt;/span>&lt;span style="color:#555">).&lt;/span>&lt;span style="color:#309">sayHello&lt;/span>&lt;span style="color:#555">(&lt;/span>request&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This sets the deadline to 100ms from when the client RPC is set to when the response is picked up by the client.&lt;/p>
&lt;h2 id="checking-deadlines">Checking deadlines&lt;/h2>
&lt;p>On the server side, the server can query to see if a particular RPC is no longer wanted. Before a server starts work on a response it is very important to check if there is still a client waiting for it. This is especially important to do before starting expensive processing.&lt;/p>
&lt;h3 id="c-1">C++&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cpp" data-lang="cpp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">if&lt;/span> (context&lt;span style="color:#555">-&amp;gt;&lt;/span>IsCancelled()) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">return&lt;/span> &lt;span style="color:#c0f">Status&lt;/span>(StatusCode&lt;span style="color:#555">::&lt;/span>CANCELLED, &lt;span style="color:#c30">&amp;#34;Deadline exceeded or Client cancelled, abandoning.&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="go-1">Go&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">if&lt;/span> ctx.&lt;span style="color:#c0f">Err&lt;/span>() &lt;span style="color:#555">==&lt;/span> context.Canceled {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">return&lt;/span> status.&lt;span style="color:#c0f">New&lt;/span>(codes.Canceled, &lt;span style="color:#c30">&amp;#34;Client cancelled, abandoning.&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="java-1">Java&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">if&lt;/span> &lt;span style="color:#555">(&lt;/span>Context&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">current&lt;/span>&lt;span style="color:#555">().&lt;/span>&lt;span style="color:#309">isCancelled&lt;/span>&lt;span style="color:#555">())&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> responseObserver&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">onError&lt;/span>&lt;span style="color:#555">(&lt;/span>Status&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">CANCELLED&lt;/span>&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">withDescription&lt;/span>&lt;span style="color:#555">(&lt;/span>&lt;span style="color:#c30">&amp;#34;Cancelled by client&amp;#34;&lt;/span>&lt;span style="color:#555">).&lt;/span>&lt;span style="color:#309">asRuntimeException&lt;/span>&lt;span style="color:#555">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">return&lt;/span>&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Is it useful for a server to continue with the request, when you know your client has reached their deadline? It depends. If the response can be cached in the server, it can be worth processing and caching it; particularly if it&amp;rsquo;s resource heavy, and costs you money for each request. This will make future requests faster as the result will already be available.&lt;/p>
&lt;h2 id="adjusting-deadlines">Adjusting deadlines&lt;/h2>
&lt;p>What if you set a deadline but a new release or server version causes a bad regression? The deadline could be too small, resulting in all your requests timing out with &lt;code>DEADLINE_EXCEEDED&lt;/code>, or too large and your user tail latency is now massive. You can use a flag to set and adjust the deadline.&lt;/p>
&lt;h3 id="c-2">C++&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cpp" data-lang="cpp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#099">#include&lt;/span> &lt;span style="color:#099">&amp;lt;gflags/gflags.h&amp;gt;&lt;/span>&lt;span style="color:#099">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#099">&lt;/span>DEFINE_int32(deadline_ms, &lt;span style="color:#f60">20&lt;/span>&lt;span style="color:#555">*&lt;/span>&lt;span style="color:#f60">1000&lt;/span>, &lt;span style="color:#c30">&amp;#34;Deadline in milliseconds.&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ClientContext context;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>time_point deadline &lt;span style="color:#555">=&lt;/span> std&lt;span style="color:#555">::&lt;/span>chrono&lt;span style="color:#555">::&lt;/span>system_clock&lt;span style="color:#555">::&lt;/span>now() &lt;span style="color:#555">+&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> std&lt;span style="color:#555">::&lt;/span>chrono&lt;span style="color:#555">::&lt;/span>milliseconds(FLAGS_deadline_ms);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>context.set_deadline(deadline);
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="go-2">Go&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">var&lt;/span> deadlineMs = flag.&lt;span style="color:#c0f">Int&lt;/span>(&lt;span style="color:#c30">&amp;#34;deadline_ms&amp;#34;&lt;/span>, &lt;span style="color:#f60">20&lt;/span>&lt;span style="color:#555">*&lt;/span>&lt;span style="color:#f60">1000&lt;/span>, &lt;span style="color:#c30">&amp;#34;Default deadline in milliseconds.&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ctx, cancel &lt;span style="color:#555">:=&lt;/span> context.&lt;span style="color:#c0f">WithTimeout&lt;/span>(ctx, time.&lt;span style="color:#c0f">Duration&lt;/span>(&lt;span style="color:#555">*&lt;/span>deadlineMs) &lt;span style="color:#555">*&lt;/span> time.Millisecond)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="java-2">Java&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#99f">@Option&lt;/span>&lt;span style="color:#555">(&lt;/span>name&lt;span style="color:#555">=&lt;/span>&lt;span style="color:#c30">&amp;#34;--deadline_ms&amp;#34;&lt;/span>&lt;span style="color:#555">,&lt;/span> usage&lt;span style="color:#555">=&lt;/span>&lt;span style="color:#c30">&amp;#34;Deadline in milliseconds.&amp;#34;&lt;/span>&lt;span style="color:#555">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">private&lt;/span> &lt;span style="color:#078;font-weight:bold">int&lt;/span> deadlineMs &lt;span style="color:#555">=&lt;/span> 20&lt;span style="color:#555">*&lt;/span>1000&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>response &lt;span style="color:#555">=&lt;/span> blockingStub&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">withDeadlineAfter&lt;/span>&lt;span style="color:#555">(&lt;/span>deadlineMs&lt;span style="color:#555">,&lt;/span> TimeUnit&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">MILLISECONDS&lt;/span>&lt;span style="color:#555">).&lt;/span>&lt;span style="color:#309">sayHello&lt;/span>&lt;span style="color:#555">(&lt;/span>request&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now the deadline can be adjusted to wait longer to avoid failing, without the need to cherry-pick a release with a different hard coded deadline. This lets you mitigate the issue for users until the regression can be debugged and resolved.&lt;/p></description></item><item><title>Blog: gRPC-Go Engineering Practices</title><link>https://grpc.io/blog/grpc-go-engineering-practices/</link><pubDate>Mon, 22 Jan 2018 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/grpc-go-engineering-practices/</guid><description>
&lt;p>It&amp;rsquo;s the start of the new year, and almost the end of my first full year on the
gRPC-Go project, so I&amp;rsquo;d like to take this opportunity to provide an update on
the state of gRPC-Go development and give some visibility into how we manage the
project. For me, personally, this is the first open source project to which
I&amp;rsquo;ve meaningfully contributed, so this year has been a learning experience for
me. Over this year, the team has made constant improvements to our work habits
and communication. I still see room for improvement, but I believe we are in a
considerably better place than we were a year ago.&lt;/p>
&lt;h2 id="repo-health">Repo Health&lt;/h2>
&lt;p>When I first joined the gRPC-Go team, they had been without their previous
technical lead for a few months. At that time, we had 45 open PRs, the oldest
of which was over a year old at the time. As a new team member and maintainer,
the accumulation of stale PRs made it difficult to assess priorities and
understand the state of things. For our contributors, neglecting PRs was both
disrespectful and an inconvenience when we started asking for rebases due to
other commits. To resolve this, we made a concerted effort to either merge or
close all of those PRs, and we now hold weekly meetings to review the status of
every active PR to prevent the situation from reoccurring.&lt;/p>
&lt;p>At the same time, we had 103 open issues, many of which were already fixed or
outdated or untriaged. Since then, we fixed or closed 85 of those and put in
place a process to ensure we triage and prioritize new issues on a weekly
rotation. Similarly to our PRs, we also review our assigned and high-priority
issues in a weekly meeting.&lt;/p>
&lt;p>Our ongoing SLO for new issues and PRs is 1 week to triage and first response.&lt;/p>
&lt;p>We also revamped our &lt;a href="https://github.com/grpc/grpc-go/labels" target="_blank" rel="noopener">labels&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> for issues
and PRs to help with organization. We typically apply a priority (P0-P3) and a
type (for example, Bug, Feature, or Performance) to every issue. We also have a
collection of status labels we apply in various situations. The type labels are
also applied to PRs to aid in generating our release notes.&lt;/p>
&lt;h2 id="versioning-and-backward-compatibility">Versioning and Backward Compatibility&lt;/h2>
&lt;p>We have recently documented our &lt;a href="https://github.com/grpc/grpc-go/blob/master/Documentation/versioning.md" target="_blank" rel="noopener">versioning
policy&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.
Our goal is to maintain full backward compatibility except in limited
circumstances, including experimental APIs and mitigating security risks (most
notably &lt;a href="https://github.com/grpc/grpc-go/pull/1392" target="_blank" rel="noopener">#1392&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>). If you notice a
behavior regression, please don&amp;rsquo;t hesitate to &lt;a href="https://github.com/grpc/grpc-go/issues/new" target="_blank" rel="noopener">open an
issue&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> in our repo (please &lt;a href="https://xkcd.com/1172/" target="_blank" rel="noopener">be
reasonable&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>).&lt;/p>
&lt;h2 id="grfc">gRFC&lt;/h2>
&lt;p>The &lt;a href="https://github.com/grpc/proposal" target="_blank" rel="noopener">gRPC proposal repo&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> contains proposals
for substantial feature changes for gRPC that need to be designed upfront,
called gRFCs. The purpose of this process is to provide visibility and solicit
feedback from the community. Each change is discussed on our &lt;a href="https://groups.google.com/g/grpc-io" target="_blank" rel="noopener">mailing
list&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> and debated before the
change is made. We leveraged this before making the
backward-compatibility-breaking metadata change (&lt;a href="https://github.com/grpc/proposal/blob/master/L7-go-metadata-api.md" target="_blank" rel="noopener">gRFC
L7&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>), and
also for designing the new resolver/balancer API (&lt;a href="https://github.com/grpc/proposal/pull/30" target="_blank" rel="noopener">gRFC
L9&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>).&lt;/p>
&lt;h2 id="regression-testing">Regression Testing&lt;/h2>
&lt;p>Every PR in our repo must pass our unit and end-to-end tests. Our current test
coverage is 85%. Anytime a regression is identified, we add a test that covers
the failing scenario, both to prove to ourselves that the problem is resolved by
the fix, and to prevent it from reoccurring in the future. This helps us
improve our overall coverage numbers as well. We also intend to re-enable
coverage reporting for all PRs, but in a non-blocking fashion (&lt;a href="https://github.com/grpc/grpc-go/issues/1676" target="_blank" rel="noopener">related
issue&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>).&lt;/p>
&lt;p>In addition to testing for correctness, any PR that we suspect will impact
performance is run though our benchmarks. We have a set of benchmarks both in
our &lt;a href="https://github.com/grpc/grpc-go/tree/master/benchmark" target="_blank" rel="noopener">open source repo&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
and also within Google. These comprise a variety of workloads that we believe
are most important for our users, both streaming and unary, and some are
specifically designed to measure our optimal QPS, throughput, or latency.&lt;/p>
&lt;h2 id="releases">Releases&lt;/h2>
&lt;p>The GA release of gRPC-Go was made in conjunction with the other languages in
July of 2016. The team performed several patch releases between then and the
end of 2016, but none included release notes. Our subsequent releases have
improved in regularity (a minor release is performed every six weeks) and
in the quality of the release notes. We also are responsive with patch
releases, back-porting bug fixes to older releases either on demand or for more
serious issues within a week.&lt;/p>
&lt;p>When performing a release, in addition to the tests in our repo, we also run a
full suite of inter-op tests with other gRPC language implementations. This
process has been working well for us, and we will cover more about this in a
future blog post.&lt;/p>
&lt;h2 id="non-open-source-work">Non-Open Source Work&lt;/h2>
&lt;p>We have taken an &amp;ldquo;open source first&amp;rdquo; approach to developing gRPC. This means
that, wherever possible, gRPC functionality is added directly into the open
source project. However, to work within Google&amp;rsquo;s infrastructure, our team
sometimes needs to provide additional functionality on top of gRPC. This is
typically done through hooks like the &lt;a href="https://godoc.org/google.golang.org/grpc/stats#Handler" target="_blank" rel="noopener">stats
API&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> or
&lt;a href="https://godoc.org/google.golang.org/grpc#UnaryClientInterceptor" target="_blank" rel="noopener">interceptors&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
or &lt;a href="https://godoc.org/google.golang.org/grpc/resolver" target="_blank" rel="noopener">custom resolvers&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;p>To keep Google&amp;rsquo;s internal version of gRPC up-to-date with the open source
version, we do weekly or on-demand imports. Before an import, we run every test
within Google that depends upon gRPC. This gives us another way in which we can
catch problems before performing releases in Open Source.&lt;/p>
&lt;h2 id="looking-forward">Looking Forward&lt;/h2>
&lt;p>In 2018, we intend to do more of the same, and maintain our SLOs around
addressing issues and accepting contributions to the project. We also would
like to more aggressively tag issues with the &lt;a href="https://github.com/grpc/grpc-go/labels/Status%3A%20Help%20Wanted" target="_blank" rel="noopener">Help
Wanted&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> label
for anyone looking to contribute to have a bigger selection of issues to choose
from.&lt;/p>
&lt;p>For gRPC itself, one of our main focuses right now is performance, which we hope
will transparently benefit many of our users. In the near-term, we have some
exciting changes we&amp;rsquo;re wrapping up that should provide a 30+% reduction in
latency with high concurrency, resulting in a QPS improvement of ~25%. Once
that work is done, we have a list of other &lt;a href="https://github.com/grpc/grpc-go/issues?q=is%3Aissue&amp;#43;is%3Aopen&amp;#43;label%3A%22Type%3A&amp;#43;Performance%22" target="_blank" rel="noopener">performance
issues&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
that we&amp;rsquo;ll be tackling next.&lt;/p>
&lt;p>On user experience, we want to provide better documentation, and are starting to
improve our godoc with better comments and more examples. We want to improve
the overall experience of using gRPC, so we will be working closely on projects
around distributed tracing, monitoring, and testing to make gRPC services easier
to manage in production. We want to do more, and we are hoping that starting
with these and listening to feedback will help us ship improvements steadily.&lt;/p></description></item><item><title>Blog: The gRPC Meetup Kit</title><link>https://grpc.io/blog/meetup-kit/</link><pubDate>Thu, 14 Sep 2017 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/meetup-kit/</guid><description>
&lt;p>If you have ever wanted to run an event around &lt;a href="https://grpc.io/">gRPC&lt;/a>, but didn&amp;rsquo;t know where to start, or weren&amp;rsquo;t sure what content is available - we have released the &lt;a href="https://github.com/grpc-ecosystem/meetup-kit" target="_blank" rel="noopener">gRPC Meetup Kit&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>!&lt;/p>
&lt;p>The meetup kit includes a 15 minute presentation on the basic concepts of gRPC, with accompanying &lt;a href="https://docs.google.com/presentation/d/1dgI09a-_4dwBMLyqfwchvS6iXtbcISQPLAXL6gSYOcc/edit?usp=sharing" target="_blank" rel="noopener">slides&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> and &lt;a href="https://www.youtube.com/watch?v=UVsIfSfS6I4" target="_blank" rel="noopener">video&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> for either reference or playback, as well as a &lt;a href="https://codelabs.developers.google.com/codelabs/cloud-grpc/index.html" target="_blank" rel="noopener">45-minute codelab&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> that takes you through the basics of gRPC in &lt;a href="https://nodejs.org" target="_blank" rel="noopener">Node.js&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> and &lt;a href="https://golang.org" target="_blank" rel="noopener">Go&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. At the end of the codelab participants will have a solid understanding of the fundamentals of gRPC.&lt;/p>
&lt;p>If you are thinking about running a gRPC event, make sure to contact us to receive &lt;a href="https://goo.gl/forms/C3TCtFdobz4ippty2" target="_blank" rel="noopener">gRPC stickers&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> and/or organise &lt;a href="https://goo.gl/forms/pvxNwWExr5ApbNst2" target="_blank" rel="noopener">office hours over Hangouts with the gRPC team&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>!&lt;/p></description></item><item><title>Blog: gRPC-Go performance Improvements</title><link>https://grpc.io/blog/grpc-go-perf-improvements/</link><pubDate>Tue, 22 Aug 2017 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/grpc-go-perf-improvements/</guid><description>
&lt;p>For past few months we&amp;rsquo;ve been working on improving gRPC-Go performance. This includes improving network utilization, optimizing CPU usage and memory allocations. Most of our recent effort has been focused around revamping gRPC-Go flow control. After several optimizations and new features we&amp;rsquo;ve been able to improve quite significantly, especially on high-latency networks. We expect users that are working with high-latency networks and large messages to see an order of magnitude performance gain.
Benchmark results at the end.&lt;/p>
&lt;p>This blog summarizes the work we have done so far (in chronological order) to improve performance and lays out our near-future plans.&lt;/p>
&lt;h2 id="recently-implemented-optimizations">Recently Implemented Optimizations&lt;/h2>
&lt;h3 id="expanding-stream-window-on-receiving-large-messages">Expanding stream window on receiving large messages&lt;/h3>
&lt;p>&lt;a href="https://github.com/grpc/grpc-go/pull/1248" target="_blank" rel="noopener">Code link&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/p>
&lt;p>This is an optimization used by gRPC-C to achieve performance benefits for large messages. The idea is that when there&amp;rsquo;s an active read by the application on the receive side, we can effectively bypass stream-level flow control to request the whole message. This proves to be very helpful with large messages. Since the application is already committed to reading and has allocated enough memory for it, it makes sense that we send a proactive large window update (if necessary) to get the whole message rather than receiving it in chunks and sending window updates when we run low on window.&lt;/p>
&lt;p>This optimization alone provided a 10x improvement for large messages on high-latency networks.&lt;/p>
&lt;h3 id="decoupling-application-reads-from-connection-flow-control">Decoupling application reads from connection flow control&lt;/h3>
&lt;p>&lt;a href="https://github.com/grpc/grpc-go/pull/1265" target="_blank" rel="noopener">Code link&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/p>
&lt;p>After having several discussions with gRPC-Java and gRPC-C core team we realized that gRPC-Go&amp;rsquo;s connection-level flow control was overly restrictive in the sense that window updates on the connection depended upon if the application had read data from it or not. It must be noted that it makes perfect sense to have stream-level flow control depended on application read but not so much for connection-level flow control. The rationale is as follows: A connection is shared by several streams (RPCs). If there were at least one stream that read slowly or didn&amp;rsquo;t read at all, it would hamper the performance or completely stall other streams on that connection. This happens because we won&amp;rsquo;t send out window updates on the connection until that slow or inactive stream read data. Therefore, it makes sense to decouple the connection&amp;rsquo;s flow control from application reads.&lt;/p>
&lt;p>However, this begs at least two questions:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Won&amp;rsquo;t a client be able to send as much data as it wants to the server by creating new streams when one runs out?&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Why even have connection-level flow control if the stream-level flow control is enough?&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>The answer to the first question is short and simple: no. A server has an option to limit the number of streams that it intends to serve concurrently. Therefore, although at first it may seem like a problem, it really is not.&lt;/p>
&lt;p>The need for connection-level flow control:&lt;/p>
&lt;p>It is true that stream-level flow control is sufficient to throttle a sender from sending too much data. But not having connection-level flow control (or using an unlimited connection-level window) makes it so that when things get slower on a stream, opening a new one will appear to make things faster. This will only take one so far since the number of streams are limited. However, having a connection-level flow control window set to the Bandwidth Delay Product (BDP) of the network puts an upper-bound on how much performance can realistically be squeezed out of the network.&lt;/p>
&lt;h3 id="piggyback-window-updates">Piggyback window updates&lt;/h3>
&lt;p>&lt;a href="https://github.com/grpc/grpc-go/pull/1273" target="_blank" rel="noopener">Code link&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/p>
&lt;p>Sending a window update itself has a cost associated to it; a flush operation is necessary, which results in a syscall. Syscalls are blocking and slow. Therefore, when sending out a stream-level window update, it makes sense to also check if a connection-level window update can be sent using the same flush syscall.&lt;/p>
&lt;h3 id="bdp-estimation-and-dynamic-flow-control-window">BDP estimation and dynamic flow control window&lt;/h3>
&lt;p>&lt;a href="https://github.com/grpc/grpc-go/pull/1310" target="_blank" rel="noopener">Code link&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/p>
&lt;p>This feature is the latest and in some ways the most awaited optimization feature that has helped us close the final gap between gRPC and HTTP/1.1 performance on high latency networks.&lt;/p>
&lt;p>Bandwidth Delay Product (BDP) is the bandwidth of a network connection times its round-trip latency. This effectively tells us how many bytes can be &amp;ldquo;on the wire&amp;rdquo; at a given moment, if full utilization is achieved.&lt;/p>
&lt;p>The &lt;a href="https://docs.google.com/document/d/1Eq4eBEbNt1rc8EYuwqsduQd1ZfcBOCYt9HVSBa--m-E/pub" target="_blank" rel="noopener">algorithm&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> to compute BDP and adapt accordingly was first proposed by @ejona and later implemented by both gRPC-C core and gRPC-Java (note that it isn&amp;rsquo;t enabled in Java yet). The idea is simple and powerful: every time a receiver gets a data frame it sends out a BDP ping (a ping with unique data only used by BDP estimator). After this, the receiver starts counting the number of bytes it receives (including the ones that triggered the BDP ping) until it receives the ack for that ping. This total sum of all bytes received in about 1.5 RTT (Round-Trip Time) is an approximation of the effective BDP * 1.5. If this is close to our current window size (say, more than 2/3rd of it) we must increase the window size. We put our window sizes (both streaming and connection) to be twice the BDP we sampled(total sum of all bytes received).&lt;/p>
&lt;p>This algorithm by itself could cause the BDP estimation to increase indefinitely; an increase in window will result in sampling more bytes which in turn will cause the window to be increased further. This phenomenon is called &lt;a href="https://en.wikipedia.org/wiki/Bufferbloat" target="_blank" rel="noopener">buffer-bloat&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> and was discovered by earlier implementations in gRPC-C core and gRPC-Java. The solution to this is to calculate the bandwidth for every sample and check if it is greater than the maximum bandwidth noted so far. If so, only then increase our window sizes. The bandwidth, as we know, can be calculated by dividing the sample by RTT * 1.5 (remember the sample was for one and a half round trips). If the bandwidth doesn&amp;rsquo;t increase with an increase in sampled bytes that&amp;rsquo;s indicative that this change is because of an increased window size and doesn&amp;rsquo;t really reflect the nature of the network itself.&lt;/p>
&lt;p>While running experiments on VMs in different continents we realized that every once in awhile a rogue, unnaturally fast ping-ack at the right time (really the wrong time) would cause our window sizes to go up. This happens because such a ping-ack would cause us to notice a decreased RTT and calculate a high bandwidth value. Now if that sample of bytes was greater than 2/3rd of our window then we would increase the window sizes. However, this ping ack was an aberration and shouldn&amp;rsquo;t have changed our perception of the network RTT al together. Therefore, we keep a running average of the RTTs we note weighted by a constant rather than the total number of samples to heed more to recent RTTs and less to the ones in past. It is important because networks might change over time.&lt;/p>
&lt;p>During implementation, we experimented with several tuning parameters, such as the multiplier to compute the window size from the sample size to select the best settings, that balanced between growth and accuracy.&lt;/p>
&lt;p>Given that we&amp;rsquo;re always bound by the flow control of TCP which for most cases is upper bounded at 4MB, we bound the growth of our window sizes by the same number: 4MB.&lt;/p>
&lt;p>BDP estimation and dynamically adjusting window sizes is turned-on by default and can be turned off by setting values manually for connection and/or stream window sizes.&lt;/p>
&lt;h3 id="near-future-efforts">Near-future efforts&lt;/h3>
&lt;p>We are now looking into improving our throughput by better CPU utilization, the following efforts are in-line with that.&lt;/p>
&lt;h3 id="reducing-flush-syscalls">Reducing flush syscalls&lt;/h3>
&lt;p>We noticed a bug in our transport layer which causes us to make a flush syscall for every data frame we write, even if the same goroutine has more data to send. We can batch a lot of these writes to use only one flush. This in fact will not be a big change to the code itself.&lt;/p>
&lt;p>In our efforts to get rid of unnecessary flushes we recently combined the headers and data write for unary and server streaming RPCs to one flush on the client-side. Link to &lt;a href="https://github.com/grpc/grpc-go/pull/1343" target="_blank" rel="noopener">code&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/p>
&lt;p>Another related idea proposed by one of our users @petermattic in &lt;a href="https://github.com/grpc/grpc-go/pull/1373" target="_blank" rel="noopener">this&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> PR was to combine a server response to a unary RPC into one flush. We are currently looking into that as well.&lt;/p>
&lt;h3 id="reducing-memory-allocation">Reducing memory allocation&lt;/h3>
&lt;p>For every data frame read from the wire a new memory allocation takes place. The same holds true at the gRPC layer for every new message for decompressing and decoding. These allocations result in excessive garbage collection cycles, which are expensive. Reusing memory buffers can reduce this GC pressure, and we are prototyping approaches to do so. As requests need buffers of differing sizes, one approach would be to maintain individual memory pools of fixed sizes (powers of two). So now when reading x bytes from the wire we can find the nearest power of 2 greater than x and reuse a buffer from our cache if available or allocate a new one if need be. We will be using golang sync Pools so we don&amp;rsquo;t have to worry about garbage collection. However, we will need to run sufficient tests before committing to this.&lt;/p>
&lt;h3 id="results">Results&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>Benchmark on a real network:&lt;/p>
&lt;ul>
&lt;li>Server and client were launched on two VMs in different continents. RTT of ~152ms.&lt;/li>
&lt;li>Client made an RPC with a payload and server responded back with an empty message.&lt;/li>
&lt;li>The time taken for each RPC was measured.&lt;/li>
&lt;li>&lt;a href="https://github.com/grpc/grpc-go/compare/master...MakMukhi:http_greeter" target="_blank" rel="noopener">Code link&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Message size&lt;/th>
&lt;th style="text-align:left">gRPC&lt;/th>
&lt;th style="text-align:left">HTTP 1.1&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">1 KB&lt;/td>
&lt;td style="text-align:left">~152 ms&lt;/td>
&lt;td style="text-align:left">~152 ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">10 KB&lt;/td>
&lt;td style="text-align:left">~152 ms&lt;/td>
&lt;td style="text-align:left">~152 ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">10 KB&lt;/td>
&lt;td style="text-align:left">~152 ms&lt;/td>
&lt;td style="text-align:left">~152 ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">1 MB&lt;/td>
&lt;td style="text-align:left">~152 ms&lt;/td>
&lt;td style="text-align:left">~152 ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">10 MB&lt;/td>
&lt;td style="text-align:left">~622 ms&lt;/td>
&lt;td style="text-align:left">~630 ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">100 MB&lt;/td>
&lt;td style="text-align:left">~5 sec&lt;/td>
&lt;td style="text-align:left">~5 sec&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;ul>
&lt;li>Benchmark on simulated network:
&lt;ul>
&lt;li>Server and client were launched on the same machine and different network latencies were simulated.&lt;/li>
&lt;li>Client made an RPC with 1MB of payload and server responded back with an empty message.&lt;/li>
&lt;li>The time taken for each RPC was measured.&lt;/li>
&lt;li>Following tables show time taken by first 10 RPCs.&lt;/li>
&lt;li>&lt;a href="https://github.com/grpc/grpc-go/compare/master...MakMukhi:grpc_vs_http" target="_blank" rel="noopener">Code link&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h5 id="no-latency-network">No-latency Network&lt;/h5>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>gRPC&lt;/th>
&lt;th style="text-align:center">HTTP 2.0&lt;/th>
&lt;th style="text-align:right">HTTP 1.1&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>5.097809ms&lt;/td>
&lt;td style="text-align:center">16.107461ms&lt;/td>
&lt;td style="text-align:right">18.298959ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>4.46083ms&lt;/td>
&lt;td style="text-align:center">4.301808ms&lt;/td>
&lt;td style="text-align:right">7.715456ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>5.081421ms&lt;/td>
&lt;td style="text-align:center">4.076645ms&lt;/td>
&lt;td style="text-align:right">8.118601ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>4.338013ms&lt;/td>
&lt;td style="text-align:center">4.232606ms&lt;/td>
&lt;td style="text-align:right">6.621028ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>5.013544ms&lt;/td>
&lt;td style="text-align:center">4.693488ms&lt;/td>
&lt;td style="text-align:right">5.83375ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>3.963463ms&lt;/td>
&lt;td style="text-align:center">4.558047ms&lt;/td>
&lt;td style="text-align:right">5.571579ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>3.509808ms&lt;/td>
&lt;td style="text-align:center">4.855556ms&lt;/td>
&lt;td style="text-align:right">4.966938ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>4.864618ms&lt;/td>
&lt;td style="text-align:center">4.324159ms&lt;/td>
&lt;td style="text-align:right">6.576279ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>3.545933ms&lt;/td>
&lt;td style="text-align:center">4.61375ms&lt;/td>
&lt;td style="text-align:right">6.105608ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>3.481094ms&lt;/td>
&lt;td style="text-align:center">4.621215ms&lt;/td>
&lt;td style="text-align:right">7.001607ms&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h5 id="network-with-rtt-of-16ms">Network with RTT of 16ms&lt;/h5>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>gRPC&lt;/th>
&lt;th style="text-align:center">HTTP 2.0&lt;/th>
&lt;th style="text-align:right">HTTP 1.1&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>118.837625ms&lt;/td>
&lt;td style="text-align:center">84.453913ms&lt;/td>
&lt;td style="text-align:right">58.858109ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>36.801006ms&lt;/td>
&lt;td style="text-align:center">22.476308ms&lt;/td>
&lt;td style="text-align:right">20.877585ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>35.008349ms&lt;/td>
&lt;td style="text-align:center">21.206222ms&lt;/td>
&lt;td style="text-align:right">19.793881ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>21.153461ms&lt;/td>
&lt;td style="text-align:center">20.940937ms&lt;/td>
&lt;td style="text-align:right">22.18179ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>20.640364ms&lt;/td>
&lt;td style="text-align:center">21.888247ms&lt;/td>
&lt;td style="text-align:right">21.4666ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>21.410346ms&lt;/td>
&lt;td style="text-align:center">21.186008ms&lt;/td>
&lt;td style="text-align:right">20.925514ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>19.755766ms&lt;/td>
&lt;td style="text-align:center">21.818027ms&lt;/td>
&lt;td style="text-align:right">20.553768ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>20.388882ms&lt;/td>
&lt;td style="text-align:center">21.366796ms&lt;/td>
&lt;td style="text-align:right">21.460029ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>20.623342ms&lt;/td>
&lt;td style="text-align:center">20.681414ms&lt;/td>
&lt;td style="text-align:right">20.586908ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>20.452023ms&lt;/td>
&lt;td style="text-align:center">20.781208ms&lt;/td>
&lt;td style="text-align:right">20.278481ms&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h5 id="network-with-rtt-of-64ms">Network with RTT of 64ms&lt;/h5>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>GRPC&lt;/th>
&lt;th style="text-align:center">HTTP 2.0&lt;/th>
&lt;th style="text-align:right">HTTP 1.1&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>455.072669ms&lt;/td>
&lt;td style="text-align:center">275.290241ms&lt;/td>
&lt;td style="text-align:right">208.826314ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>195.43357ms&lt;/td>
&lt;td style="text-align:center">70.386788ms&lt;/td>
&lt;td style="text-align:right">70.042513ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>132.215978ms&lt;/td>
&lt;td style="text-align:center">70.01131ms&lt;/td>
&lt;td style="text-align:right">71.19429ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>69.239273ms&lt;/td>
&lt;td style="text-align:center">70.032237ms&lt;/td>
&lt;td style="text-align:right">69.479335ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>68.669903ms&lt;/td>
&lt;td style="text-align:center">70.192272ms&lt;/td>
&lt;td style="text-align:right">70.858937ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>70.458108ms&lt;/td>
&lt;td style="text-align:center">69.395154ms&lt;/td>
&lt;td style="text-align:right">71.161921ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>68.488057ms&lt;/td>
&lt;td style="text-align:center">69.252731ms&lt;/td>
&lt;td style="text-align:right">71.374758ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>68.816031ms&lt;/td>
&lt;td style="text-align:center">69.628744ms&lt;/td>
&lt;td style="text-align:right">70.141381ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>69.170105ms&lt;/td>
&lt;td style="text-align:center">68.935813ms&lt;/td>
&lt;td style="text-align:right">70.685521ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>68.831608ms&lt;/td>
&lt;td style="text-align:center">69.728349ms&lt;/td>
&lt;td style="text-align:right">69.45605ms&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table></description></item><item><title>Blog: 2017-08-17 Community Meeting Update</title><link>https://grpc.io/blog/community-meeting-update/</link><pubDate>Thu, 17 Aug 2017 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/community-meeting-update/</guid><description>
&lt;p>&lt;strong>Next Community Meeting:&lt;/strong> Thursday, August 31, 2017 11am Pacific Time (US and Canada)&lt;/p>
&lt;h2 id="general-announcements">General Announcements&lt;/h2>
&lt;p>Call for Papers: CloudNativeCon&lt;/p>
&lt;p>CloudNativeCon gathers all CNCF (Cloud Native Computing Foundation) projects under a single roof.
Presenters will be talking about their experiences with Kubernetes, Prometheus, OpenTracing, Fluentd, Linkerd, gRPC, CoreDNS, containerd, rkt and CNI.
The call for papers period will be ending on Monday, August 21, 2017.
The conference will be taking place on the 6th and 7th of December, 2017.
If you submit a talk, please add an entry to the spreadsheet linked in the &lt;a href="https://docs.google.com/document/d/1DTMEbBNmzNbZBh8nOivsnnw3CwUr1Q7WGRe7rNxyHOU/edit#bookmark=id.7qk9qf3ri75m" target="_blank" rel="noopener">gRPC Community Meeting Working Doc&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;p>Register for &lt;a href="https://events.linuxfoundation.org/events/cloudnativecon-and-kubecon-north-america/attend/register" target="_blank" rel="noopener">CloudNativeCon&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/p>
&lt;h2 id="release-updates">Release Updates&lt;/h2>
&lt;p>1.6 will be available soon.
The required changes have already been merged and published in the protocol buffer libraries.
Keep your eyes peeled for the upcoming release.&lt;/p>
&lt;h2 id="platform-updates">Platform Updates&lt;/h2>
&lt;p>No platform updates.&lt;/p>
&lt;h2 id="language-updates">Language Updates&lt;/h2>
&lt;p>No language specific updates.&lt;/p></description></item><item><title>Blog: Announcing out-of-the-box support for gRPC in the Flatbuffers serialization library</title><link>https://grpc.io/blog/grpc-flatbuffers/</link><pubDate>Thu, 17 Aug 2017 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/grpc-flatbuffers/</guid><description>
&lt;p>The recent release of Flatbuffers &lt;a href="https://github.com/google/flatbuffers/releases" target="_blank" rel="noopener">version 1.7&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> introduced truly zero-copy support for gRPC out of the box.&lt;/p>
&lt;p>&lt;a href="https://google.github.io/flatbuffers/" target="_blank" rel="noopener">Flatbuffers&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> is a serialization library that allows you to access serialized data without first unpacking it or allocating any
additional data structures. It was originally designed for games and other resource constrained applications, but is now finding more general use, both by teams within Google and in other companies such as Netflix and Facebook.&lt;/p>
&lt;p>Flatbuffers enables maximum throughput by directly using gRPC&amp;rsquo;s slice buffers with zero-copy for common use cases. An incoming rpc can be processed directly from gRPCs internal buffers, and constructing a new message will write directly to these buffers without intermediate steps.&lt;/p>
&lt;p>This is currently, fully supported in the C++ implementation of FlatBuffers, with more languages to come. There is also an implementation in Go, which is not entirely zero copy, but still very low on allocation cost (see below).&lt;/p>
&lt;h2 id="example-usage">Example Usage&lt;/h2>
&lt;p>Let&amp;rsquo;s look at an example of how this works.&lt;/p>
&lt;h3 id="use-flatbuffers-as-an-idl">Use Flatbuffers as an IDL&lt;/h3>
&lt;p>Start with an &lt;code>.fbs&lt;/code> schema (similar to .proto, if you are familiar with protocol buffers) that declares an RPC service:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-proto" data-lang="proto">&lt;span style="display:flex;">&lt;span>table HelloReply {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> message&lt;span style="color:#555">:&lt;/span>&lt;span style="color:#078;font-weight:bold">string&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>}&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>table HelloRequest {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> name&lt;span style="color:#555">:&lt;/span>&lt;span style="color:#078;font-weight:bold">string&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>}&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>table ManyHellosRequest {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> name&lt;span style="color:#555">:&lt;/span>&lt;span style="color:#078;font-weight:bold">string&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> num_greetings&lt;span style="color:#555">:&lt;/span>int;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>}&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>rpc_service Greeter {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> SayHello(HelloRequest)&lt;span style="color:#555">:&lt;/span>HelloReply;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> SayManyHellos(ManyHellosRequest)&lt;span style="color:#555">:&lt;/span>HelloReply (streaming&lt;span style="color:#555">:&lt;/span> &lt;span style="color:#c30">&amp;#34;server&amp;#34;&lt;/span>);&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>}&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>To generate C++ code from this, run: &lt;code>flatc --cpp --grpc example.fbs&lt;/code>, much like in protocol buffers.&lt;/p>
&lt;h4 id="generated-server-implementation">Generated Server Implementation&lt;/h4>
&lt;p>The server implementation is very similar to protocol buffers, except now the request and response messages are of type &lt;code>flatbuffers::grpc::Message&amp;lt;HelloRequest&amp;gt; *&lt;/code>.
Unlike protocol buffers, where these types represent a tree of C++ objects, here they are merely handles to a flat object in the underlying gRPC slice. You can access the data directly:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cpp" data-lang="cpp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">auto&lt;/span> request &lt;span style="color:#555">=&lt;/span> request_msg&lt;span style="color:#555">-&amp;gt;&lt;/span>GetRoot();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">auto&lt;/span> name &lt;span style="color:#555">=&lt;/span> request&lt;span style="color:#555">-&amp;gt;&lt;/span>name()&lt;span style="color:#555">-&amp;gt;&lt;/span>str();
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Building a response is equally simple&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cpp" data-lang="cpp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">auto&lt;/span> msg_offset &lt;span style="color:#555">=&lt;/span> mb_.CreateString(&lt;span style="color:#c30">&amp;#34;Hello, &amp;#34;&lt;/span> &lt;span style="color:#555">+&lt;/span> name);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">auto&lt;/span> hello_offset &lt;span style="color:#555">=&lt;/span> CreateHelloReply(mb_, msg_offset);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>mb_.Finish(hello_offset);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">*&lt;/span>response_msg &lt;span style="color:#555">=&lt;/span> mb_.ReleaseMessage&lt;span style="color:#555">&amp;lt;&lt;/span>HelloReply&lt;span style="color:#555">&amp;gt;&lt;/span>();
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The client code is the same as that generated by protocol buffers, except for the FlatBuffer access and construction code.&lt;/p>
&lt;p>See the full example &lt;a href="https://github.com/google/flatbuffers/tree/master/grpc/samples/greeter" target="_blank" rel="noopener">here&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. To compile it, you need gRPC.
The same repo has a &lt;a href="https://github.com/google/flatbuffers/blob/master/grpc/tests/go_test.go" target="_blank" rel="noopener">similar example&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> for Go.&lt;/p>
&lt;p>Read more about using and building FlatBuffers for your platform &lt;a href="https://google.github.io/flatbuffers/" target="_blank" rel="noopener">on the flatbuffers site&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p></description></item><item><title>Blog: gRPC Load Balancing</title><link>https://grpc.io/blog/grpc-load-balancing/</link><pubDate>Thu, 15 Jun 2017 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/grpc-load-balancing/</guid><description>
&lt;p>This post describes various load balancing scenarios seen when deploying gRPC. If you use &lt;a href="https://grpc.io/">gRPC&lt;/a> with multiple backends, this document is for you.&lt;/p>
&lt;p>A large scale gRPC deployment typically has a number of identical back-end instances, and a number of clients. Each server has a certain capacity. Load balancing is used for distributing the load from clients optimally across available servers.&lt;/p>
&lt;h2 id="why-grpc">Why gRPC?&lt;/h2>
&lt;p>gRPC is a modern RPC protocol implemented on top of HTTP/2. HTTP/2 is a Layer 7 (Application layer) protocol, that runs on top of a TCP (Layer 4 - Transport layer) protocol, which runs on top of IP (Layer 3 - Network layer) protocol. gRPC has many advantages over traditional HTTP/REST/JSON mechanism such as&lt;/p>
&lt;ol>
&lt;li>&lt;a href="https://http2.github.io/faq/#why-is-http2-binary" target="_blank" rel="noopener">Binary protocol (HTTP/2)&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>Multiplexing many requests on one connection (HTTP/2)&lt;/li>
&lt;li>Header compression (HTTP/2)&lt;/li>
&lt;li>Strongly typed service and message definition (Protobuf)&lt;/li>
&lt;li>Idiomatic client/server library implementations in many languages&lt;/li>
&lt;/ol>
&lt;p>In addition, gRPC integrates seamlessly with ecosystem components like service discovery, name resolver, load balancer, tracing and monitoring, among others.&lt;/p>
&lt;h2 id="load-balancing-options">Load balancing options&lt;/h2>
&lt;h3 id="proxy-or-client-side">Proxy or Client side?&lt;/h3>
&lt;p>&lt;em>Note: Proxy load balancing is also known as server-side load balancing in some literature.&lt;/em>&lt;/p>
&lt;p>Deciding between proxy versus client-side load balancing is a primary architectural choice. In Proxy load balancing, the client issues RPCs to the a Load Balancer (LB) proxy. The LB distributes the RPC call to one of the available backend servers that implement the actual logic for serving the call. The LB keeps track of load on each backend and implements algorithms for distributing load fairly. The clients themselves do not know about the backend servers. Clients can be untrusted. This architecture is typically used for user facing services where clients from open internet can connect to servers in a data center, as shown in the picture below. In this scenario, clients make requests to LB (#1). The LB passes on the request to one of the backends (#2), and the backends report load to LB (#3).&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/image_0.png" alt="image alt text" id="image_0" data-toggle="modal" data-target="#modal-image_0"/>
&lt;div class="modal" id="modal-image_0">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/image_0.png" alt="image alt text"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>In Client side load balancing, the client is aware of multiple backend servers and chooses one to use for each RPC. The client gets load reports from backend servers and the client implements the load balancing algorithms. In simpler configurations server load is not considered and client can just round-robin between available servers. This is shown in the picture below. As you can see, the client makes request to a specific backend (#1). The backends respond with load information (#2), typically on the same connection on which client RPC is executed. The client then updates its internal state.&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/image_1.png" alt="image alt text" id="image_1" data-toggle="modal" data-target="#modal-image_1"/>
&lt;div class="modal" id="modal-image_1">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/image_1.png" alt="image alt text"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>The following table outlines the pros and cons of each model.&lt;/p>
&lt;table>
&lt;tr>
&lt;td>&lt;/td>
&lt;td>Proxy&lt;/td>
&lt;td>Client Side&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="width:10% !important">Pros&lt;/td>
&lt;td>
&lt;ul>
&lt;li>Simple client&lt;/li>
&lt;li>No client-side awareness of backend&lt;/li>
&lt;li>Works with untrusted clients&lt;/li>
&lt;/ul>
&lt;/td>
&lt;td>
&lt;ul>
&lt;li>High performance because elimination of extra hop&lt;/li>
&lt;/ul>
&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Cons&lt;/td>
&lt;td>
&lt;ul>
&lt;li>LB is in the data path&lt;/li>
&lt;li>Higher latency&lt;/li>
&lt;li>LB throughput may limit scalability&lt;/li>
&lt;/ul>
&lt;/td>
&lt;td>
&lt;ul>
&lt;li>Complex client&lt;/li>
&lt;li>Client keeps track of server load and health&lt;/li>
&lt;li>Client implements load balancing algorithm&lt;/li>
&lt;li>Per-language implementation and maintenance burden&lt;/li>
&lt;li>Client needs to be trusted, or the trust boundary needs to be handled by a lookaside LB.&lt;/li>
&lt;/ul>
&lt;/td>
&lt;/tr>
&lt;/table>
&lt;h3 id="proxy-load-balancer-options">Proxy Load Balancer options&lt;/h3>
&lt;p>Proxy load balancing can be L3/L4 (transport level) or L7 (application level). In transport level load balancing, the server terminates the TCP connection and opens another connection to the backend of choice. The application data (HTTP/2 and gRPC frames) are simply copied between the client connection to the backend connection. L3/L4 LB by design does very little processing, adds less latency compared with L7 LB, and is cheaper because it consumes fewer resources.&lt;/p>
&lt;p>In L7 (application level) load balancing, the LB terminates and parses the HTTP/2 protocol. The LB can inspect each request and assign a backend based on the request contents. For example, a session cookie sent as part of HTTP header can be used to associate with a specific backend, so all requests for that session are served by the same backend. Once the LB has chosen an appropriate backend, it creates a new HTTP/2 connection to that backend. It then forwards the HTTP/2 streams received from the client to the backend(s) of choice. With HTTP/2, LB can distribute the streams from one client among multiple backends.&lt;/p>
&lt;h4 id="l3l4-transport-vs-l7-application">L3/L4 (Transport) vs L7 (Application)&lt;/h4>
&lt;table>
&lt;tr>
&lt;td>
Use case
&lt;/td>
&lt;td>
Recommendation
&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>RPC load varies a lot among connections&lt;/td>
&lt;td>Use Application level LB&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Storage or compute affinity is important&lt;/td>
&lt;td>Use Application level LB and use cookies or similar for routing requests to correct backend&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Minimizing resource utilization in proxy is more important than features&lt;/td>
&lt;td>Use L3/L4 LB&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Latency is paramount&lt;/td>
&lt;td>Use L3/L4 LB&lt;/td>
&lt;/tr>
&lt;/table>
&lt;h3 id="client-side-lb-options">Client side LB options&lt;/h3>
&lt;h4 id="thick-client">Thick client&lt;/h4>
&lt;p>A thick client approach means the load balancing smarts are implemented in the client. The client is responsible for keeping track of available servers, their workload, and the algorithms used for choosing servers. The client typically integrates libraries that communicate with other infrastructures such as service discovery, name resolution, quota management, etc.&lt;/p>
&lt;h4 id="lookaside-load-balancing">Lookaside Load Balancing&lt;/h4>
&lt;p>&lt;em>Note: A lookaside load balancer is also known as an external load balancer or one-arm load balancer&lt;/em>&lt;/p>
&lt;p>With lookaside load balancing, the load balancing smarts are implemented in a special LB server. Clients query the lookaside LB and the LB responds with best server(s) to use. The heavy lifting of keeping server state and implementation of LB algorithm is consolidated in the lookaside LB. Note that client might choose to implement simple algorithms on top of the sophisticated ones implemented in the LB. gRPC defines a protocol for communication between client and LB using this model. See Load Balancing in gRPC &lt;a href="https://github.com/grpc/grpc/blob/master/doc/load-balancing.md" target="_blank" rel="noopener">doc&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> for details.&lt;/p>
&lt;p>The picture below illustrates this approach. The client gets at least one address from lookaside LB (#1). Then the client uses this address to make a RPC (#2), and server sends load report to the LB (#3). The lookaside LB communicates with other infrastructure such as name resolution, service discovery, and so on (#4).&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/image_2.png" alt="image alt text" id="image_2" data-toggle="modal" data-target="#modal-image_2"/>
&lt;div class="modal" id="modal-image_2">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/image_2.png" alt="image alt text"/>
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;h2 id="recommendations-and-best-practices">Recommendations and best practices&lt;/h2>
&lt;p>Depending upon the particular deployment and constraints, we suggest the following.&lt;/p>
&lt;table>
&lt;tr>
&lt;td>Setup&lt;/td>
&lt;td>Recommendation&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>
&lt;ul>
&lt;li>Very high traffic between clients and servers&lt;/li>
&lt;li>Clients can be trusted&lt;/li>
&lt;/ul>
&lt;/td>
&lt;td>
&lt;ul>
&lt;li>Thick client-side load balancing&lt;/li>
&lt;li>Client side LB with ZooKeeper/Etcd/Consul/Eureka. &lt;a href="https://github.com/makdharma/grpc-zookeeper-lb" target="_blank" rel="noopener">ZooKeeper example&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/li>
&lt;/ul>
&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>
&lt;ul>
&lt;li>Traditional setup - Many clients connecting to services behind a proxy&lt;/li>
&lt;li>Need trust boundary between servers and clients&lt;/li>
&lt;/ul>
&lt;/td>
&lt;td>
&lt;ul>
&lt;li>Proxy Load Balancing&lt;/li>
&lt;li>L3/L4 LB with GCLB (if using GCP)&lt;/li>
&lt;li>L3/L4 LB with haproxy - &lt;a href="https://gist.github.com/thpham/114d20de8472b2cef966" target="_blank" rel="noopener">config file&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>Nginx coming soon&lt;/li>
&lt;li>If need session stickiness - L7 LB with Envoy as proxy&lt;/li>
&lt;/ul>
&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>
&lt;ul>
&lt;li>Microservices - N clients, M servers in the data center&lt;/li>
&lt;li>Very high performance requirements (low latency, high traffic)&lt;/li>
&lt;li>Client can be untrusted&lt;/li>
&lt;/ul>
&lt;/td>
&lt;td>
&lt;ul>
&lt;li>Look-aside Load Balancing&lt;/li>
&lt;li>Client-side LB using &lt;a href="https://github.com/grpc/grpc/blob/master/doc/load-balancing.md" target="_blank" rel="noopener">gRPC-LB protocol&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. Roll your own implementation (Q2’17), hosted gRPC-LB in the works.&lt;/li>
&lt;/ul>
&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>
&lt;ul>
&lt;li>Existing Service-mesh like setup using Linkerd or Istio&lt;/li>
&lt;/ul>
&lt;/td>
&lt;td>
&lt;ul>
&lt;li>Service Mesh&lt;/li>
&lt;li>Use built-in LB with &lt;a href="https://istio.io/" target="_blank" rel="noopener">Istio&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, or &lt;a href="https://github.com/lyft/envoy" target="_blank" rel="noopener">Envoy&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/li>
&lt;/ul>
&lt;/td>
&lt;/tr>
&lt;/table></description></item><item><title>Blog: gRPC in Helm</title><link>https://grpc.io/blog/helm-grpc/</link><pubDate>Mon, 15 May 2017 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/helm-grpc/</guid><description>
&lt;p>Helm is the package manager for Kubernetes. Helm provides its users with a customizable mechanism for
managing distributed applications and controlling their deployment.&lt;/p>
&lt;p>I have the good fortune to be a member of the phenomenal open-source Kubernetes Helm community serving as
a core contributor. My first day working with the Helm team was spent prototyping the architecture for
the next generation of Helm. By the end of that day, we had procured the preliminary RPC protocol data model
used to enable communication between Helm and its in-cluster server component, Tiller.&lt;/p>
&lt;p>We chose to use protocol buffers - the default framework gRPC uses for serialization and over-the-air
transmission - as our data definition language. By the end of that first day hacking with the Helm team,
gRPC and protocol buffers proved to be a powerful combination. We had successfully had achieved communication
between the Helm client and Tiller server using code generated from the protobuf and gRPC service definitions.
As a personal preference, we found that the protobuf files and resulting generated gRPC
code provided an aesthetic, nearly self-documenting developer experience compared to something like Swagger.&lt;/p>
&lt;p>Within a few days, the Helm team was scoping and implementing features for our users. By choosing gRPC/Proto
we had reduced the typical time spent bikeshedding that, in general, inevitably evolves from API modeling and
churning out boilerplate server code. If we had not reaped the benefits of gRPC/protobuf from day 1, we would
have spent significantly more time pivoting up and down the stack, as opposed to honing our focus on what
matters: the users and the features they requested.&lt;/p>
&lt;p>In addition to serving as the Helm/Tiller communication protocol, one of our more interesting applications
of protocol buffers is that we use it to model what&amp;rsquo;s referred to in Kubernetes parlance as a &amp;ldquo;Chart&amp;rdquo;. Charts
are an encapsulation of Kubernetes manifests that enable you to define, install, and upgrade Kubernetes applications.
For more complex Kubernetes applications, the set of manifests may be large. By virtue of its inherent compression
capabilities, protocol buffers and gRPC allowed us to mitigate the nuisance of transmitting bulky and
sprawling Kubernetes manifests.&lt;/p>
&lt;p>For a deeper dive into:&lt;/p>
&lt;ul>
&lt;li>The Helm proto, see: &lt;a href="https://github.com/kubernetes/helm/tree/master/_proto/hapi" target="_blank" rel="noopener">https://github.com/kubernetes/helm/tree/master/_proto/hapi&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>Its generated counterpart, see: &lt;a href="https://github.com/kubernetes/helm/tree/master/pkg/proto/hapi" target="_blank" rel="noopener">https://github.com/kubernetes/helm/tree/master/pkg/proto/hapi&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>The interface to our Helm client, see: &lt;a href="https://github.com/kubernetes/helm/tree/master/pkg/helm" target="_blank" rel="noopener">https://github.com/kubernetes/helm/tree/master/pkg/helm&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>In summary, protobuf and gRPC provided Helm with:&lt;/p>
&lt;ul>
&lt;li>Clearly defined message and protocol semantics for client and server communications.&lt;/li>
&lt;li>Increased feature development via a reduction in time spent on boilerplate server code / API modeling.&lt;/li>
&lt;li>High performance transmission of data through generated code and compression.&lt;/li>
&lt;li>Minimized cognitive cycles spent going from 0 to client/server communications.&lt;/li>
&lt;/ul></description></item><item><title>Blog: Migration to Google Cloud Platform — gRPC &amp; grpc-gateway</title><link>https://grpc.io/blog/yikyak/</link><pubDate>Wed, 12 Apr 2017 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/yikyak/</guid><description>
&lt;p>In our previous blog &lt;a href="https://medium.com/yik-yak-eng/migration-to-google-cloud-platform-overview-9b5e5c17c368" target="_blank" rel="noopener">post&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> we gave an overview of our migration to Google Cloud Platform from Amazon Web Services. In this post we will drill down into the role that &lt;a href="https://grpc.io/">gRPC&lt;/a> and &lt;a href="https://github.com/grpc-ecosystem/grpc-gateway" target="_blank" rel="noopener">grpc-gateway&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> played in that migration and share some lessons which we picked up along the way.&lt;/p>
&lt;h2 id="most-people-have-rest-apis-dont-you-whats-the-problem">Most people have REST APIs, don’t you? What’s the problem?&lt;/h2>
&lt;p>Yes, we actually still have REST APIs that clients use because migrating the client APIs was out of scope. To be fair, you can make REST APIs work and there are a lot of useful REST APIs out there. Having said that, the issues that we had with REST lie in the details.&lt;/p>
&lt;h3 id="no-canonical-rest-specification">No Canonical REST Specification&lt;/h3>
&lt;p>There is no single REST specification that is canonical. There are best practices, but no true canon. For that reason, there isn’t unanimous agreement on when to use specific HTTP methods and response codes. Beyond that, not all of the possible HTTP methods and response codes are supported across all platforms… This forces REST API implementers to compensate for these deficiencies using techniques that work for them but create more variance in REST APIs across the board. At best, REST APIs are really REST-ish dialects.&lt;/p>
&lt;h3 id="harder-on-developers">Harder on Developers&lt;/h3>
&lt;p>REST APIs aren’t exactly great from a developer’s standpoint either.
First, because REST is tied to HTTP there is no simple mapping to an API in my language of choice. If I’m using Go or Java there is no “interface” that I can use in my code to stub it out. I can create one, but it is extra-linguistic to the REST API definition.&lt;/p>
&lt;p>Second, REST APIs spread information that is necessary to interpreting the intent of the request across various components of the request. You have the HTTP method, the request URI, the request payload, and it can get even more complicated if request headers are involved in the semantics.&lt;/p>
&lt;p>Third, it is great that I can use curl from the command line to hit an API, but it comes at the cost of having to shoehorn the API into that ecosystem. Normally that use case only matters for letting people quickly try out an API — and if that is high on your list of requirements then by all means feel free to use REST… Just keep it simple.&lt;/p>
&lt;h3 id="no-declarative-rest-api-description">No Declarative REST API Description&lt;/h3>
&lt;p>The fourth problem with a REST APIs is that, at least until &lt;a href="https://swagger.io/" target="_blank" rel="noopener">Swagger&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> arrived on the scene, there was no declarative way to define a REST API and include type information. It may sound pedantic, but there are legitimate reasons to want a proper definition that includes type information in general. To reinforce the point, look at the lines of PHP server code below, which were extracted from various files, that set the “hidePin” field on “yak” which was then returned to the client. The actual line of code that executed on the server was a function of multiple parameters, so imagine that the one which was run was basically chosen at random:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// Code omitted…
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>&lt;span style="color:#033">$yak&lt;/span>&lt;span style="color:#555">-&amp;gt;&lt;/span>&lt;span style="color:#309">hidePin&lt;/span>&lt;span style="color:#555">=&lt;/span>&lt;span style="color:#069;font-weight:bold">false&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// Code omitted…
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>&lt;span style="color:#033">$yak&lt;/span>&lt;span style="color:#555">-&amp;gt;&lt;/span>&lt;span style="color:#309">hidePin&lt;/span>&lt;span style="color:#555">=&lt;/span>&lt;span style="color:#069;font-weight:bold">true&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// Code omitted…
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>&lt;span style="color:#033">$yak&lt;/span>&lt;span style="color:#555">-&amp;gt;&lt;/span>&lt;span style="color:#309">hidePin&lt;/span>&lt;span style="color:#555">=&lt;/span>&lt;span style="color:#f60">0&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// Code omitted…
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>&lt;span style="color:#033">$yak&lt;/span>&lt;span style="color:#555">-&amp;gt;&lt;/span>&lt;span style="color:#309">hidePin&lt;/span>&lt;span style="color:#555">=&lt;/span>&lt;span style="color:#f60">1&lt;/span>;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>What is the type of the field hidePin? You cannot say for certain. It could be a boolean or an integer or whatever happens to have been written there by the server, but in any case now your clients have to be able to deal with these possibilities which makes them more complicated.&lt;/p>
&lt;p>Problems can also arise when the client’s definition of a type varies from that which the server expects. Have a look at the server code below which processed a JSON payload sent up by a client:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// Code omitted...
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>&lt;span style="color:#069;font-weight:bold">switch&lt;/span> (&lt;span style="color:#033">$fieldName&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// Code omitted...
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#069;font-weight:bold">case&lt;/span> “recipientID”&lt;span style="color:#555">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// This is being added because iOS is passing the recipientID
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#09f;font-style:italic">// incorrectly and we still want to capture these events
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#09f;font-style:italic">// … expected fall through …
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">case&lt;/span> “Recipientid”&lt;span style="color:#555">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#033">$this&lt;/span>&lt;span style="color:#555">-&amp;gt;&lt;/span>&lt;span style="color:#309">yakkerEvent&lt;/span>&lt;span style="color:#555">-&amp;gt;&lt;/span>&lt;span style="color:#309">recipientID&lt;/span> &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#033">$value&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">break&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// Code omitted...
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// Code omitted...
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>In this case, the server had to deal with an iOS client that sent a JSON object whose field name used unexpected casing. Again, not insurmountable but all of these little disconnects compound and work together to steal time away from the problems that really move the ball down the field.&lt;/p>
&lt;h2 id="grpc-can-address-the-issues-with-rest">gRPC can address the issues with REST&lt;/h2>
&lt;p>If you’re not familiar with gRPC, it’s a “high performance, open-source universal remote procedure call (RPC) framework” that uses Google Protocol Buffers as the Interface Description Language (IDL) for describing a service interface as well as the structure of the messages exchanged. This IDL can then be compiled to produce language-specific client and server stubs. In case that seemed a little obtuse, I’ll zoom into the aspects that are important.&lt;/p>
&lt;h3 id="grpc-is-declarative-strongly-typed-and-language-independent">gRPC is Declarative, Strongly-Typed, and Language Independent&lt;/h3>
&lt;p>gRPC descriptions are written using an Interface Description Language that is independent of any specific programming language, yet its concepts map onto the supported languages. This means that you can describe your ideal service API, the messages that it supports, and then use “protoc”, the protocol compiler, to generate client and server stubs for your API. Out of the box, you can produce client and server stubs in C/C++, C#, Node.js, PHP, Ruby, Python, Go and Java. You can also get additional protoc plugins which can create stubs for Objective-C and Swift.&lt;/p>
&lt;p>Those issues that we had with “hidePin” and “recipientID” vs.”Recipientid” fields above go away because we have a single, canonical declaration that establishes the types used, and the language-specific code generation ensures that we don’t have typos in the client or server code regardless of their implementation language.&lt;/p>
&lt;h3 id="grpc-means-no-hand-rolling-of-rpc-code-is-required">gRPC Means No hand-rolling of RPC Code is Required&lt;/h3>
&lt;p>This is a very powerful aspect of the gRPC ecosystem. Often times developers will hand roll their RPC code because it just seems more straightforward. However, as the number of types of clients that you need to support increases, the carrying costs of this approach also increase non-linearly.
Imagine that you start off with a service that is called from a web browser. At some point down the road, the requirements are updated and now you have to support Android and iOS clients. Your server is likely fine, but the clients now need to be able to speak the same RPC dialect and often times there are differences that creep in. Things can get even worse if the server has to compensate for the differences amongst the clients.
On the other hand, using gRPC you just add the protocol compiler plugins and they generate the Android and iOS client stubs. This cuts out a whole class of problems. As a bonus, if you don’t modify the generated code — and you should not have to — then any performance improvements in the generated code will be picked up.&lt;/p>
&lt;h3 id="grpc-has-compact-serialization">gRPC has Compact Serialization&lt;/h3>
&lt;p>gRPC uses Google protocol buffers to serialize messages. This serialization format is very compact because, among other things, field names are not included in the serialized form. Compare this to a JSON object where each instance of an object carries a full copy of its field names, includes extra curly braces, etc. For a low-volume application this may not be an issue, but it can add up quickly.&lt;/p>
&lt;h3 id="grpc-tooling-is-extensible">gRPC Tooling is Extensible&lt;/h3>
&lt;p>Another very useful feature of the gRPC framework is that it is extensible. If you need support for a language that is not currently supported, there is a way to create plugins for the protocol compiler that allows you to add what you need.&lt;/p>
&lt;h3 id="grpc-supports-contract-updates">gRPC Supports Contract Updates&lt;/h3>
&lt;p>An often overlooked aspect of service APIs is how they may evolve over time. At best, this is often a secondary consideration. If you are using gRPC, and you adhered to a few basic rules, your messages can be forward and backward compatible.&lt;/p>
&lt;h2 id="grpc-gatewaybecause-rest-will-be-with-us-for-a-while">Grpc-gateway — because REST will be with us for a while…&lt;/h2>
&lt;p>You’re probably thinking: gRPC is great but I have a ton of REST clients to deal with. Well, there is another tool in this ecosystem and it is called grpc-gateway. Grpc-gateway “generates a reverse-proxy server which translates a RESTful JSON API into gRPC”. So if you want to support REST clients you can, and it doesn’t cost you any real extra effort.
If your existing REST clients are pretty far from the normal REST APIs, you can use custom marshallers with grpc-gateway to compensate.&lt;/p>
&lt;h2 id="migration-and-grpc--grpc-gateway">Migration and gRPC + grpc-gateway&lt;/h2>
&lt;p>As mentioned previously, we had a lot of PHP code and REST endpoints which we wanted to rework as part of the migration. By using the combination of gRPC and grpc-gateway, we were able to define gRPC versions of the legacy REST APIs and then use grpc-gateway to expose the exact REST endpoints that clients were used to. With these alternative implementations in place we were able to move traffic between the old and new systems using combinations of DNS updates as well as our &lt;a href="https://medium.com/yik-yak-eng/yik-yak-configuration-and-experiment-system-16a5c15ee77c#.7s11d3kqh" target="_blank" rel="noopener">Experimentation and Configuration System&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> without causing any disruption to the existing clients. We were even able to leverage the existing test suites to verify functionality and establish parity between the old and new systems.
Lets walk through the pieces and how they fit together.&lt;/p>
&lt;h3 id="grpc-idl-for-apigetmessages">gRPC IDL for “/api/getMessages”&lt;/h3>
&lt;p>Below is the gRPC IDL that we defined to mimic the legacy Yik Yak API in GCP. We’ve simplified the example to only contain the “/api/getMessages” endpoint which clients use to get the set of messages centered around their current location.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-proto" data-lang="proto">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// APIRequest Message — sent by clients
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>&lt;span style="color:#069;font-weight:bold">message&lt;/span> &lt;span style="color:#0a8;font-weight:bold">APIRequest&lt;/span> {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#09f;font-style:italic">// userID is the ID of the user making the request
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#078;font-weight:bold">string&lt;/span> userID &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">1&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#09f;font-style:italic">// Other fields omitted for clarity…
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>}&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#09f;font-style:italic">// APIFeedResponse contains the set of messages that clients should
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// display.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>&lt;span style="color:#069;font-weight:bold">message&lt;/span> &lt;span style="color:#0a8;font-weight:bold">APIFeedResponse&lt;/span> {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#069;font-weight:bold">repeated&lt;/span> APIPost messages &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">1&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#09f;font-style:italic">// Other fields omitted for clarity…
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>}&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#09f;font-style:italic">// APIPost defines the set of post fields returned to the clients.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>&lt;span style="color:#069;font-weight:bold">message&lt;/span> &lt;span style="color:#0a8;font-weight:bold">APIPost&lt;/span> {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#078;font-weight:bold">string&lt;/span> messageID &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">1&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#078;font-weight:bold">string&lt;/span> &lt;span style="color:#069;font-weight:bold">message&lt;/span> &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">2&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#09f;font-style:italic">// Other fields omitted for clarity…
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>}&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>&lt;span style="color:#09f;font-style:italic">// YYAPI service accessed by Android, iOS and Web clients.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>&lt;span style="color:#069;font-weight:bold">service&lt;/span> YYAPI {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#09f;font-style:italic">// Other endpoints omitted…
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#09f;font-style:italic">// APIGetMessages returns the list of messages within a radius of
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#09f;font-style:italic">// the user’s current location.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#069;font-weight:bold">rpc&lt;/span> APIGetMessages (APIRequest) &lt;span style="color:#069;font-weight:bold">returns&lt;/span> (APIFeedResponse) {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#069;font-weight:bold">option&lt;/span> (google.api.http) &lt;span style="color:#555">=&lt;/span> {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> get&lt;span style="color:#555">:&lt;/span> &lt;span style="color:#a00;background-color:#faa">“&lt;/span>&lt;span style="color:#555">/&lt;/span>api&lt;span style="color:#555">/&lt;/span>getMessages&lt;span style="color:#a00;background-color:#faa">”&lt;/span> &lt;span style="color:#09f;font-style:italic">// Option tells grpc-gateway that an HTTP
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#09f;font-style:italic">// GET to /api/getMessages should be
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#09f;font-style:italic">// routed to the APIGetMessages gRPC
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#09f;font-style:italic">// endpoint.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> };&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> }&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#09f;font-style:italic">// Other endpoints omitted…
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>}&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="protoc-generated-go-interfaces-for-yyapi-service">Protoc Generated Go Interfaces for YYAPI Service&lt;/h3>
&lt;p>The IDL above is then compiled to Go files by the protoc compiler to produce client proxies and server stubs as below.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// Client API for YYAPI service
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>&lt;span style="color:#069;font-weight:bold">type&lt;/span> YYAPIClient &lt;span style="color:#069;font-weight:bold">interface&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c0f">APIGetMessages&lt;/span>(ctx context.Context, in &lt;span style="color:#555">*&lt;/span>APIRequest, opts &lt;span style="color:#555">...&lt;/span>grpc.CallOption) (&lt;span style="color:#555">*&lt;/span>APIFeedResponse, &lt;span style="color:#078;font-weight:bold">error&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// NewYYAPIClient returns an implementation of the YYAPIClient interface which
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// clients can use to call the gRPC service.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>&lt;span style="color:#069;font-weight:bold">func&lt;/span> &lt;span style="color:#c0f">NewYYAPIClient&lt;/span>(cc &lt;span style="color:#555">*&lt;/span>grpc.ClientConn) YYAPIClient {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// Code omitted for clarity..
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// Server API for YYAPI service
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>&lt;span style="color:#069;font-weight:bold">type&lt;/span> YYAPIServer &lt;span style="color:#069;font-weight:bold">interface&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c0f">APIGetMessages&lt;/span>(context.Context, &lt;span style="color:#555">*&lt;/span>APIRequest) (&lt;span style="color:#555">*&lt;/span>APIFeedResponse, &lt;span style="color:#078;font-weight:bold">error&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// RegisterYYAPIServer registers an implementation of the YYAPIServer with an
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// existing gRPC server instance.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>&lt;span style="color:#069;font-weight:bold">func&lt;/span> &lt;span style="color:#c0f">RegisterYYAPIServer&lt;/span>(s &lt;span style="color:#555">*&lt;/span>grpc.Server, srv YYAPIServer) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// Code omitted for clarity..
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="grpc-gateway-generated-go-code-for-rest-reverse-proxy-of-yyapi-service">Grpc-gateway Generated Go-code for REST Reverse Proxy of YYAPI Service&lt;/h3>
&lt;p>By using the google.api.http option in our IDL above, we tell the grpc-gateway system that it should route HTTP GETs for “/api/getMessages” to the APIGetMessages gRPC endpoint. In turn, it creates the HTTP to gRPC reverse proxy and allows you to set it up by calling the generated function below.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// RegisterYYAPIHandler registers the http handlers for service YYAPI to “mux”.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// The handlers forward requests to the grpc endpoint over “conn”.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>&lt;span style="color:#069;font-weight:bold">func&lt;/span> &lt;span style="color:#c0f">RegisterYYAPIHandler&lt;/span>(ctx context.Context, mux &lt;span style="color:#555">*&lt;/span>runtime.ServeMux, conn &lt;span style="color:#555">*&lt;/span>grpc.ClientConn) &lt;span style="color:#078;font-weight:bold">error&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// Code omitted for clarity
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>So again, from a single gRPC IDL description you can obtain client and server interfaces and implementation stubs in your language of choice as well as REST reverse proxies for free.&lt;/p>
&lt;h2 id="grpci-heard-there-were-some-rough-edges">gRPC — I heard there were some rough edges?&lt;/h2>
&lt;p>We started working with gRPC for Go late in Q1 of 2016 and there were definitely some rough edges at the time.&lt;/p>
&lt;h3 id="early-adopter-issues">Early Adopter Issues&lt;/h3>
&lt;p>We ran into &lt;a href="https://github.com/grpc/grpc-go/issues/674" target="_blank" rel="noopener">Issue 674&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, a resource leak inside of the Go gRPC client code which could cause gRPC transports to hang when under heavy load. The gRPC team was very responsive and the fix was merged into the master branch within days.&lt;/p>
&lt;p>We ran into a resource leak in the generated code for grpc-gateway. However, by the time we found that issue, it had already been fixed by that team and merged into master.&lt;/p>
&lt;p>The last early-adopter type issue that we ran into was around the Go’s gRPC client not supporting the GOAWAY packet that was part of the gRPC protocol spec. Fortunately, this one did not impact us in production. It only manifested during the repo case we had put together for Issue 674.&lt;/p>
&lt;p>All in all this was fairly reasonable given how early we were.&lt;/p>
&lt;h3 id="load-balancing">Load Balancing&lt;/h3>
&lt;p>Now, if you are going to use gRPC this is definitely one area that you need to think through carefully. By default, gRPC uses HTTP2 instead of HTTP1. HTTP2 is able to open a connection to a server and reuse it for multiple requests among other things. If you use it in that mode, you won’t distribute requests amongst all of the servers in your load balancing pool. At the time that we executing the migration, existing load balancers didn’t handle HTTP2 traffic very well if at all.&lt;/p>
&lt;p>At the time the gRPC team didn’t have a &lt;a href="https://github.com/grpc/grpc/blob/master/doc/load-balancing.md" target="_blank" rel="noopener">Load Balancing Proposal&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, so we burned a lot of cycles trying to force our system to do some type of client-side load balancing. In the end, since most of our raw gRPC communications took place within the data center, and everything was deployed using Kubernetes, it was simpler to dial the remote server every time thereby forcing the system to spread the load out amongst the servers in the Kubernetes Service. Given our setup it only added about 1 ms to the overall response time, so it was a simple work around.&lt;/p>
&lt;p>So was that the end of the load balancing issues? Not exactly. Once we had our basic gRPC-based system up and running we started running load tests against it, and noticed some interesting behaviors. Below is the per gRPC server CPU load graph over time, do you notice anything curious about it?&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/yy-cpu-imbalance.png" id="yy-cpu-imbalance" data-toggle="modal" data-target="#modal-yy-cpu-imbalance"/>
&lt;div class="modal" id="modal-yy-cpu-imbalance">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/yy-cpu-imbalance.png" />
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>The server with the heaviest load was running at around 50% CPU, while the most lightly loaded server was running at around 20% CPU even after several minutes of warmup. It turned out that even though we were dialing every time, we had an &lt;a href="https://nghttp2.org/" target="_blank" rel="noopener">nghttp2&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> ingress as part of our network topology which would tend to send inbound requests to servers to whom it had already connected and thereby causing uneven distribution. After removing the nghttp2 ingress, our CPU graphs showed much less variance in the load distribution.&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/yy-cpu-balanced.png" id="yy-cpu-balanced" data-toggle="modal" data-target="#modal-yy-cpu-balanced"/>
&lt;div class="modal" id="modal-yy-cpu-balanced">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/yy-cpu-balanced.png" />
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>REST APIs have their issues, but they are not going away anytime soon. If you are up for trying something a little cleaner, then definitely consider using gRPC (along with grpc-gateway if you still need to expose a REST API). Even though we hit some issues early on, gRPC was a net gain for us. It gave us a path forward to more tightly defined APIs. It also allowed us to stand up new implementations of the legacy REST APIs in GCP which teed us up to seamlessly migrate traffic from the AWS implementations to the new GCP ones in a controlled manner.&lt;/p>
&lt;p>Having discussed our use of Go, gRPC and Google Cloud Platform, we are ready to discuss how we built a new geo store on top of Google Bigtable and the Google S2 Library — the subject of our next post.&lt;/p></description></item><item><title>Blog: Building gRPC services with bazel and rules_protobuf</title><link>https://grpc.io/blog/bazel-rules-protobuf/</link><pubDate>Thu, 13 Oct 2016 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/bazel-rules-protobuf/</guid><description>
&lt;p>&lt;a href="https://grpc.io/">gRPC&lt;/a> makes it easier to build high-performance
microservices by providing generated service entrypoints in a variety
of different languages. &lt;a href="https://bazel.io" target="_blank" rel="noopener">Bazel&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> complements these
efforts with a capable and fast polyglot build environment.&lt;/p>
&lt;p>&lt;a href="https://github.com/pubref/rules_protobuf" target="_blank" rel="noopener">rules_protobuf&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> extends
bazel and makes it easier develop gRPC services.&lt;/p>
&lt;p>It does this by:&lt;/p>
&lt;ol>
&lt;li>Building &lt;code>protoc&lt;/code> (the protocol buffer compiler) and all the
necessary &lt;code>protoc-gen-*&lt;/code> plugins.&lt;/li>
&lt;li>Building the protobuf and gRPC libraries required for gRPC-related
code to compile.&lt;/li>
&lt;li>Abstracting away &lt;code>protoc&lt;/code> plugin invocation (you don&amp;rsquo;t have to
necessarily learn or remember how to call &lt;code>protoc&lt;/code>).&lt;/li>
&lt;li>Regenerating and recompiling outputs when protobuf source files
change.&lt;/li>
&lt;/ol>
&lt;p>In this post I&amp;rsquo;ll provide background about how bazel works
(&lt;a href="#about-bazel">Part 1&lt;/a>) and how to get started building gRPC
services with rules_protobuf
(&lt;a href="#building">Part 2&lt;/a>). If
you&amp;rsquo;re already a bazel aficionado, you can skip directly to Part 2.&lt;/p>
&lt;p>To best follow along,
&lt;a href="https://www.bazel.io/versions/master/docs/install.html" target="_blank" rel="noopener">install bazel&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
and clone the rules_protobuf repository:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>git clone https://github.com/pubref/rules_protobuf
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#366">cd&lt;/span> rules_protobuf
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/rules_protobuf$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Great. Let&amp;rsquo;s get started!&lt;/p>
&lt;h1 id="about-bazel">1: About Bazel&lt;/h1>
&lt;p>&lt;a href="https://www.bazel.io/" target="_blank" rel="noopener">Bazel&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> is Google&amp;rsquo;s open-source version of
their internal build tool called &amp;ldquo;Blaze&amp;rdquo;. Blaze originated from the
challenges of managing a large monorepo with code written in a variety
of languages. Blaze was the inspiration for other capable and fast
build tools including &lt;a href="https://www.pantsbuild.org/" target="_blank" rel="noopener">Pants&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> and
&lt;a href="https://buckbuild.com/" target="_blank" rel="noopener">Buck&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. Bazel is conceptually simple but
there are some core concepts &amp;amp; terminology to understand:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Bazel command&lt;/strong>: a function that does some type of work when
called from the command line. Common ones include &lt;code>bazel build&lt;/code>
(compile a library), &lt;code>bazel run&lt;/code> (run a binary executable), &lt;code>bazel test&lt;/code> (execute tests), and &lt;code>bazel query&lt;/code> (tell me something about
the build dependency graph). See all with &lt;code>bazel help&lt;/code>.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Build phases&lt;/strong>: the three stages (loading, analysis, and
execution) that bazel goes through when calling a bazel command.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>The WORKSPACE file&lt;/strong>: a required file that defines the project
root. It is primarily used to declare external dependencies
(external workspaces).&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>BUILD files&lt;/strong>: the presence of a &lt;code>BUILD&lt;/code> file in a directory
defines it as a &lt;em>package&lt;/em>. &lt;code>BUILD&lt;/code> files contain &lt;em>rules&lt;/em> that define
&lt;em>targets&lt;/em> which can be selected using the &lt;em>target pattern syntax&lt;/em>.
Rules are written in a python-like language called
&lt;a href="https://bazel.io/versions/master/docs/skylark/index.html" target="_blank" rel="noopener">&lt;em>skylark&lt;/em>&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.
Syklark has stronger deterministic guarantees than python but is
intentionally minimal, excluding language features such as recursion,
classes, and lambdas.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h2 id="11-package-structure">1.1: Package Structure&lt;/h2>
&lt;p>To illustrate these concepts, let&amp;rsquo;s look at the package structure of
the
&lt;a href="https://github.com/pubref/rules_protobuf/tree/master/examples" target="_blank" rel="noopener">rules_protobuf examples subdirectory&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.
Let&amp;rsquo;s look at the file tree, showing only those folder having a
&lt;code>BUILD&lt;/code> file:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-diff" data-lang="diff">&lt;span style="display:flex;">&lt;span>tree -P &amp;#39;BUILD|WORKSPACE&amp;#39; -I &amp;#39;third_party|bzl&amp;#39; examples/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>├── BUILD
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>├── WORKSPACE
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>└── examples
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    ├── helloworld
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    │   ├── cpp
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    │   │   └── BUILD
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    │   ├── go
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    │   │   ├── client
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    │   │   │   └── BUILD
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    │   │   ├── greeter_test
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    │   │   │   └── BUILD
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    │   │   └── server
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    │   │   └── BUILD
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    │   ├── grpc_gateway
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    │   │   └── BUILD
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    │   ├── java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    │   │   └── org
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    │   │   └── pubref
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    │   │   └── rules_protobuf
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    │   │   └── examples
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    │   │   └── helloworld
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    │   │   ├── client
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    │   │   │   └── BUILD
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    │   │   └── server
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    │   │   └── BUILD
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    │   └── proto
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    │      └── BUILD
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    └── proto
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>    └── BUILD
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="12-targets">1.2: Targets&lt;/h2>
&lt;p>To get a list of targets within the &lt;code>examples/&lt;/code> folder, use a query.
This says &lt;em>&amp;ldquo;Ok bazel, show me all the callable targets in all packages
within the examples folder, and say what kind of thing it is in
addition to its path label&amp;rdquo;&lt;/em>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>~/rules_protobuf$ bazel query //examples/... --output label_kind | sort | column -t
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cc_binary rule //examples/helloworld/cpp:client
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cc_binary rule //examples/helloworld/cpp:server
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cc_library rule //examples/helloworld/cpp:clientlib
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cc_library rule //examples/helloworld/proto:cpp
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cc_library rule //examples/proto:cpp
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cc_proto_compile rule //examples/helloworld/proto:cpp.pb
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cc_proto_compile rule //examples/proto:cpp.pb
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cc_test rule //examples/helloworld/cpp:test
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>filegroup rule //examples/helloworld/proto:protos
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>filegroup rule //examples/proto:protos
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>go_binary rule //examples/helloworld/go/client:client
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>go_binary rule //examples/helloworld/go/server:server
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>go_library rule //examples/helloworld/go/server:greeter
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>go_library rule //examples/helloworld/grpc_gateway:gateway
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>go_library rule //examples/helloworld/proto:go
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>go_library rule //examples/proto:go_default_library
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>go_proto_compile rule //examples/helloworld/proto:go.pb
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>go_proto_compile rule //examples/proto:go_default_library.pb
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>go_test rule //examples/helloworld/go/greeter_test:greeter_test
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>go_test rule //examples/helloworld/grpc_gateway:greeter_test
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>grpc_gateway_proto_compile rule //examples/helloworld/grpc_gateway:gateway.pb
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>java_binary rule //examples/helloworld/java/org/pubref/rules_protobuf/examples/helloworld/client:netty
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>java_binary rule //examples/helloworld/java/org/pubref/rules_protobuf/examples/helloworld/server:netty
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>java_library rule //examples/helloworld/java/org/pubref/rules_protobuf/examples/helloworld/client:client
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>java_library rule //examples/helloworld/java/org/pubref/rules_protobuf/examples/helloworld/server:server
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>java_library rule //examples/helloworld/proto:java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>java_library rule //examples/proto:java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>java_proto_compile rule //examples/helloworld/proto:java.pb
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>java_proto_compile rule //examples/proto:java.pb
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>js_proto_compile rule //examples/helloworld/proto:js
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>js_proto_compile rule //examples/proto:js
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>py_proto_compile rule //examples/helloworld/proto:py.pb
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ruby_proto_compile rule //examples/proto:rb.pb
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>We&amp;rsquo;re not limited to targets in our own workspace. As it turns out,
the &lt;a href="https://github.com/google/protobuf" target="_blank" rel="noopener">Google Protobuf repo&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> is
named as an external repository (more on this later) and we can also
address targets in that workspace in the same way. Here&amp;rsquo;s a partial
list:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>~/rules_protobuf$ bazel query @com_github_google_protobuf//... --output label_kind | sort | column -t
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cc_binary rule @com_github_google_protobuf//:protoc
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cc_library rule @com_github_google_protobuf//:protobuf
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cc_library rule @com_github_google_protobuf//:protobuf_lite
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cc_library rule @com_github_google_protobuf//:protoc_lib
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cc_library rule @com_github_google_protobuf//util/python:python_headers
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>filegroup rule @com_github_google_protobuf//:well_known_protos
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>java_library rule @com_github_google_protobuf//:protobuf_java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>objc_library rule @com_github_google_protobuf//:protobuf_objc
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>py_library rule @com_github_google_protobuf//:protobuf_python
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This is possible because the protobuf team provides a
&lt;a href="https://github.com/google/protobuf/blob/master/BUILD" target="_blank" rel="noopener">BUILD file&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> at
the root of their repository. Thanks Protobuf team! Later we&amp;rsquo;ll
learn how to &amp;ldquo;inject&amp;rdquo; our own BUILD files into repositories that don&amp;rsquo;t
already have one.&lt;/p>
&lt;p>Inspecting the list above, we see a &lt;code>cc_binary&lt;/code> rule named &lt;code>protoc&lt;/code>.
If we &lt;code>bazel run&lt;/code> that target, bazel will clone the protobuf repo,
build all the dependent libraries, build a pristine executable binary
from source, and call it (pass command line arguments to binary rules
after the double-dash):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>~/rules_protobuf$ bazel run @com_github_google_protobuf//:protoc -- --help
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Usage: /private/var/tmp/_bazel_pcj/63330772b4917b139280caef8bb81867/execroot/rules_protobuf/bazel-out/local-fastbuild/bin/external/com_github_google_protobuf/protoc &lt;span style="color:#555">[&lt;/span>OPTION&lt;span style="color:#555">]&lt;/span> PROTO_FILES
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Parse PROTO_FILES and generate output based on the options given:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> -IPATH, --proto_path&lt;span style="color:#555">=&lt;/span>PATH Specify the directory in which to search &lt;span style="color:#069;font-weight:bold">for&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> imports. May be specified multiple times;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> directories will be searched in order. If not
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> given, the current working directory is used.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> --version Show version info and exit.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> -h, --help Show this text and exit.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>As we&amp;rsquo;ll see in a moment, &lt;em>we name the protobuf external dependency
with a specific commit ID so there&amp;rsquo;s no ambiguity about which protoc
version we&amp;rsquo;re using&lt;/em>. In this way you can vendor in tools with your
project with reliable, repeable, secure precision without bloating
your repository by checking in binaries, resorting to git submodules,
or similar hacks. Very clean!&lt;/p>
&lt;blockquote>
&lt;p>Note: the gRPC repository also has a BUILD file: &lt;code>$ bazel query @com_github_grpc_grpc//... --output label_kind&lt;/code>&lt;/p>
&lt;/blockquote>
&lt;h2 id="13-target-pattern-syntax">1.3: Target Pattern Syntax&lt;/h2>
&lt;p>With those examples under our belt, let&amp;rsquo;s examine the target syntax a
bit more. When I first started working with bazel I found the
target-pattern syntax somewhat intimidating. It&amp;rsquo;s actually not too
bad. Here&amp;rsquo;s a closer look:&lt;/p>
&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/target-pattern-syntax.png" id="target-pattern-syntax" data-toggle="modal" data-target="#modal-target-pattern-syntax"/>
&lt;div class="modal" id="modal-target-pattern-syntax">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/target-pattern-syntax.png" />
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;ul>
&lt;li>
&lt;p>The &lt;code>@&lt;/code> (at-sign) selects an external workspace. These are
established by
&lt;a href="https://bazel.io/docs/be/workspace.html#workspace-rules" target="_blank" rel="noopener">workspace rules&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
that bind a name to something fetched over the network (or your
filesystem).&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The &lt;code>//&lt;/code> (double-slash) selects the workspace root.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The &lt;code>:&lt;/code> (colon) selects a target (rule or file) within a &lt;em>package&lt;/em>.
Recall that a package is established by the presence of a &lt;code>BUILD&lt;/code>
file in a subfolder of the workspace.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The &lt;code>/&lt;/code> (single-slash) selects a folder within a workspace or
package.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>A common source of confusion is that the mere presence of a
BUILD file defines that filesystem subtree as a package and
therefore one must always account for that. For example, if there
exists a file &lt;code>qux.js&lt;/code> in &lt;code>foo/bar/baz/&lt;/code> and there exists a BUILD
file in &lt;code>baz/&lt;/code> also, the file is selected with &lt;code>foo/bar/baz:qux.js&lt;/code>
and not &lt;code>foo/bar/baz/quz.js&lt;/code>&lt;/p>
&lt;/blockquote>
&lt;p>&lt;em>Common shortcut&lt;/em>: if there exists a rule having the same name as the
package, this is the implied target and can be omitted. For example,
there is a &lt;code>:jar&lt;/code> target in the &lt;code>//jar&lt;/code> package in the external
workspace &lt;code>com_google_guava_guava&lt;/code>, so the following are equivalent:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>deps &lt;span style="color:#555">=&lt;/span> [&lt;span style="color:#c30">&amp;#34;@com_google_guava_guava//jar:jar&amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>deps &lt;span style="color:#555">=&lt;/span> [&lt;span style="color:#c30">&amp;#34;@com_google_guava_guava//jar&amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="14-external-dependencies-workspace-rules">1.4: External Dependencies: Workspace Rules&lt;/h2>
&lt;p>Many large organizations check-in in all the required tools,
compilers, linkers, etc to guarantee correct, repeatable builds. With
external workspaces, one can effectively accomplish the same thing
without bloating your repository.&lt;/p>
&lt;blockquote>
&lt;p>Note: the bazel convention is to use a fully-namespaced identifier
for external dependency names (replacing special chars with
underscore). For example, the remote repository URL is
&lt;a href="https://github.com/google/protobuf.git" target="_blank" rel="noopener">https://github.com/google/protobuf.git&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. This is simplified to the
workspace identifier com_github_google_protobuf. Similarly, by
convention the jar artifact &lt;code>io.grpc:grpc-netty:jar:1.0.0-pre1&lt;/code>
becomes &lt;code>io_grpc_grpc_netty&lt;/code>.&lt;/p>
&lt;/blockquote>
&lt;h3 id="141-workspace-rules-that-require-a-pre-existing-workspace">1.4.1: Workspace Rules that require a pre-existing WORKSPACE&lt;/h3>
&lt;p>These rules assume that the remote resource or URL contains a
WORKSPACE file at the top of the file tree and BUILD files that define
rule targets. These are referred to as &lt;em>bazel repositories&lt;/em>.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;a href="https://bazel.io/docs/be/workspace.html#git_repository" target="_blank" rel="noopener">git_repository&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>:
external bazel dependency from a git repository. The rule requires
&lt;code>commit&lt;/code> (or &lt;code>tag&lt;/code>).&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://bazel.io/docs/be/workspace.html#http_archive" target="_blank" rel="noopener">http_archive&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>:
an external zip or tar.gz dependency from a URL. It is highly
recommended to name a sha265 for security.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>Note: although you don&amp;rsquo;t interact directly with the bazel
execution_root, you can peek at what these external dependencies
look like when unpacked at &lt;code>$(bazel info execution_root)/external/WORKSPACE_NAME&lt;/code>.&lt;/p>
&lt;/blockquote>
&lt;h3 id="142-workspace-rules-that-autogenerate-a-workspace-file-for-you">1.4.2: Workspace Rules that autogenerate a WORKSPACE file for you&lt;/h3>
&lt;p>The implementation of these repository rules contain logic to
autogenerate a WORKSPACE file and BUILD file(s) to make resources
available. As always, it is recommended to provide a known sha265 for
security to prevent a malicious agent from slipping in tainted code
via a compromised network.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;a href="https://bazel.io/docs/be/workspace.html#http_jar" target="_blank" rel="noopener">http_jar&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>:
external jar from a URL. The jar file is available as a
&lt;code>java_library&lt;/code> dependency as &lt;code>@WORKSPACE_NAME//jar&lt;/code>.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://bazel.io/docs/be/workspace.html#maven_jar" target="_blank" rel="noopener">maven_jar&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>:
external jar from a URL. The jar file is available as a
&lt;code>java_library&lt;/code> dependency as &lt;code>@WORKSPACE_NAME//jar&lt;/code>.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://bazel.io/docs/be/workspace.html#http_file" target="_blank" rel="noopener">http_file&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>:
external file from a URL. The resource is available as a &lt;code>filegroup&lt;/code>
via &lt;code>@WORKSPACE_NAME//file&lt;/code>.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>For example, we can peek at the generated BUILD file for the
&lt;code>maven_jar&lt;/code> guava dependency via:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>~/rules_protobuf$ cat &lt;span style="color:#069;font-weight:bold">$(&lt;/span>bazel info execution_root&lt;span style="color:#069;font-weight:bold">)&lt;/span>/external/com_google_guava_guava/jar/BUILD
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"># DO NOT EDIT: automatically generated BUILD file for maven_jar rule com_google_guava_guava&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>java_import(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> name &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#c30">&amp;#39;jar&amp;#39;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> jars &lt;span style="color:#555">=&lt;/span> [&lt;span style="color:#c30">&amp;#39;guava-19.0.jar&amp;#39;&lt;/span>],
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> visibility &lt;span style="color:#555">=&lt;/span> [&lt;span style="color:#c30">&amp;#39;//visibility:public&amp;#39;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>filegroup(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> name &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#c30">&amp;#39;file&amp;#39;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> srcs &lt;span style="color:#555">=&lt;/span> [&lt;span style="color:#c30">&amp;#39;guava-19.0.jar&amp;#39;&lt;/span>],
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> visibility &lt;span style="color:#555">=&lt;/span> [&lt;span style="color:#c30">&amp;#39;//visibility:public&amp;#39;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>Note: the external workspace directory won&amp;rsquo;t exist until you
actually need it, so you&amp;rsquo;ll have to have built a target that
requires it, such as &lt;code>bazel build examples/helloworld/java/org/pubref/rules_protobuf/examples/helloworld/client&lt;/code>&lt;/p>
&lt;/blockquote>
&lt;h3 id="143-workspace-rules-that-accept-a-build-file-as-an-argument">1.4.3: Workspace Rules that accept a BUILD file as an argument&lt;/h3>
&lt;p>If a repository has no BUILD file(s), you can put one into its
filesystem root to adapt the external resource into bazel&amp;rsquo;s worldview
and make those resources available to your project.&lt;/p>
&lt;p>For example, consider
&lt;a href="https://github.com/madler/zlib" target="_blank" rel="noopener">Mark Adler&amp;rsquo;s zlib library&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. To start,
let&amp;rsquo;s learn what depends on this code. This query says &amp;ldquo;&lt;em>Ok bazel,
for all targets in examples, find all dependencies (a transitive
closure set), then tell me which ones depend on the zlib target in the
root package of the external workspace com_github_madler_zlib.&lt;/em>&amp;rdquo; Bazel
reports this reverse dependency set. We request the output in
graphviz format and pipe this to dot to generate the figure:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>~/rules_protobuf$ bazel query &lt;span style="color:#c30">&amp;#34;rdeps(deps(//examples/...), @com_github_madler_zlib//:zlib)&amp;#34;&lt;/span> &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span> --output graph | dot -Tpng -O
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>
&lt;figure class="text-center">
&lt;img class="modal-trigger" src="https://grpc.io/img/zlib-deps.png" id="zlib-deps" data-toggle="modal" data-target="#modal-zlib-deps"/>
&lt;div class="modal" id="modal-zlib-deps">
&lt;div class="modal-dialog modal-lg modal-dialog-centered">
&lt;div class="modal-body">
&lt;img src="https://grpc.io/img/zlib-deps.png" />
&lt;/div>
&lt;/div>
&lt;/figure>
&lt;/p>
&lt;p>So we can see that all grpc-related C code ultimately depends on this
library. But, there is no BUILD file in Mark&amp;rsquo;s repo&amp;hellip; where did it
come from?&lt;/p>
&lt;p>By using the variant workspace rule &lt;code>new_git_repository&lt;/code>, we can
provide our
&lt;a href="https://github.com/pubref/rules_protobuf/blob/master/protobuf/build_file/com_github_madler_zlib.BUILD" target="_blank" rel="noopener">own BUILD file&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
(which defines the &lt;code>cc_library&lt;/code> target) as follows:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>new_git_repository(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> name &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#c30">&amp;#34;com_github_madler_zlib&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> remote &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#c30">&amp;#34;https://github.com/madler/zlib&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> tag: &lt;span style="color:#c30">&amp;#34;v1.2.8&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> build_file: &lt;span style="color:#c30">&amp;#34;//bzl:build_file/com_github_madler_zlib.BUILD&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This &lt;code>new_*&lt;/code> family of workspace rules keeps your repository lean and
allows you to vendor in pretty much any type of network-available
resource. Awesome!&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://bazel.io/docs/be/workspace.html#new_git_repository" target="_blank" rel="noopener">new_git_repository&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://bazel.io/docs/be/workspace.html#new_local_repository" target="_blank" rel="noopener">new_local_repository&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://bazel.io/docs/be/workspace.html#new_http_archive" target="_blank" rel="noopener">new_http_archive&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>You can also
&lt;a href="https://bazel.io/docs/skylark/repository_rules.html" target="_blank" rel="noopener">write your own repository rules&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
that have custom logic to pull resources from the net and bind it
into bazel&amp;rsquo;s view of the universe.&lt;/p>
&lt;/blockquote>
&lt;h2 id="15-bazel-summary">1.5: Bazel Summary&lt;/h2>
&lt;p>When presented with a command and a target-pattern, bazel goes through
the following three phases:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Loading: Read the WORKSPACE and required BUILD files. Generate a
dependency graph.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Analysis: for all nodes in the graph, which nodes are actually
required for this build? Do we have all the necessary
resources available?&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Execution: execute each required node in the dependency graph and
generate outputs.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>Hopefully you now have enough conceptual knowledge of bazel to be
productive.&lt;/p>
&lt;h2 id="16-rules_protobuf">1.6: rules_protobuf&lt;/h2>
&lt;p>&lt;a href="https://github.com/pubref/rules_protobuf" target="_blank" rel="noopener">rules_protobuf&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> is an
extension to bazel that takes care of:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Building the protocol buffer compiler &lt;code>protoc&lt;/code>,&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Downloading and/or building all the necessary protoc-gen plugins.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Downloading and/or building all the necessary gRPC-related support
libraries.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Invoking protoc for you (on demand), smoothing out the
idiosyncrasies of different protoc plugins.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>It works by passing one or more &lt;code>proto_language&lt;/code> specifications to the
&lt;code>proto_compile&lt;/code> rule. A &lt;code>proto_language&lt;/code> rule contains the metadata
about how to invoke the plugin and the predicted file outputs, while
the &lt;code>proto_compile&lt;/code> rule interprets a &lt;code>proto_language&lt;/code> spec and builds
the appropriate command-line arguments to &lt;code>protoc&lt;/code>. For example,
here&amp;rsquo;s how we can generate outputs for multiple languages
simultaneously:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span> proto_compile(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> name &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#c30">&amp;#34;pluriproto&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> protos &lt;span style="color:#555">=&lt;/span> [&lt;span style="color:#c30">&amp;#34;:protos&amp;#34;&lt;/span>],
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> langs &lt;span style="color:#555">=&lt;/span> [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c30">&amp;#34;//cpp&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c30">&amp;#34;//csharp&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c30">&amp;#34;//closure&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c30">&amp;#34;//ruby&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c30">&amp;#34;//java&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c30">&amp;#34;//java:nano&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c30">&amp;#34;//python&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c30">&amp;#34;//objc&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c30">&amp;#34;//node&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ],
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> verbose &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">1&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> with_grpc &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">True&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> )
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>bazel build :pluriproto
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"># ************************************************************&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#366">cd&lt;/span> &lt;span style="color:#069;font-weight:bold">$(&lt;/span>bazel info execution_root&lt;span style="color:#069;font-weight:bold">)&lt;/span> &lt;span style="color:#555">&amp;amp;&amp;amp;&lt;/span> bazel-out/host/bin/external/com_github_google_protobuf/protoc &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span>--plugin&lt;span style="color:#555">=&lt;/span>protoc-gen-grpc-java&lt;span style="color:#555">=&lt;/span>bazel-out/host/genfiles/third_party/protoc_gen_grpc_java/protoc_gen_grpc_java &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span>--plugin&lt;span style="color:#555">=&lt;/span>protoc-gen-grpc&lt;span style="color:#555">=&lt;/span>bazel-out/host/bin/external/com_github_grpc_grpc/grpc_cpp_plugin &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span>--plugin&lt;span style="color:#555">=&lt;/span>protoc-gen-grpc-nano&lt;span style="color:#555">=&lt;/span>bazel-out/host/genfiles/third_party/protoc_gen_grpc_java/protoc_gen_grpc_java &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span>--plugin&lt;span style="color:#555">=&lt;/span>protoc-gen-grpc-csharp&lt;span style="color:#555">=&lt;/span>bazel-out/host/genfiles/external/nuget_grpc_tools/protoc-gen-grpc-csharp &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span>--plugin&lt;span style="color:#555">=&lt;/span>protoc-gen-go&lt;span style="color:#555">=&lt;/span>bazel-out/host/bin/external/com_github_golang_protobuf/protoc_gen_go &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span>--descriptor_set_out&lt;span style="color:#555">=&lt;/span>bazel-genfiles/examples/proto/pluriproto.descriptor_set &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span>--ruby_out&lt;span style="color:#555">=&lt;/span>bazel-genfiles &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span>--python_out&lt;span style="color:#555">=&lt;/span>bazel-genfiles &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span>--cpp_out&lt;span style="color:#555">=&lt;/span>bazel-genfiles &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span>--grpc_out&lt;span style="color:#555">=&lt;/span>bazel-genfiles &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span>--objc_out&lt;span style="color:#555">=&lt;/span>bazel-genfiles &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span>--csharp_out&lt;span style="color:#555">=&lt;/span>bazel-genfiles/examples/proto &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span>--java_out&lt;span style="color:#555">=&lt;/span>bazel-genfiles/examples/proto/pluriproto_java.jar &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span>--javanano_out&lt;span style="color:#555">=&lt;/span>&lt;span style="color:#033">ignore_services&lt;/span>&lt;span style="color:#555">=&lt;/span>true:bazel-genfiles/examples/proto/pluriproto_nano.jar &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span>--js_out&lt;span style="color:#555">=&lt;/span>&lt;span style="color:#033">import_style&lt;/span>&lt;span style="color:#555">=&lt;/span>closure,error_on_name_conflict,binary,library&lt;span style="color:#555">=&lt;/span>examples/proto/pluriproto:bazel-genfiles &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span>--js_out&lt;span style="color:#555">=&lt;/span>&lt;span style="color:#033">import_style&lt;/span>&lt;span style="color:#555">=&lt;/span>commonjs,error_on_name_conflict,binary:bazel-genfiles &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span>--go_out&lt;span style="color:#555">=&lt;/span>&lt;span style="color:#033">plugins&lt;/span>&lt;span style="color:#555">=&lt;/span>grpc,Mexamples/proto/common.proto&lt;span style="color:#555">=&lt;/span>github.com/pubref/rules_protobuf/examples/proto/pluriproto:bazel-genfiles &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span>--grpc-java_out&lt;span style="color:#555">=&lt;/span>bazel-genfiles/examples/proto/pluriproto_java.jar &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span>--grpc-nano_out&lt;span style="color:#555">=&lt;/span>&lt;span style="color:#033">ignore_services&lt;/span>&lt;span style="color:#555">=&lt;/span>true:bazel-genfiles/examples/proto/pluriproto_nano.jar &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span>--grpc-csharp_out&lt;span style="color:#555">=&lt;/span>bazel-genfiles/examples/proto &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span>--proto_path&lt;span style="color:#555">=&lt;/span>. &lt;span style="color:#c30;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30;font-weight:bold">&lt;/span>examples/proto/common.proto
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"># ************************************************************&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>examples/proto/common_pb.rb
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>examples/proto/pluriproto_java.jar
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>examples/proto/pluriproto_nano.jar
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>examples/proto/common_pb2.py
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>examples/proto/common.pb.h
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>examples/proto/common.pb.cc
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>examples/proto/common.grpc.pb.h
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>examples/proto/common.grpc.pb.cc
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>examples/proto/Common.pbobjc.h
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>examples/proto/Common.pbobjc.m
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>examples/proto/pluriproto.js
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>examples/proto/Common.cs
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>examples/proto/CommonGrpc.cs
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>examples/proto/common.pb.go
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>examples/proto/common_pb.js
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>examples/proto/pluriproto.descriptor_set
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The various &lt;code>*_proto_library&lt;/code> rules (that we&amp;rsquo;ll be using below)
internally invoke this &lt;code>proto_compile&lt;/code> rule, then consume the
generated outputs and compile them with the requisite libraries into
&lt;code>.class&lt;/code>, &lt;code>.so&lt;/code>, &lt;code>.a&lt;/code> (or whatever) objects.&lt;/p>
&lt;p>So let&amp;rsquo;s &lt;em>make something&lt;/em> already! We&amp;rsquo;ll use bazel and rules_protobuf
to build a gRPC application.&lt;/p>
&lt;h1 id="building">2: Building a gRPC service with rules_protobuf&lt;/h1>
&lt;p>The application will involve communication between two
different gRPC services:&lt;/p>
&lt;h2 id="21-services">2.1: Services&lt;/h2>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>The Greeter service&lt;/strong>: This is the familiar &amp;ldquo;Hello World&amp;rdquo; starter
example that accepts a request with a &lt;code>user&lt;/code> argument and replies
back with the string &lt;code>Hello {user}&lt;/code>.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>The GreeterTimer service&lt;/strong>: This gRPC service will repeatedly
call a Greeter service in batches and report back aggregate batch
times (in milliseconds). In this way we can compare some average
rpc times for the different Greeter service implementations.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;blockquote>
&lt;p>This is an informal benchmark intended only for demonstration of
building gRPC applications. For more formal performance testing,
consult the
&lt;a href="https://performance-dot-grpc-testing.appspot.com/explore?dashboard=5760820306771968" target="_blank" rel="noopener">gRPC performance dashboard&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;h2 id="22-compiled-programs">2.2: Compiled Programs&lt;/h2>
&lt;p>For the demo, we&amp;rsquo;ll use 6 different compiled programs written in 4
languages:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>A &lt;code>GreeterTimer&lt;/code> client (go). This command-line interface requires
the &lt;code>greetertimer.proto&lt;/code> service definition defined locally in the
&lt;code>//proto:greetertimer.proto&lt;/code> file.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>A &lt;code>GreeterTimer&lt;/code> server (java). This netty-based server requires
both the &lt;code>//proto/greetertimer.proto&lt;/code> file and the proto definition
defined externally in
&lt;code>@org_pubref_rules_protobuf//examples/helloworld/proto:helloworld.proto&lt;/code>.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Four &lt;code>Greeter&lt;/code> server implementations (C++, java, go, and C#).
rules_protobuf already provides these example implementations, so
we&amp;rsquo;ll just use them directly.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 id="23-protobuf-definitions">2.3: Protobuf Definitions&lt;/h2>
&lt;p>GreeterTimer accepts a unary &lt;code>TimerRequest&lt;/code> and streams back a
sequence of &lt;code>BatchResponse&lt;/code> until all messages have been processed, at
which point the remote procedure call is complete.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>service GreeterTimer {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// Unary request followed by multiple streamed responses.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#09f;font-style:italic">// Response granularity will be set by the request batch size.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> rpc timeHello(TimerRequest) returns (stream BatchResponse);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>TimerRequest&lt;/code> includes metadata about where to contact the Greeter
service, how many total RPC calls to make, and how frequent to stream
back a BatchResponse (configured via the batch size).&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>message TimerRequest {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// the host where the grpc server is running
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> string host &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">1&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// The port of the grpc server
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> int32 port &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">2&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// The total number of hellos
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> int32 total &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">3&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// The number of hellos before sending a BatchResponse.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> int32 batchSize &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">4&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>BatchResponse&lt;/code> reports the number of calls made in the batch, how
long the batch run took, and the number of remaining calls.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>message BatchResponse {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// The number of checks that are remaining, calculated relative to
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#09f;font-style:italic">// totalChecks in the request.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> int32 remaining &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">1&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// The number of checks actually performed in this batch.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> int32 batchCount &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">2&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// The number of checks that failed.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> int32 errCount &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">3&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// The total time spent, expressed as a number of milliseconds per
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#09f;font-style:italic">// request batch size (total time spent performing batchSize number
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#09f;font-style:italic">// of health checks).
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> int64 batchTimeMillis &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">4&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The non-streaming &lt;code>Greeter&lt;/code> service takes a unary &lt;code>HelloRequest&lt;/code> and
responds with a single &lt;code>HelloReply&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>service Greeter {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> rpc SayHello (HelloRequest) returns (HelloReply) {}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>message HelloRequest {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> string name &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">1&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> common.Config config &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">2&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>message HelloReply {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> string message &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">1&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>The &lt;code>common.Config&lt;/code> message type is not particularly functional here
but serves to demonstrate the use of imports. rules_protobuf can
help with more complex setups having multiple proto → proto
dependencies.&lt;/p>
&lt;/blockquote>
&lt;h2 id="24-build-the-grpc_greetertimer-example-application">2.4: Build the grpc_greetertimer example application.&lt;/h2>
&lt;p>This demo application can be cloned at
&lt;a href="https://github.com/pubref/grpc_greetertimer" target="_blank" rel="noopener">https://github.com/pubref/grpc_greetertimer&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;h3 id="241-create-the-project-layout">2.4.1: Create the Project Layout&lt;/h3>
&lt;p>Here&amp;rsquo;s the directory layout and relevant BUILD files we&amp;rsquo;ll be using:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>mkdir grpc_greetertimer &lt;span style="color:#555">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#366">cd&lt;/span> grpc_greetertimer
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/grpc_greetertimer$ mkdir -p proto/ go/ java/org/pubref/grpc/greetertimer/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/grpc_greetertimer$ touch WORKSPACE
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/grpc_greetertimer$ touch proto/BUILD
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/grpc_greetertimer$ touch proto/greetertimer.proto
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/grpc_greetertimer$ touch go/BUILD
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/grpc_greetertimer$ touch go/main.go
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/grpc_greetertimer$ touch java/org/pubref/grpc/greetertimer/BUILD
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/grpc_greetertimer$ touch java/org/pubref/grpc/greetertimer/GreeterTimerServer.java
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="242-the-workspace">2.4.2: The WORKSPACE&lt;/h3>
&lt;p>We&amp;rsquo;ll begin by creating the &lt;a href="https://github.com/pubref/grpc_greetertimer" target="_blank" rel="noopener">WORKSPACE&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> file with a
reference to the rules_protobuf repository. We load the main
entrypoint skylark file
&lt;a href="https://github.com/pubref/rules_protobuf/blob/master/protobuf/rules.bzl" target="_blank" rel="noopener">rules.bzl&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
in the &lt;code>//bzl&lt;/code> package and call its &lt;code>protobuf_repositories&lt;/code> function
with the languages to we want to use (in this case &lt;code>java&lt;/code> and &lt;code>go&lt;/code>).
We also load &lt;a href="https://github.com/bazelbuild/rules_go" target="_blank" rel="noopener">rules_go&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> for go
compile support (not shown).&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"># File //:WORKSPACE&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>workspace(name &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#c30">&amp;#34;org_pubref_grpc_greetertimer&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>git_repository(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> name &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#c30">&amp;#34;org_pubref_rules_protobuf&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> remote &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#c30">&amp;#34;https://github.com/pubref/rules_protobuf.git&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> tag &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#c30">&amp;#34;v0.6.0&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"># Load language-specific dependencies&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>load(&lt;span style="color:#c30">&amp;#34;@org_pubref_rules_protobuf//java:rules.bzl&amp;#34;&lt;/span>, &lt;span style="color:#c30">&amp;#34;java_proto_repositories&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>java_proto_repositories()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>load(&lt;span style="color:#c30">&amp;#34;@org_pubref_rules_protobuf//go:rules.bzl&amp;#34;&lt;/span>, &lt;span style="color:#c30">&amp;#34;go_proto_repositories&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>go_proto_repositories()
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>Refer to the
&lt;a href="https://github.com/pubref/rules_protobuf/protobuf/internal/repositories.bzl" target="_blank" rel="noopener">repositories.bzl file&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>,
if you are interested in inspecting the dependencies.&lt;/p>
&lt;/blockquote>
&lt;p>Bazel won&amp;rsquo;t actually &lt;em>fetch&lt;/em> something unless we actually need it by
some other rule later, so let&amp;rsquo;s go ahead and write some code. We&amp;rsquo;ll
store our protocol buffer sources in &lt;code>//proto&lt;/code>, our java sources in
&lt;code>//java&lt;/code>, and go source in &lt;code>//go&lt;/code>.&lt;/p>
&lt;blockquote>
&lt;p>Note: go development within a bazel workspace is a little different
than vanilla go. In particular, one does not have to adhere to a
typical &lt;code>GOCODE&lt;/code> layout having a &lt;code>src/&lt;/code>, &lt;code>pkg/&lt;/code>, &lt;code>bin/&lt;/code>
subdirectories.&lt;/p>
&lt;/blockquote>
&lt;h3 id="243-the-greetertimer-server">2.4.3: The GreeterTimer Server&lt;/h3>
&lt;p>The &lt;a href="https://github.com/pubref/grpc_greetertimer/blob/master/java/org/pubref/grpc/greetertimer/GreeterTimerServer.java" target="_blank" rel="noopener">Java server&amp;rsquo;s&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
main job is to accept requests and then connect to the requested
Greeter service as a client. The implementation counts down the
number of remaining messages and does a blocking &lt;code>sayHello(request)&lt;/code>
for each one. If the batchSize limit is met, the
&lt;code>observer.onNext(response)&lt;/code> message is invoked, streaming back a
response to the client.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">/* File //java/org/pubref/grpc/greetertimer:GreeterTimerServer.java */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">while&lt;/span> &lt;span style="color:#555">(&lt;/span>remaining&lt;span style="color:#555">--&lt;/span> &lt;span style="color:#555">&amp;gt;&lt;/span> 0&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">if&lt;/span> &lt;span style="color:#555">(&lt;/span>batchCount&lt;span style="color:#555">++&lt;/span> &lt;span style="color:#555">==&lt;/span> batchSize&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> BatchResponse response &lt;span style="color:#555">=&lt;/span> BatchResponse&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">newBuilder&lt;/span>&lt;span style="color:#555">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">setRemaining&lt;/span>&lt;span style="color:#555">(&lt;/span>remaining&lt;span style="color:#555">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">setBatchCount&lt;/span>&lt;span style="color:#555">(&lt;/span>batchCount&lt;span style="color:#555">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">setBatchTimeMillis&lt;/span>&lt;span style="color:#555">(&lt;/span>batchTime&lt;span style="color:#555">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">setErrCount&lt;/span>&lt;span style="color:#555">(&lt;/span>errCount&lt;span style="color:#555">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">build&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> observer&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">onNext&lt;/span>&lt;span style="color:#555">(&lt;/span>response&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> blockingStub&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">sayHello&lt;/span>&lt;span style="color:#555">(&lt;/span>HelloRequest&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">newBuilder&lt;/span>&lt;span style="color:#555">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">setName&lt;/span>&lt;span style="color:#555">(&lt;/span>&lt;span style="color:#c30">&amp;#34;#&amp;#34;&lt;/span> &lt;span style="color:#555">+&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">build&lt;/span>&lt;span style="color:#555">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="244-the-greetertimer-client">2.4.4: The GreeterTimer Client&lt;/h3>
&lt;p>The &lt;a href="https://github.com/pubref/grpc_greetertimer/blob/master/go/main.go" target="_blank" rel="noopener">Go client&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
prepares a &lt;code>TimerRequest&lt;/code> and gets back a stream interface from the
&lt;code>client.TimeHello&lt;/code> method. We call its &lt;code>Recv()&lt;/code> method until EOF, at
which point the call is complete. A summary of each BatchResponse is
simply printed out to the terminal.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// File: //go:main.go
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">func&lt;/span> &lt;span style="color:#c0f">submit&lt;/span>(client greeterTimer.GreeterTimerClient, request &lt;span style="color:#555">*&lt;/span>greeterTimer.TimerRequest) &lt;span style="color:#078;font-weight:bold">error&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> stream, err &lt;span style="color:#555">:=&lt;/span> client.&lt;span style="color:#c0f">TimeHello&lt;/span>(context.&lt;span style="color:#c0f">Background&lt;/span>(), request)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">if&lt;/span> err &lt;span style="color:#555">!=&lt;/span> &lt;span style="color:#069;font-weight:bold">nil&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> log.&lt;span style="color:#c0f">Fatalf&lt;/span>(&lt;span style="color:#c30">&amp;#34;could not submit request: %v&amp;#34;&lt;/span>, err)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">for&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> batchResponse, err &lt;span style="color:#555">:=&lt;/span> stream.&lt;span style="color:#c0f">Recv&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">if&lt;/span> err &lt;span style="color:#555">==&lt;/span> io.EOF {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">return&lt;/span> &lt;span style="color:#069;font-weight:bold">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">if&lt;/span> err &lt;span style="color:#555">!=&lt;/span> &lt;span style="color:#069;font-weight:bold">nil&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> log.&lt;span style="color:#c0f">Fatalf&lt;/span>(&lt;span style="color:#c30">&amp;#34;error during batch recv: %v&amp;#34;&lt;/span>, err)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">return&lt;/span> err
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c0f">reportBatchResult&lt;/span>(batchResponse)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="245-generate-the-go-protobufgrpc-code">2.4.5: Generate the go protobuf+gRPC code&lt;/h3>
&lt;p>In our &lt;code>//proto:BUILD&lt;/code> file, we have a &lt;code>go_proto_library&lt;/code> rule loaded
from the rules_protobuf repository. Internally, the rule declares to
bazel that it is responsible for creating &lt;code>greetertimer.pb.go&lt;/code> output
file. This rule won&amp;rsquo;t actually &lt;em>do&lt;/em> anything unless we depend on it
somewhere else.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"># File: //proto:BUILD&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>load(&lt;span style="color:#c30">&amp;#34;@org_pubref_rules_protobuf//go:rules.bzl&amp;#34;&lt;/span>, &lt;span style="color:#c30">&amp;#34;go_proto_library&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>go_proto_library(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> name &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#c30">&amp;#34;go_default_library&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> protos &lt;span style="color:#555">=&lt;/span> [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c30">&amp;#34;greetertimer.proto&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ],
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> with_grpc &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">True&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The go client implementation depends on the &lt;code>go_proto_library&lt;/code> as
source file provider to the &lt;code>go_binary&lt;/code> rule. We also pass in some
compile-time dependencies named in the
&lt;code>GRPC_COMPILE_DEPS&lt;/code> list.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>load(&lt;span style="color:#c30">&amp;#34;@io_bazel_rules_go//go:def.bzl&amp;#34;&lt;/span>, &lt;span style="color:#c30">&amp;#34;go_binary&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>load(&lt;span style="color:#c30">&amp;#34;@org_pubref_rules_protobuf//go:rules.bzl&amp;#34;&lt;/span>, &lt;span style="color:#c30">&amp;#34;GRPC_COMPILE_DEPS&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>go_binary(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> name &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#c30">&amp;#34;hello_client&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> srcs &lt;span style="color:#555">=&lt;/span> [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c30">&amp;#34;main.go&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ],
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> deps &lt;span style="color:#555">=&lt;/span> [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c30">&amp;#34;//proto:go_default_library&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ] &lt;span style="color:#555">+&lt;/span> GRPC_COMPILE_DEPS,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>~/grpc_greetertimer$ bazel build //go:client
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Here&amp;rsquo;s what happens when we invoke bazel to actually build the client
binary:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Bazel checks to see if the inputs (files) that the binary depends
on have changed (by content hash and filestamps). Bazel recognizes
that the output files for the &lt;code>//proto:go_default_library&lt;/code> have not
been built.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Bazel checks to see if all the necessary inputs (including tools)
for the &lt;code>go_proto_library&lt;/code> are available. If not, download and
build all the necessary tools. Then, invoke the rule.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Fetch the &lt;code>google/protobuf&lt;/code> repository and build &lt;code>protoc&lt;/code> from
source (via a cc_binary rule).&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Build the &lt;code>protoc-gen-go&lt;/code> plugin from source (via a go_binary
rule).&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Invoke &lt;code>protoc&lt;/code> with the &lt;code>protoc-gen-go&lt;/code> plugin with the
appropriate options and arguments.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Confirm that all the declared outputs of the &lt;code>go_proto_library&lt;/code>
where actually built (should be in &lt;code>bazel-bin/proto/greetertimer.pb.go&lt;/code>).&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;p>Compile the generated &lt;code>greetertimer.pb.go&lt;/code> with the client
&lt;code>main.go&lt;/code> file, creating the &lt;code>bazel-bin/go/client&lt;/code> executable.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h3 id="246-generate-the-java-protobuf-libraries">2.4.6: Generate the java protobuf libraries&lt;/h3>
&lt;p>The &lt;code>java_proto_library&lt;/code> rule is functionally identical to the
&lt;code>go_proto_library&lt;/code> rule. However, instead of providing a &lt;code>*.pb.go&lt;/code>
file, it bundles up all the generated outputs into a &lt;code>*.srcjar&lt;/code> file
(which is then used as an input to the &lt;code>java_library&lt;/code> rule). This an
implementation detail of the java rule. Here is how we build the
final java binary:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>java_binary(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> name &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#c30">&amp;#34;server&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> main_class &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#c30">&amp;#34;org.pubref.grpc.greetertimer.GreeterTimerServer&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> srcs &lt;span style="color:#555">=&lt;/span> [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c30">&amp;#34;GreeterTimerServer.java&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ],
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> deps &lt;span style="color:#555">=&lt;/span> [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c30">&amp;#34;:timer_protos&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c30">&amp;#34;@org_pubref_rules_protobuf//examples/helloworld/proto:java&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c30">&amp;#34;@org_pubref_rules_protobuf//java:grpc_compiletime_deps&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ],
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> runtime_deps &lt;span style="color:#555">=&lt;/span> [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c30">&amp;#34;@org_pubref_rules_protobuf//java:netty_runtime_deps&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ],
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol>
&lt;li>
&lt;p>The &lt;code>:timer_protos&lt;/code> is a locally defined &lt;code>java_proto_library&lt;/code> rule.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The &lt;code>@org_pubref_rules_protobuf//examples/helloworld/proto:java&lt;/code> is
an external &lt;code>java_proto_library&lt;/code> rule that generates the greeter service
client stub in our own workspace.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Finally, we name the compile-time and run-time dependencies for the
executable jar. If these jar files have not yet been downloaded from
maven central, they will be fetch as soon as we need them:&lt;/p>
&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>~/grpc_greetertimer$ bazel build java/org/pubref/grpc/greetertimer:server
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/grpc_greetertimer$ bazel build java/org/pubref/grpc/greetertimer:server_deploy.jar
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This last form (having the extra &lt;code>_deploy.jar&lt;/code>) is called an &lt;em>implicit
target&lt;/em> of the &lt;code>:server&lt;/code> rule. When invoked this way, bazel will pack
up all the required classes and generate a standalone executable jar
that can be run independently in a jvm.&lt;/p>
&lt;h3 id="247-run-it">2.4.7: Run it!&lt;/h3>
&lt;p>First, we&amp;rsquo;ll start a greeter server (one at a time):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>~/grpc_greetertimer$ &lt;span style="color:#366">cd&lt;/span> ~/rules_protobuf
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/rules_protobuf$ bazel run examples/helloworld/go/server
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/rules_protobuf$ bazel run examples/helloworld/cpp/server
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/rules_protobuf$ bazel run examples/helloworld/java/org/pubref/rules_protobuf/examples/helloworld/server:netty
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/rules_protobuf$ bazel run examples/helloworld/csharp/GreeterServer
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>INFO: Server started, listening on &lt;span style="color:#f60">50051&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>In a separate terminal, start the greetertimer server:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>~/grpc_greetertimer$ bazel build //java/org/pubref/grpc/greetertimer:server_deploy.jar
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/grpc_greetertimer$ java -jar bazel-bin/java/org/pubref/grpc/greetertimer/server_deploy.jar
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Finally, in a third terminal, invoke the greetertimer client:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"># Timings for the java server&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/rules_protobuf$ bazel run examples/helloworld/java/org/pubref/rules_protobuf/examples/helloworld/server:netty
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/grpc_greeterclient$ bazel run //go:client -- -total_size &lt;span style="color:#f60">10000&lt;/span> -batch_size &lt;span style="color:#f60">1000&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:31:04 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">8999&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 1.7 hellos/ms or ~590µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"># ... plus a few runs to warm up the jvm...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:31:13 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">8999&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 6.7 hellos/ms or ~149µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:31:13 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">7998&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 9.0 hellos/ms or ~111µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:31:13 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">6997&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 8.9 hellos/ms or ~112µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:31:13 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">5996&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 9.2 hellos/ms or ~109µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:31:13 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">4995&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 9.4 hellos/ms or ~106µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:31:13 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">3994&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 9.0 hellos/ms or ~111µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:31:13 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">2993&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 9.4 hellos/ms or ~107µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:31:13 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">1992&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 9.4 hellos/ms or ~107µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:31:13 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">991&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 9.1 hellos/ms or ~110µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:31:14 &lt;span style="color:#f60">991&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, -1 remaining&lt;span style="color:#555">)&lt;/span>: 9.0 hellos/ms or ~111µs per hello&lt;span style="color:#c30">```&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c30">```&lt;/span>sh
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"># Timings for the go server&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/rules_protobuf$ bazel run examples/helloworld/go/server
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/grpc_greeterclient$ bazel run //go:client -- -total_size &lt;span style="color:#f60">10000&lt;/span> -batch_size &lt;span style="color:#f60">1000&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:32:33 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">8999&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 7.5 hellos/ms or ~134µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:32:33 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">7998&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 7.9 hellos/ms or ~127µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:32:34 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">6997&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 7.8 hellos/ms or ~128µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:32:34 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">5996&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 7.7 hellos/ms or ~130µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:32:34 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">4995&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 7.9 hellos/ms or ~126µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:32:34 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">3994&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 8.0 hellos/ms or ~125µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:32:34 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">2993&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 7.6 hellos/ms or ~132µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:32:34 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">1992&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 7.9 hellos/ms or ~126µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:32:34 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">991&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 7.9 hellos/ms or ~127µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:32:34 &lt;span style="color:#f60">991&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, -1 remaining&lt;span style="color:#555">)&lt;/span>: 7.8 hellos/ms or ~128µs per hello
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"># Timings for the C++ server&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/rules_protobuf$ bazel run examples/helloworld/cpp:server
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/grpc_greeterclient$ bazel run //go:client -- -total_size &lt;span style="color:#f60">10000&lt;/span> -batch_size &lt;span style="color:#f60">1000&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:33:10 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">8999&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 9.1 hellos/ms or ~110µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:33:10 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">7998&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 9.0 hellos/ms or ~111µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:33:10 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">6997&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 9.1 hellos/ms or ~110µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:33:10 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">5996&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 8.6 hellos/ms or ~116µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:33:10 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">4995&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 9.0 hellos/ms or ~111µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:33:10 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">3994&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 9.0 hellos/ms or ~111µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:33:10 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">2993&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 9.1 hellos/ms or ~110µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:33:10 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">1992&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 9.0 hellos/ms or ~111µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:33:10 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">991&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 9.0 hellos/ms or ~111µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:33:11 &lt;span style="color:#f60">991&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, -1 remaining&lt;span style="color:#555">)&lt;/span>: 9.0 hellos/ms or ~111µs per hello
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"># Timings for the C# server&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/rules_protobuf$ bazel run examples/helloworld/csharp/GreeterServer
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/grpc_greeterclient$ bazel run //go:client -- -total_size &lt;span style="color:#f60">10000&lt;/span> -batch_size &lt;span style="color:#f60">1000&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:34:37 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">8999&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 6.0 hellos/ms or ~166µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:34:37 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">7998&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 6.7 hellos/ms or ~150µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:34:37 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">6997&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 6.8 hellos/ms or ~148µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:34:37 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">5996&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 6.8 hellos/ms or ~147µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:34:37 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">4995&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 6.7 hellos/ms or ~150µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:34:38 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">3994&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 6.7 hellos/ms or ~150µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:34:38 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">2993&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 6.7 hellos/ms or ~149µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:34:38 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">1992&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 6.7 hellos/ms or ~149µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:34:38 &lt;span style="color:#f60">1001&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, &lt;span style="color:#f60">991&lt;/span> remaining&lt;span style="color:#555">)&lt;/span>: 6.8 hellos/ms or ~148µs per hello
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>17:34:38 &lt;span style="color:#f60">991&lt;/span> hellos &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#f60">0&lt;/span> errs, -1 remaining&lt;span style="color:#555">)&lt;/span>: 6.8 hellos/ms or ~147µs per hello
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The informal analysis demonstrated comparable timings for c++, go, and
java greeter service implementations. The c++ server had the overall
fastest and most consistent performance. The go implementation was
also very consistent, but slightly slower than C++. Java demonstrated
some initial relative slowness likely due to the JVM warming up but
soon converged on timings similar to the C++ implementation. C# has
consistent performance but marginally slower.&lt;/p>
&lt;h2 id="25-summary">2.5: Summary&lt;/h2>
&lt;p>Bazel assists in the construction of gRPC applications by providing a
capable build environment for services built in a multitude of
languages. &lt;a href="https://github.com/pubref/rules_protobuf/" target="_blank" rel="noopener">rules_protobuf&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> complements bazel by packaging up all the
dependencies needed and abstracting away the need to call protoc
directly.&lt;/p>
&lt;p>In this workflow one does not need to check in the generated source code
(it is always generated on-demand within your workspace). For
projects that &lt;em>do&lt;/em> require this, one can use the &lt;code>output_to_workspace&lt;/code> option to place the generated
files alongside the protobuf definitions.&lt;/p>
&lt;p>Finally, rules_protobuf has full support for the
&lt;a href="https://github.com/grpc-ecosystem/grpc-gateway" target="_blank" rel="noopener">grpc-gateway&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> project
via the
&lt;a href="https://github.com/pubref/rules_protobuf/tree/master/grpc_gateway#grpc_gateway_proto_library" target="_blank" rel="noopener">grpc_gateway_proto_library&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
and
&lt;a href="https://github.com/pubref/rules_protobuf/tree/master/grpc_gateway#grpc_gateway_binary" target="_blank" rel="noopener">grpc_gateway_binary&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> rules, so you can easily bridge your gRPC apps with HTTP/1.1 gateways.&lt;/p>
&lt;p>Refer to the &lt;a href="https://github.com/pubref/rules_protobuf/#rules" target="_blank" rel="noopener">complete list of supported languages and gRPC versions&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> for more information.&lt;/p>
&lt;p>And&amp;hellip; that&amp;rsquo;s a wrap. Happy procedure calling!&lt;/p>
&lt;blockquote>
&lt;p>Paul Johnston is the principal at &lt;a href="https://pubref.org" target="_blank" rel="noopener">PubRef&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>
(&lt;a href="https://twitter.com/pub_ref" target="_blank" rel="noopener">@pub_ref&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>), a solutions provider for
scientific communications workflows. If you have an organizational
need for assistance with Bazel, gRPC, or related technologies,
please contact &lt;a href="mailto:pcj@pubref.org">pcj@pubref.org&lt;/a>. Thanks!&lt;/p>
&lt;/blockquote></description></item><item><title>Blog: gRPC at VSCO</title><link>https://grpc.io/blog/vsco/</link><pubDate>Tue, 06 Sep 2016 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/vsco/</guid><description>
&lt;p>Our guest post today comes from Robert Sayre and Melinda Lu of VSCO.&lt;/p>
&lt;p>Founded in 2011, &lt;a href="https://vsco.co" target="_blank" rel="noopener">VSCO&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> is a community for expression—empowering people to create, discover and connect through images and words. VSCO is in the process of migrating their stack to gRPC.&lt;/p>
&lt;p>In 2015, user growth forced VSCO down a familiar path. A monolithic PHP application in existence since the early days of the company was exhibiting performance problems and becoming difficult to maintain. We experimented with some smaller services in node.js, Go, and Java. At the same time, a larger messaging service for email, push messages, and in-app notifications was built in Go. Taking a first step away from JSON, we chose &lt;a href="https://developers.google.com/protocol-buffers/" target="_blank" rel="noopener">Protocol Buffers&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> as the serialization format for this system.&lt;/p>
&lt;p>Today, VSCO has largely settled on Go for new services. There are exceptions, particularly where a mature JVM solution is available for a given problem. Additionally, VSCO uses node.js for web applications, often with server-side &lt;a href="https://facebook.github.io/react/" target="_blank" rel="noopener">React&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. Given that mix of languages, services, and some future data pipeline work detailed below, VSCO settled on gRPC and Protocol Buffers as the most practical solution for interprocess communication. A gradual migration from JSON over HTTP/1.1 APIs to gRPC over HTTP/2 is underway and going well. That said, there have been issues with the maturity of the PHP implementation relative to other languages.&lt;/p>
&lt;p>Protocol buffers have been particularly valuable in building out our data ecosystem, where we rely on them to standardize and allow safe evolution of our data schemas in a language-agnostic way. As one example, we’ve built a Go service that feeds off our MySQL and MongoDB database replication logs and transforms backend database changes into a stream of immutable events in Kafka, with each row- or document-change event encoded as a protocol buffer. This database event stream allows us to add real-time data consumers as desired, without impacting production traffic and without having to coordinate with other systems. By processing all database events into protocol buffers en-route to Kafka, we can ensure that data is encoded in a uniform way that makes it easy to consume and use from multiple languages. Our implementation of &lt;a href="https://github.com/vsco/autobahn-binlog" target="_blank" rel="noopener">MySQL-binary-log&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> and &lt;a href="https://github.com/vsco/autobahn-oplog" target="_blank" rel="noopener">Mongo-oplog&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> tailers are available on GitHub.&lt;/p>
&lt;p>Elsewhere in our data pipeline, we’ve begun using gRPC and protocol buffers to deliver behavioral events from our iOS and Android clients to a Go ingestion service, which then publishes these events to Kafka. To support this high-volume use case, we needed (1) a performant, fault-tolerant, language-agnostic RPC framework, (2) a way to ensure data compatibility as our product evolves, and (3) horizontally-scalable infrastructure. We’ve found gRPC, protocol buffers, and Go services running in Kubernetes a good fit for all three. As this was our first client-facing Go gRPC service, we did experience some new points of friction — in particular, load-balancer support and amenities like curl-like debugging have been lagging due to the youth of the HTTP/2 ecosystem. However, the ease of defining services with the gRPC IDL, using built-in architecture like interceptors, and scaling with Go have made the tradeoffs worthwhile.&lt;/p>
&lt;p>As a first step in bringing gRPC to our mobile clients, we’ve shipped telemetry code in our iOS and Android apps. As of gRPC 1.0, this process is relatively straightforward. They only post events to our servers so far, and don’t do much with gRPC responses. The previous implementation was based on JSON, and our move to a single protocol buffer definition of our events uncovered a bunch of subtle bugs and differences between the clients.&lt;/p>
&lt;p>One slight roadblock we ran into was the need for our clients to maintain compatibility with our JSON implementation as we ramp up, and for integration with vendor SDKs. This required a little bit of key-value coding on iOS, but it got more difficult on Android. We ended up having to write a protobuf compiler plugin to get the reflection features we needed while maintaining adequate performance. Drawing from that experience, we’ve made a concise &lt;a href="https://github.com/vsco/protoc-demo" target="_blank" rel="noopener">example protoc plugin&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> built with &lt;a href="https://bazel.io/" target="_blank" rel="noopener">Bazel&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> available on GitHub.&lt;/p>
&lt;p>As more and more of our data becomes available in protocol buffer form, we plan to build upon this unified schema to expand our machine-learning and analytics systems. For example, we write our Kafka database replication streams to Amazon S3 as &lt;a href="https://parquet.apache.org/" target="_blank" rel="noopener">Apache Parquet&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, an efficient columnar disk-storage format. Parquet has low-level support for protocol buffers, so we can use our existing data definitions to write optimized tables and do partial deserializations where desired.&lt;/p>
&lt;p>From S3, we run computations on our data using Apache Spark, which can use our protocol buffer definitions to define types. We’re also building new machine-learning applications with &lt;a href="https://www.tensorflow.org/" target="_blank" rel="noopener">TensorFlow&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. It uses protocol buffers natively and allows us to serve our models as gRPC services with &lt;a href="https://tensorflow.github.io/serving/" target="_blank" rel="noopener">TensorFlow Serving&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;p>So far, we’ve had good luck with gRPC and Protocol Buffers. They don’t eliminate every integration headache. However it’s easy to see how they help our engineers avoid writing a lot of boilerplate RPC code, while side-stepping the endless data-quality papercuts that come with looser serialization formats.&lt;/p></description></item><item><title>Blog: Why we have decided to move our APIs to gRPC</title><link>https://grpc.io/blog/vendasta/</link><pubDate>Mon, 29 Aug 2016 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/vendasta/</guid><description>
&lt;p>Vendasta started out 8 years ago as a point solution provider of products for small business. From the beginning we partnered with media companies and agencies who have armies of salespeople and existing relationships with those businesses to sell our software. It is estimated that over 30 million small businesses exist in the United States alone, so scalability of our SaaS solution was considered one of our top concerns from the beginning and it was the reason we started with &lt;a href="https://cloud.google.com/appengine/" target="_blank" rel="noopener">Google App Engine&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> and Datastore. This solution worked really well for us as our system scaled from hundreds to hundreds of thousands of end users. We also scaled our offering from a point solution to an entire platform with multiple products and the tools for partners to manage their sales of those products during this time.&lt;/p>
&lt;p>All throughout this journey Python GAE served our needs well. We exposed a number of APIs via HTTP + JSON for our partners to automate tasks and integrate their other systems with our products and platform. However, in 2016 we introduced the Vendasta Marketplace. This marked a major change to our offering, which depended heavily on having 3rd party vendors use our APIs to deliver their own products in our platform. This was a major change because our public APIs provide an upper-bound on 3rd-party applications, and made us realize that we really needed to make APIs that were amazing, not just good.&lt;/p>
&lt;p>The first optimization that we started with was to use the Go programming language to build endpoints that handled higher throughput with lower latency than we could get with Python. On some APIs this made an incredible difference: we saw 50th percentile response times to drop from 1200 ms to 4 ms, and even more spectacularly 99th percentile response times drop from 30,000 ms to 12 ms! On other APIs we saw a much smaller, but still significant difference.&lt;/p>
&lt;p>The second optimization we used was to replicate large portions of our Datastore data into ElasticSearch. ElasticSearch is a fundamentally different storage technology to Datastore, and is not a managed service, so it was a big leap for us. But this change allowed us to migrate almost all of our overnight batch-processing APIs to real-time APIs. We had tried BigQuery, but it&amp;rsquo;s query processing times meant that we couldn&amp;rsquo;t display things in real time. We had tried cloudSQL, but there was too much data for it to easily scale. We had tried the appengine Search API, but it has limitations with result sets over 10,000. We instead scaled up our ElasticSearch cluster using &lt;a href="https://cloud.google.com/container-engine/" target="_blank" rel="noopener">Google Container Engine&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> and with it&amp;rsquo;s powerful aggregations and facet processing our needs were easily met. So with these first two solutions in place, we had made meaningful changes to the performance of our APIs.&lt;/p>
&lt;p>The last optimization we made was to move our APIs to &lt;a href="https://grpc.io/">gRPC&lt;/a>. This change was much more extensive than the others as it affected our clients. Like ElasticSearch, it represents a fundamentally different model with differing performance characteristics, but unlike ElasticSearch we found it to be a true superset: all of our usage scenarios were impacted positively by it.&lt;/p>
&lt;p>The first benefit we saw from gRPC was the ability to move from publishing APIs and asking developers to integrate with them, to releasing SDKs and asking developers to copy-paste example code written in their language. This represents a really big benefit for people looking to integrate with our products, while not requiring us to hand-roll entire SDKs in the 5+ languages our partners and vendors use. It is important to note that we still write light wrappers over the generated gRPC SDKs to make them package-manager friendly, and to provide wrappers over the generated protobuf structures.&lt;/p>
&lt;p>The second benefit we saw from gRPC was the ability to break free from the call-and-response architecture necessitated by HTTP + JSON. gRPC is built on top of HTTP/2, which allows for client-side and/or server-side streaming. In our use cases, this means we can lower the time to first display by streaming results as they become ready on the server (server-side streaming). We have also been investigating the potential to offer very flexible create endpoints that easily support bulk ingestion with bi-directional streaming, this would mean we would allow the client to asynchronously stream results, while the server would stream back statuses allowing for easy checkpoint operations while not slowing upload speeds to wait for confirmations. We feel that we are just starting to see the benefits from this feature as it opens up a totally new model for client-server interactions that just wasn&amp;rsquo;t possible with HTTP.&lt;/p>
&lt;p>The third benefit was the switch from JSON to protocol buffers, which works very well with gRPC. This improves serialization and deserialization times; which is very significant to some of our APIs, but appreciated on all of them. The more important benefit comes from the explicit format specification of proto, meaning that clients receive typed objects rather than free-form JSON. Because of this, our clients can reap the benefits of auto-completion in their IDEs, type-safety if their language supports it, and enforced compatibility between clients and servers with differing versions.&lt;/p>
&lt;p>The final benefit of gRPC was our ability to quickly spec endpoints. The proto format for both data and service definition greatly simplifies defining new endpoints and finally allows the succinct definition of endpoint contracts. This means we are much better able to communicate endpoint specifications between our development teams. gRPC means that for the first time at our company we are able to simultaneously develop the client and the server side of our APIs! This means our latency to produce new APIs with the accompanying SDKs has dropped dramatically. Combined with code generation, it allows us to truly develop clients and servers in parallel.&lt;/p>
&lt;p>Our experience with gRPC has been positive, even though it does not eliminate the difficulty of providing endpoints to partners and vendors, and address all of our performance issues. However, it does make improvements to our endpoint performance, integration with those endpoints, and even in delivery of SDKs.&lt;/p></description></item><item><title>Blog: gRPC Project is now 1.0 and ready for production deployments</title><link>https://grpc.io/blog/ga-announcement/</link><pubDate>Tue, 23 Aug 2016 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/ga-announcement/</guid><description>
&lt;p>Today, the gRPC project has reached a significant milestone with its &lt;a href="https://github.com/grpc/grpc/releases" target="_blank" rel="noopener">1.0 release&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.
Languages moving to 1.0 include C++, Java, Go, Node, Ruby, Python and C# across Linux, Windows, and Mac. Objective-C and Android Java support on iOS and Android is also moving to 1.0. The 1.0 release means that the core protocol and API surface are now stable with measured performance, stress tested and developers can rely on these APIs and deploy in production, they will follow semantic versioning from here.&lt;/p>
&lt;p>We are very excited about the progress we have made so far and would like to thank all our users and contributors. First announced in March 2015 with &lt;a href="https://corner.squareup.com/2015/02/grpc.html" target="_blank" rel="noopener">Square&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, gRPC is already being used in many open source projects like &lt;a href="https://github.com/coreos/etcd" target="_blank" rel="noopener">etcd&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> from CoreOS, &lt;a href="https://github.com/docker/containerd" target="_blank" rel="noopener">containerd&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> from Docker, &lt;a href="https://github.com/cockroachdb/cockroach" target="_blank" rel="noopener">cockroachdb&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> from Cockroach Labs, and by many other companies like &lt;a href="https://vendasta.com" target="_blank" rel="noopener">Vendasta&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, &lt;a href="https://github.com/Netflix/ribbon" target="_blank" rel="noopener">Netflix&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, &lt;a href="http://yikyakapp.com" target="_blank" rel="noopener">YikYak&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> and &lt;a href="http://carbon3d.com" target="_blank" rel="noopener">Carbon 3d&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. Outside of microservices, telecom giants like &lt;a href="https://github.com/CiscoDevNet/grpc-getting-started" target="_blank" rel="noopener">Cisco&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, &lt;a href="https://github.com/Juniper/open-nti" target="_blank" rel="noopener">Juniper&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, &lt;a href="https://github.com/aristanetworks/goarista" target="_blank" rel="noopener">Arista&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, and Ciena, are building support for streaming telemetry and network configuration from their network devices using gRPC, as part of &lt;a href="http://www.openconfig.net/" target="_blank" rel="noopener">OpenConfig&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> effort.&lt;/p>
&lt;p>From the beta release, we have made significant strides in the areas of usability, interoperability, and performance measurement on the &lt;a href="https://www.youtube.com/watch?v=_vfbVJ_u5mE" target="_blank" rel="noopener">road to 1.0&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. In most of the languages, the &lt;a href="https://grpc.io/blog/installation/">installation of the gRPC runtime&lt;/a> as well as setup of a development environment is a single command. Beyond installation, we have set up automated tests for gRPC across languages and RPC types in order to stress test our APIs and ensure interoperability. There is now a &lt;a href="https://goo.gl/tHPEfD" target="_blank" rel="noopener">performance dashboard&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> available in the open to see latency and throughput for unary and streaming ping pong for various languages. Other measurements have shown significant gains from using gRPC/Protobuf instead of HTTP/JSON such as in &lt;a href="https://blog.gopheracademy.com/advent-2015/etcd-distributed-key-value-store-with-grpc-http2/" target="_blank" rel="noopener">CoreOS blogpost&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> and in &lt;a href="https://cloud.google.com/blog/big-data/2016/03/announcing-grpc-alpha-for-google-cloud-pubsub" target="_blank" rel="noopener">Google Cloud PubSub testing&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. In the coming months, we will invest a lot more in performance tuning.&lt;/p>
&lt;p>Even within Google, we have seen Google cloud APIs like &lt;a href="https://cloudplatform.googleblog.com/2015/07/A-Go-client-for-Google-Cloud-Bigtable.html" target="_blank" rel="noopener">BigTable&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, PubSub, &lt;a href="https://github.com/GoogleCloudPlatform/java-docs-samples/tree/master/speech/grpc" target="_blank" rel="noopener">Speech&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>, launch of a gRPC-based API surface leading to ease of use and performance benefits. Products like &lt;a href="https://research.googleblog.com/2016/02/running-your-models-in-production-with.html" target="_blank" rel="noopener">Tensorflow&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> have effectively used gRPC for inter-process communication as well.
Beyond usage, we are keen to see the contributor community grow with gRPC. We are already starting to see contributions around gRPC in meaningful ways in the &lt;a href="https://github.com/grpc-ecosystem" target="_blank" rel="noopener">grpc-ecosystem&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> organization. We are very happy to see projects like &lt;a href="https://github.com/grpc-ecosystem/grpc-gateway" target="_blank" rel="noopener">grpc-gateway&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> to enable users to serve REST clients with gRPC based services, &lt;a href="https://github.com/grpc-ecosystem/polyglot" target="_blank" rel="noopener">Polyglot&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> to have a CLI for gRPC, &lt;a href="https://github.com/grpc-ecosystem/go-grpc-prometheus" target="_blank" rel="noopener">Prometheus monitoring&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> of gRPC Services and work with &lt;a href="https://github.com/grpc-ecosystem/grpc-opentracing" target="_blank" rel="noopener">OpenTracing&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. You can suggest and contribute projects to this organization &lt;a href="https://docs.google.com/a/google.com/forms/d/119zb79XRovQYafE9XKjz9sstwynCWcMpoJwHgZJvK74/edit" target="_blank" rel="noopener">here&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. We look forward to working with the community to take the gRPC project to new heights.&lt;/p></description></item><item><title>Blog: Mobile Benchmarks</title><link>https://grpc.io/blog/mobile-benchmarks/</link><pubDate>Tue, 26 Jul 2016 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/mobile-benchmarks/</guid><description>
&lt;p>As gRPC has become a better and faster RPC framework, we&amp;rsquo;ve consistently gotten the question, &amp;ldquo;How &lt;em>much&lt;/em> faster is gRPC?&amp;rdquo; We already have comprehensive server-side benchmarks, but we don&amp;rsquo;t have mobile benchmarks. Benchmarking a client is a bit different than benchmarking a server. We care more about things such as latency and request size and less about things like queries per second (QPS) and number of concurrent threads. Thus we built an Android app in order to quantify these factors and provide solid numbers behind them.&lt;/p>
&lt;p>Specifically what we want to benchmark is client side protobuf vs. JSON serialization/deserialization and gRPC vs. a RESTful HTTP JSON service. For the serialization benchmarks, we want to measure the size of messages and speed at which we serialize and deserialize. For the RPC benchmarks, we want to measure the latency of end-to-end requests and packet size.&lt;/p>
&lt;h2 id="protobuf-vs-json">Protobuf vs. JSON&lt;/h2>
&lt;p>In order to benchmark protobuf and JSON, we ran serializations and deserializations over and over on randomly generated protos, which can be seen &lt;a href="https://github.com/david-cao/gRPCBenchmarks/tree/master/protolite_app/app/src/main/proto" target="_blank" rel="noopener">here&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. These protos varied quite a bit in size and complexity, from just a few bytes to over 100kb. JSON equivalents were created and then also benchmarked. For the protobuf messages, we had three main methods of serializing and deserializing: simply using a byte array, &lt;code>CodedOutputStream&lt;/code>/&lt;code>CodedInputStream&lt;/code> which is protobuf&amp;rsquo;s own implementation of input and output streams, and Java&amp;rsquo;s &lt;code>ByteArrayOutputStream&lt;/code> and &lt;code>ByteArrayInputStream&lt;/code>. For JSON we used &lt;code>org.json&lt;/code>&amp;rsquo;s &lt;a href="https://developer.android.com/reference/org/json/JSONObject.html" target="_blank" rel="noopener">&lt;code>JSONObject&lt;/code>&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. This only had one method to serialize and deserialize, &lt;code>toString()&lt;/code> and &lt;code>new JSONObject()&lt;/code>, respectively.&lt;/p>
&lt;p>In order to keep benchmarks as accurate as possible, we wrapped the code to be benchmarked in an interface and simply looped it for a set number of iterations. This way we discounted any time spent checking the system time.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">interface&lt;/span> &lt;span style="color:#0a8;font-weight:bold">Action&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">execute&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// Sample benchmark of multiplication
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>Action a &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> Action&lt;span style="color:#555">()&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#99f">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">execute&lt;/span>&lt;span style="color:#555">()&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#078;font-weight:bold">int&lt;/span> x &lt;span style="color:#555">=&lt;/span> 1000 &lt;span style="color:#555">*&lt;/span> 123456&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">for&lt;/span> &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#078;font-weight:bold">int&lt;/span> i &lt;span style="color:#555">=&lt;/span> 0&lt;span style="color:#555">;&lt;/span> i &lt;span style="color:#555">&amp;lt;&lt;/span> 100&lt;span style="color:#555">;&lt;/span> &lt;span style="color:#555">++&lt;/span>i&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> a&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">execute&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Before running a benchmark, we ran a warmup in order to clean out any erratic behaviour by the JVM, and then calculated the number of iterations needed to run for a set time (10 seconds in the protobuf vs. JSON case). To do this, we started with 1 iteration, measured the time it took for that run, and compared it to a minimum sample time (2 seconds in our case). If the number of iterations took long enough, we estimated the number of iterations needed to run for 10 seconds by doing some math. Otherwise, we multiplied the number of iterations by 2 and repeated.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-Java" data-lang="Java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// This can be found in ProtobufBenchmarker.java benchmark()
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>&lt;span style="color:#078;font-weight:bold">int&lt;/span> iterations &lt;span style="color:#555">=&lt;/span> 1&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// Time action simply reports the time it takes to run a certain action for that number of iterations
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>&lt;span style="color:#078;font-weight:bold">long&lt;/span> elapsed &lt;span style="color:#555">=&lt;/span> timeAction&lt;span style="color:#555">(&lt;/span>action&lt;span style="color:#555">,&lt;/span> iterations&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">while&lt;/span> &lt;span style="color:#555">(&lt;/span>elapsed &lt;span style="color:#555">&amp;lt;&lt;/span> MIN_SAMPLE_TIME_MS&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> iterations &lt;span style="color:#555">*=&lt;/span> 2&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> elapsed &lt;span style="color:#555">=&lt;/span> timeAction&lt;span style="color:#555">(&lt;/span>action&lt;span style="color:#555">,&lt;/span> iterations&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// Estimate number of iterations to run for 10 seconds
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>iterations &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#078;font-weight:bold">int&lt;/span>&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">((&lt;/span>TARGET_TIME_MS &lt;span style="color:#555">/&lt;/span> &lt;span style="color:#555">(&lt;/span>&lt;span style="color:#078;font-weight:bold">double&lt;/span>&lt;span style="color:#555">)&lt;/span> elapsed&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">*&lt;/span> iterations&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="results">Results&lt;/h2>
&lt;p>Benchmarks were run on protobuf, JSON, and gzipped JSON.&lt;/p>
&lt;p>We found that regardless of the serialization/deserialization method used for protobuf, it was consistently about 3x faster for serializing than JSON. For deserialization, JSON is actually a bit faster for small messages (&amp;lt;1kb), around 1.5x, but for larger messages (&amp;gt;15kb) protobuf is 2x faster. For gzipped JSON, protobuf is well over 5x faster in serialization, regardless of size. For deserialization, both are about the same at small messages, but protobuf is about 3x faster for larger messages. Results can be explored in more depth and replicated &lt;a href="https://github.com/david-cao/gRPCBenchmarks" target="_blank" rel="noopener">in the README&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p>
&lt;h2 id="grpc-vs-http-json">gRPC vs. HTTP JSON&lt;/h2>
&lt;p>To benchmark RPC calls, we want to measure end-to-end latency and bandwidth. To do this, we ping pong with a server for 60 seconds, using the same message each time, and measure the latency and message size. The message consists of some fields for the server to read, and a payload of bytes. We compared gRPC&amp;rsquo;s unary call to a simple RESTful HTTP JSON service. The gRPC benchmark creates a channel, and starts a unary call that repeats when it receives a response until 60 seconds have passed. The response contains a proto with the same payload sent.&lt;/p>
&lt;p>Similarly for the HTTP JSON benchmarks, it sends a POST request to the server with an equivalent JSON object, and the server sends back a JSON object with the same payload.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// This can be found in AsyncClient.java doUnaryCalls()
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">// Make stub to send unary call
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span>&lt;span style="color:#069;font-weight:bold">final&lt;/span> BenchmarkServiceStub stub &lt;span style="color:#555">=&lt;/span> BenchmarkServiceGrpc&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">newStub&lt;/span>&lt;span style="color:#555">(&lt;/span>channel&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>stub&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">unaryCall&lt;/span>&lt;span style="color:#555">(&lt;/span>request&lt;span style="color:#555">,&lt;/span> &lt;span style="color:#069;font-weight:bold">new&lt;/span> StreamObserver&lt;span style="color:#555">&amp;lt;&lt;/span>SimpleResponse&lt;span style="color:#555">&amp;gt;()&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#078;font-weight:bold">long&lt;/span> lastCall &lt;span style="color:#555">=&lt;/span> System&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">nanoTime&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// Do nothing on next
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#99f">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">onNext&lt;/span>&lt;span style="color:#555">(&lt;/span>SimpleResponse value&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#99f">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">onError&lt;/span>&lt;span style="color:#555">(&lt;/span>Throwable t&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Status status &lt;span style="color:#555">=&lt;/span> Status&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">fromThrowable&lt;/span>&lt;span style="color:#555">(&lt;/span>t&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> System&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">err&lt;/span>&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">println&lt;/span>&lt;span style="color:#555">(&lt;/span>&lt;span style="color:#c30">&amp;#34;Encountered an error in unaryCall. Status is &amp;#34;&lt;/span> &lt;span style="color:#555">+&lt;/span> status&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> t&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">printStackTrace&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> future&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">cancel&lt;/span>&lt;span style="color:#555">(&lt;/span>&lt;span style="color:#069;font-weight:bold">true&lt;/span>&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// Repeat if time isn&amp;#39;t reached
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> &lt;span style="color:#99f">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">public&lt;/span> &lt;span style="color:#078;font-weight:bold">void&lt;/span> &lt;span style="color:#c0f">onCompleted&lt;/span>&lt;span style="color:#555">()&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#078;font-weight:bold">long&lt;/span> now &lt;span style="color:#555">=&lt;/span> System&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">nanoTime&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#09f;font-style:italic">// Record the latencies in microseconds
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic">&lt;/span> histogram&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">recordValue&lt;/span>&lt;span style="color:#555">((&lt;/span>now &lt;span style="color:#555">-&lt;/span> lastCall&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">/&lt;/span> 1000&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> lastCall &lt;span style="color:#555">=&lt;/span> now&lt;span style="color:#555">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Context prevCtx &lt;span style="color:#555">=&lt;/span> Context&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">ROOT&lt;/span>&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">attach&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">try&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">if&lt;/span> &lt;span style="color:#555">(&lt;/span>endTime &lt;span style="color:#555">&amp;gt;&lt;/span> now&lt;span style="color:#555">)&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> stub&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">unaryCall&lt;/span>&lt;span style="color:#555">(&lt;/span>request&lt;span style="color:#555">,&lt;/span> &lt;span style="color:#069;font-weight:bold">this&lt;/span>&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span> &lt;span style="color:#069;font-weight:bold">else&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> future&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">done&lt;/span>&lt;span style="color:#555">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span> &lt;span style="color:#069;font-weight:bold">finally&lt;/span> &lt;span style="color:#555">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Context&lt;span style="color:#555">.&lt;/span>&lt;span style="color:#309">current&lt;/span>&lt;span style="color:#555">().&lt;/span>&lt;span style="color:#309">detach&lt;/span>&lt;span style="color:#555">(&lt;/span>prevCtx&lt;span style="color:#555">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#555">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#555">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Both &lt;code>HttpUrlConnection&lt;/code> and the &lt;a href="https://square.github.io/okhttp/" target="_blank" rel="noopener">OkHttp library&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> were used.&lt;/p>
&lt;p>Only gRPC&amp;rsquo;s unary calls were benchmarked against HTTP, since streaming calls were over 2x faster than the unary calls. Moreover, HTTP has no equivalent of streaming, which is an HTTP/2 specific feature.&lt;/p>
&lt;h2 id="results-1">Results&lt;/h2>
&lt;p>In terms of latency, gRPC is &lt;strong>5x-10x&lt;/strong> faster up to the 95th percentile, with averages of around 2 milliseconds for an end-to-end request. For bandwidth, gRPC is about 3x faster for small requests (100-1000 byte payload), and consistently 2x faster for large requests (10kb-100kb payload). To replicate these results or explore in more depth, check out our &lt;a href="https://github.com/david-cao/gRPCBenchmarks" target="_blank" rel="noopener">repository&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>.&lt;/p></description></item><item><title>Blog: gRPC with REST and Open APIs</title><link>https://grpc.io/blog/coreos/</link><pubDate>Mon, 09 May 2016 00:00:00 +0000</pubDate><guid>https://grpc.io/blog/coreos/</guid><description>
&lt;p>Our guest post today comes from Brandon Phillips of &lt;a href="https://coreos.com/" target="_blank" rel="noopener">CoreOS&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. CoreOS builds open source projects and products for Linux Containers. Their flagship product for consensus and discovery &lt;a href="https://coreos.com/etcd/" target="_blank" rel="noopener">etcd&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> and their container engine &lt;a href="https://coreos.com/rkt/" target="_blank" rel="noopener">rkt&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> are early adopters of gRPC.&lt;/p>
&lt;p>One of the key reasons CoreOS chose gRPC is because it uses HTTP/2, enabling applications to present both a HTTP 1.1 REST/JSON API and an efficient gRPC interface on a single TCP port (available for Go). This provides developers with compatibility with the REST web ecosystem, while advancing a new, high-efficiency RPC protocol. With the recent release of Go 1.6, Go ships with a stable &lt;code>net/http2&lt;/code> package by default.&lt;/p>
&lt;p>Since many CoreOS clients speak HTTP 1.1 with JSON, gRPC&amp;rsquo;s easy interoperability with JSON and the &lt;a href="https://github.com/OAI/OpenAPI-Specification" target="_blank" rel="noopener">Open API Specification&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a> (formerly Swagger) was extremely valuable. For their users who are more comfortable with HTTP/1.1+JSON-based and Open API Spec APIs they used a combination of open source libraries to make their gRPC services available in both gRPC and HTTP REST flavors, using API multiplexers to give users the best of both worlds. Let&amp;rsquo;s dive into the details and find out how they did it!&lt;/p>
&lt;h2 id="a-grpc-application-called-echoservice">A gRPC application called EchoService&lt;/h2>
&lt;p>In this post we will build a small proof-of-concept gRPC application from a gRPC API definition, add a REST service gateway, and finally serve it all on a single TLS port. The application is called EchoService, and is the web equivalent of the shell command echo: the service returns, or &amp;ldquo;echoes&amp;rdquo;, whatever text is sent to it.&lt;/p>
&lt;p>First, let’s define the arguments to EchoService in a protobuf message called EchoMessage, which includes a single field called value. We will define this message in a protobuf &amp;ldquo;.proto&amp;rdquo; file called &lt;code>service.proto&lt;/code>. Here is our EchoMessage:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-proto" data-lang="proto">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">message&lt;/span> &lt;span style="color:#0a8;font-weight:bold">EchoMessage&lt;/span> {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#078;font-weight:bold">string&lt;/span> value &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#f60">1&lt;/span>;&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>}&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>In this same .proto file, we define a gRPC service that takes this data structure and returns it:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-proto" data-lang="proto">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">service&lt;/span> EchoService {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#069;font-weight:bold">rpc&lt;/span> Echo(EchoMessage) &lt;span style="color:#069;font-weight:bold">returns&lt;/span> (EchoMessage) {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> }&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>}&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Running this &lt;code>service.proto&lt;/code> file &amp;ldquo;as is&amp;rdquo; through the Protocol Buffer compiler &lt;code>protoc&lt;/code> generates a stub gRPC service in Go, along with clients in various languages. But gRPC alone isn’t as useful as a service that also exposes a REST interface, so we won’t stop with the gRPC service stub.&lt;/p>
&lt;p>Next, we add the gRPC REST Gateway. This library will build a RESTful proxy on top of the gRPC EchoService. To build this gateway, we add metadata to the EchoService .proto to indicate that the Echo RPC maps to a RESTful POST method with all RPC parameters mapped to a JSON body. The gateway can map RPC parameters to URL paths and query parameters, but we omit those complications here for brevity.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-proto" data-lang="proto">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">service&lt;/span> EchoService {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#069;font-weight:bold">rpc&lt;/span> Echo(EchoMessage) &lt;span style="color:#069;font-weight:bold">returns&lt;/span> (EchoMessage) {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> &lt;span style="color:#069;font-weight:bold">option&lt;/span> (google.api.http) &lt;span style="color:#555">=&lt;/span> {&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> post&lt;span style="color:#555">:&lt;/span> &lt;span style="color:#c30">&amp;#34;/v1/echo&amp;#34;&lt;/span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> body&lt;span style="color:#555">:&lt;/span> &lt;span style="color:#c30">&amp;#34;*&amp;#34;&lt;/span>&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> };&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span> }&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a00;background-color:#faa">&lt;/span>}&lt;span style="color:#a00;background-color:#faa">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This means the gateway, once generated by &lt;code>protoc&lt;/code>, can now accept a HTTP request from &lt;code>curl&lt;/code> like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>curl -X POST -k https://localhost:10000/v1/echo -d &lt;span style="color:#c30">&amp;#39;{&amp;#34;value&amp;#34;: &amp;#34;CoreOS is hiring!&amp;#34;}&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The whole system so far looks like this, with a single &lt;code>service.proto&lt;/code> file generating both a gRPC server and a REST proxy:&lt;/p>
&lt;img src="https://grpc.io/img/grpc-rest-gateway.png" class="img-responsive" alt="gRPC API with REST gateway">
&lt;p>To bring this all together, the echo service creates a Go &lt;code>http.Handler&lt;/code> to detect if the protocol is HTTP/2 and the Content-Type is &amp;ldquo;application/grpc&amp;rdquo;, and sends such requests to the gRPC server. Everything else is routed to the REST gateway. The code looks something like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">if&lt;/span> r.ProtoMajor &lt;span style="color:#555">==&lt;/span> &lt;span style="color:#f60">2&lt;/span> &lt;span style="color:#555">&amp;amp;&amp;amp;&lt;/span> strings.&lt;span style="color:#c0f">Contains&lt;/span>(r.Header.&lt;span style="color:#c0f">Get&lt;/span>(&lt;span style="color:#c30">&amp;#34;Content-Type&amp;#34;&lt;/span>), &lt;span style="color:#c30">&amp;#34;application/grpc&amp;#34;&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> grpcServer.&lt;span style="color:#c0f">ServeHTTP&lt;/span>(w, r)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>} &lt;span style="color:#069;font-weight:bold">else&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> otherHandler.&lt;span style="color:#c0f">ServeHTTP&lt;/span>(w, r)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>To try it out, all you need is a working Go 1.6 development environment and the following simple commands:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>go get -u github.com/philips/grpc-gateway-example
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>grpc-gateway-example serve
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>With the server running you can try requests on both HTTP 1.1 and gRPC interfaces:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>grpc-gateway-example &lt;span style="color:#366">echo&lt;/span> Take a REST from REST with gRPC
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>curl -X POST -k https://localhost:10000/v1/echo -d &lt;span style="color:#c30">&amp;#39;{&amp;#34;value&amp;#34;: &amp;#34;CoreOS is hiring!&amp;#34;}&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>One last bonus: because we have an Open API specification, you can browse the Open API UI running at &lt;code>https://localhost:10000/swagger-ui/#!/EchoService/Echo&lt;/code> if you have the server above running on your laptop.&lt;/p>
&lt;img src="https://grpc.io/img/grpc-swaggerscreen.png" class="img-responsive" alt="gRPC/REST Open API document">
&lt;p>We’ve taken a look at how to use gRPC to bridge to the world of REST. If you want to take a look at the complete project, check out the &lt;a href="https://github.com/philips/grpc-gateway-example" target="_blank" rel="noopener">repo on GitHub&lt;i class="fas fa-external-link-alt">&lt;/i>&lt;/a>. We think this pattern of using a single protobuf to describe an API leads to an easy to consume, flexible API framework, and we’re excited to leverage it in more of our projects.&lt;/p></description></item></channel></rss>