惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Tenable Blog
MyScale Blog
MyScale Blog
罗磊的独立博客
Hugging Face - Blog
Hugging Face - Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
爱范儿
爱范儿
博客园 - 司徒正美
D
Darknet – Hacking Tools, Hacker News & Cyber Security
量子位
N
News | PayPal Newsroom
S
Secure Thoughts
酷 壳 – CoolShell
酷 壳 – CoolShell
L
LINUX DO - 热门话题
有赞技术团队
有赞技术团队
V
Visual Studio Blog
T
Tailwind CSS Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Project Zero
Project Zero
B
Blog RSS Feed
J
Java Code Geeks
Google Online Security Blog
Google Online Security Blog
Last Week in AI
Last Week in AI
Cyberwarzone
Cyberwarzone
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
小众软件
小众软件
博客园 - 【当耐特】
Latest news
Latest news
T
Threat Research - Cisco Blogs
aimingoo的专栏
aimingoo的专栏
博客园_首页
博客园 - 三生石上(FineUI控件)
Engineering at Meta
Engineering at Meta
D
Docker
Forbes - Security
Forbes - Security
Help Net Security
Help Net Security
Apple Machine Learning Research
Apple Machine Learning Research
P
Proofpoint News Feed
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Simon Willison's Weblog
Simon Willison's Weblog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
V2EX - 技术
V2EX - 技术
N
Netflix TechBlog - Medium
The Last Watchdog
The Last Watchdog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
T
Threatpost
Cloudbric
Cloudbric
T
The Exploit Database - CXSecurity.com
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 叶小钗
Webroot Blog
Webroot Blog

VictoriaMetrics: Simple & Reliable Monitoring for Everyone on VictoriaMetrics

Operator now has Long-Term Support (LTS) version Multi-tiered Observability: A Practical Way to Handle Diverse Workloads VictoriaMetrics April 2026 Ecosystem Updates Not All Telemetry Requires Premium Pricing VictoriaMetrics at KubeCon Amsterdam: Community Highlights What's new in VictoriaMetrics Anomaly Detection (Q1 2026) What's New in VictoriaMetrics Cloud Q1 2026? Logs, MCP Server, Better Alerting, and... a Secret Project VictoriaMetrics at KubeCon: Optimizing Tail Sampling in OpenTelemetry with Retroactive Sampling VictoriaMetrics March 2026 Ecosystem Updates Observability Lessons From OpenAI Benchmarking Kubernetes Log Collectors: vlagent, Vector, Fluent Bit, OpenTelemetry Collector, and more VictoriaMetrics February 2026 Ecosystem Updates VictoriaMetrics at FOSDEM, Cloud Native Days France, and CfgMgmtCamp Ghent VictoriaLogs in VictoriaMetrics Cloud: Fast, Cost-Effective Log Management is Here What’s new in VictoriaMetrics Anomaly Detection (2025) VictoriaMetrics January 2026 Ecosystem Updates VictoriaLogs Basics: What You Need to Know, with Examples & Visuals What's New in VictoriaMetrics Cloud Q4 2025? New tiers, more deployment options, IaC and alerting rules. Vibe coding tools observability with VictoriaMetrics Stack and OpenTelemetry How a US Software Provider Improved Traffic Alerting with VictoriaMetrics Anomaly Detection VictoriaMetrics 2025 Developer Experience: A Year in Review Spotify’s performance & control across large monitoring environments with VictoriaMetrics VictoriaMetrics Achieves Red Hat OpenShift Operator Certification Our latest updates across the VictoriaMetrics Observability ecosystem New Capacity Tiers in VictoriaMetrics Cloud Announcing 1B+ Downloads & Product Development With Logs, Traces, Metrics AI Agents Observability with OpenTelemetry and the VictoriaMetrics Stack Discarding gRPC-Go: The Story Behind OTLP/gRPC Support in VictoriaTraces What's New in VictoriaMetrics Cloud Q3 2025? From new region in Asia to proactive alerts How DreamHost Slashed Memory Usage by 80% and Scaled to 76 Million Time Series Upcoming Conferences & Meetups: Where to Meet Our Team VictoriaMetrics Long-Term Support (LTS): H2 2025 Update Creating a Sustainable Open Source Business Model - Introduction Full-Stack Observability with VictoriaMetrics in the OTel Demo Alerting Best Practices vmanomaly Deep Dive: Smarter Alerting with AI (Tech Talk Companion) VictoriaLogs Practical Ingestion Guide for Message, Time and Streams Monotonic and Wall Clock Time in the Go time package Hello Singapore! VictoriaMetrics Cloud Expands to Asia Pacific MCP Server Integration & Much More: What's New in VictoriaMetrics Cloud Q2 2025 FIPS 140-3 Compatible Builds for VictoriaMetrics Enterprise Components VictoriaLogs Unleashed: Cluster Version Now Available for Exceptional, Linear Scaling Integrations made easy with VictoriaMetrics Cloud Developer's Note: Research on Distributed Tracing, Comparing With Tempo and ClickHouse vmagent: Key Features Explained in Under 15 Minutes Go synctest: Solving Flaky Tests vmalert: Maximize Your Monitoring (Tech Talk Companion) Celebrating 14K Stars on GitHub: Spring Update vmalert: Maximize Your Monitoring VictoriaMetrics Connects with the Open Source Community at LinuxFest Northwest 2025 Graceful Shutdown in Go: Practical Patterns VictoriaLogs: Gaps, Gains & Growth Prometheus Monitoring: Functions, Subqueries, Operators, and Modifiers VictoriaMetrics Cloud: What's New in Q1 2025? Don’t default to microservices: You’ll thank us later! Container CPU Requests & Limits Explained with GOMAXPROCS Tuning gRPC in Go: Streaming RPCs, Interceptors, and Metadata From Chaos to Clarity with VictoriaLogs Prometheus Alerting 101: Rules, Recording Rules, and Alertmanager Heading to London: Meet Our Team at KubeCon Europe 2025 Inside vmselect: The Query Processing Engine of VictoriaMetrics Meet Our Team at Scale 22x Practical Protobuf - From Basic to Best Practices VictoriaLogs Status Update: Heading Towards the Cluster Version 24th of February 2025 Statement: VictoriaMetrics Stands with Ukraine! Prometheus Metrics Explained: Counters, Gauges, Histograms & Summaries Prometheus Monitoring: Instant Queries and Range Queries Explained 300%+ Growth in 2024: Join Our Team in 2025! FOSDEM 2025 recap How Protobuf Works—The Art of Data Encoding OpenTelemetry, Prometheus, and More: Which Is Better for Metrics Collection and Propagation? How vmstorage Handles Query Requests From vmselect How vmstorage's IndexDB Works VictoriaMetrics Tech Talk Stream: A Deep Dive into Blackbox Monitoring How HTTP/2 Works and How to Enable It in Go VictoriaMetrics Cloud: What's New in Q4 2024? How vmstorage Processes Data: Retention, Merging, Deduplication,... How vmstorage Handles Data Ingestion From vminsert When Metrics Meet vminsert: A Data-Delivery Story VictoriaMetrics helps IHI Terrasun Win Big in Vegas on $1.2B Clean Energy Project Piros | VictoriaMetrics Partner Allenta | VictoriaMetrics Partner CloudRaft | VictoriaMetrics Partner Sensedia & VictoriaMetrics: API-compatible Efficient Storage Scalable Prometheus: Why DSV Chose VictoriaMetrics Sensor Factory | VictoriaMetrics Partner Erythix | VictoriaMetrics Partner Groove X & VictoriaMetrics: Faster Device Health Monitoring Scaled & Performant Monitoring at Spotify with VictoriaMetrics Grammarly & VictoriaMetrics: 10× Lower Costs & Direct Access Zelarsoft | VictoriaMetrics Partner DFKI & VictoriaMetrics: Efficient Long-Term Metric Storage Niubits | VictoriaMetrics Partner Megazone Cloud | VictoriaMetrics Partner Cogito Software | VictoriaMetrics Partner Bajau | VictoriaMetrics Partner Find Out Why Dig Security Chose VictoriaMetrics! Ness | VictoriaMetrics Partner Alpha Data | VictoriaMetrics Partner SIOS Technology | VictoriaMetrics Partner
From net/rpc to gRPC in Go Applications
Phuong Le · 2024-12-20 · via VictoriaMetrics: Simple & Reliable Monitoring for Everyone on VictoriaMetrics

This article kicks off a series on communication protocols related to gRPC:

  1. From net/rpc to gRPC in Go Applications (We’re here)
  2. How HTTP/2 Works and How to Enable It in Go
  3. Practical Protobuf - From Basic to Best Practices
  4. How Protobuf Works—The Art of Data Encoding
  5. gRPC in Go: Streaming RPCs, Interceptors, and Metadata

To start things off, we’re keeping it simple: cover the basics of gRPC and Protobuf, and then build an RPC setup (not gRPC yet, gRPC is just typical way to implement RPC). We’ll use Go’s built-in net/rpc package to get a feel for how it all works under the hood and why we need gRPC.

What’s gRPC & Protobuf?

#

In a nutshell, gRPC (Google Remote Procedure Call) is a way to get different services talking to each other faster and more efficiently. The catch is, it’s a bit less straightforward than your usual REST setup.

With JSON-based APIs, you’d define your API contracts in a document like Swagger. But gRPC takes a different strategy. Everything starts with .proto files — these are your blueprints for how services communicate. They define the types of data, the fields, and the rules for exchanging messages. From this file, gRPC can generate client and server code for you, so you don’t have to write it from scratch.

A single schema powers multi-language compatibility

A single schema powers multi-language compatibility

Here’s an example of a simple .proto file. It defines a user service and the messages that let services talk to each other using Protobuf (Protocol Buffers):

syntax = "proto3";  // Using the latest Protobuf version

package example.app;  // Namespace for generated code

// Import another .proto file
import "google/protobuf/timestamp.proto";

// Enum
enum UserRole {
  USER = 0;
  ADMIN = 1;
  SUPER_ADMIN = 2;
}

// Message for a user
message User {
  int32 id = 1;
  string name = 2;
  optional string email = 3;
  UserRole role = 4;
  google.protobuf.Timestamp created_at = 5;
}

message GetUserRequest {
  int32 user_id = 1;
}

message GetUserResponse {
  User user = 1;
}

// Service definition
service UserService {
  rpc GetUser (GetUserRequest) returns (GetUserResponse);  // Fetch a single user
  rpc CreateUser (User) returns (GetUserResponse);         // Create a new user
}

That’s a lot to unpack, but don’t worry — it’s mostly just Protobuf syntax: things like imports, enums, messages, services, and rpcs. Once you’ve seen it a few times, it starts to click. We’ll revisit this section later on.

gRPC uses HTTP/2 as its underlying protocol and it makes it easier to send concurrent requests over a single connection.

“Why?”

With HTTP/1.1, your browser typically opens multiple “phone lines” (TCP connections) to handle several requests at once, like fetching images, text, code from a webpage. Otherwise, it processes them one by one. HTTP/2 changes the game by using a single connection to send all the requests simultaneously and this clever trick is called “multiplexing.”

Now, what make it feel different to your normal REST is, you don’t think in terms of “endpoints” anymore.

Instead, you’re calling functions on the server like they’re part of your own code. That’s what Remote Procedure Call (RPC) is all about. The server does all the heavy lifting behind the scenes, but to you, it just feels like calling a regular function.

“Okay, but why not use gRPC for everything?”

It’s all about trade-offs. gRPC brings speed, consistency, and a robust typing system to the table, but it doesn’t have the same simplicity or flexibility as JSON-based APIs.

  • Go with gRPC: If you care about performance, low latency, real-time communication, or need something that works well across different languages (e.g., Python, Java, C++).
  • Stick with REST: If you value simplicity, easy to read, easy to write, and flexibility (like avoiding client updates every time your API changes), or you’re building something browser-based.

And that’s it for now! We’re not jumping straight into gRPC, HTTP/2, or Protobuf just yet. Instead, we’ll start from the ground up with Go’s net/rpc package to build a solid foundation.

net/rpc

#

First off, a little heads-up, net/rpc isn’t the same as gRPC. It uses its own custom binary protocol over HTTP or raw TCP, and it doesn’t have the fancy features or performance benefits of HTTP/2. That said, it’s part of Go’s standard library, which makes it a simple way to demonstrate the idea of RPC in action.

Let’s not overcomplicate it. Here’s a quick example to get the gist of how it works:

// Service is the struct defining the service.
type Service struct{}

// Hello is the method exposed to RPC clients.
func (h *Service) Hello(request string, reply *string) error {
  *reply = "Hello, " + request + "!"
  return nil
}

func main() {
	_ = rpc.Register(new(Service))

	listener, _ := net.Listen("tcp", ":8080")
	defer listener.Close()

	// Accept connections and serve them in separate goroutines.
	for {
		conn, _ := listener.Accept()
		go rpc.ServeConn(conn)
	}
}

Skipping error handling here to keep things focused.

This snippet sets up the server side. It listens on port 8080 for TCP connections and serves the Service through the net/rpc package. A few things to keep in mind about the service and its methods:

  • The service’s type has to be exported.
  • The method must also be exported.
  • Methods need exactly two arguments: the first is a value type (input), and the second is a pointer (output), which lets the server write back the result to the client.
  • The method can only return one value, and that’s an error. Any actual data goes back to the client through the second argument.

So, the signature of a valid RPC method looks like this:

func (t *Type) MethodName(argType Argument, replyType *Reply) error

And, RPC is about sending data, things like function arguments or return values, between a client and a server. For this to work, the data has to be encoded into a format that can travel over the network, and then decoded on the other side. With net/rpc, this encoding and decoding happens automatically using the gob format by default.

“What’s with the gob format?”

gob is Go’s native way of serializing data. It takes Go data structures and turns them into a compact binary format that’s easy to send over a network or save to a file. The catch is, it’s Go-centric, so it’s perfect if both the client and server are written in Go but not great if you’re mixing languages.

Now let’s see how you’d create a client to call the Hello method from the Service:

func main() {
	// Connect to the server at localhost:8080.
	client, _ := rpc.Dial("tcp", "localhost:8080")
	defer client.Close()

	// Make a remote call to the Service.Hello method.
	var reply string
	_ = client.Call("Service.Hello", "World", &reply)

	fmt.Println(reply)
}

// Output:
// Hello, World!

Here’s the play-by-play of what’s happening:

Sending method details and parameters to server

Sending method details and parameters to server

The client starts by dialing the server. This is where the TCP handshake happens (SYN, SYN-ACK, ACK, you get the idea). The rpc.Dial function you see here is just Go’s net.Dial under the hood, so no magic.

Next, the client creates a request. This request includes: the name of the service (Service), the name of the method (Hello), and the arguments you’re passing in ("World"). Everything is then packed up into a neat binary format using gob. Along with that, the request gets a sequence number, an incremental number that starts at zero and goes up with each request.

“Why does it need a sequence number?”

It’s all about keeping things organized. Let’s talk about that connection.

When the client connects to the server, they set up a single TCP connection. This connection stays open until you explicitly close it or something goes wrong (like the server shutting down or the network breaking). And you can send multiple requests over that same connection without starting over. No need to keep shaking hands for every call.

Each RPC request tagged with a unique ID

Each RPC request tagged with a unique ID

You can even fire off several RPC requests at once, one after the other, or in parallel. The responses might come back in any order, depending on how quickly the server processes them. The sequence number ensures that each response lines up perfectly with its matching request.

On the server side, when a request comes in, the server decodes it to figure out which service and method it’s targeting. It checks its registry of services (remember, we registered the Service earlier) and spawns a goroutine to handle the call. That’s how it all ties together, requests, responses, and that sequence number keeping everything in sync.

“Does it use reflection? We didn’t explicitly provide methods for the server, how does it know?”

Yes, reflection does a lot of the heavy lifting here. It’s used at multiple stages: when the service is registered to figure out which methods are available; during request handling to create the right argument types; and finally, when it’s time to actually call the method. This heavy use of reflection is one reason why gRPC, with its pre-generated code, can be more performant than net/rpc.

Once the method finishes running and we’ve got a result, the server encodes both the result and any potential error using the codec (again, default is gob) and sends it back to the client over the same connection.

Back on the client side, the response arrives and is decoded. That sequence number we talked about earlier makes sure the response is matched to the right request. For synchronous calls (like client.Call), the result or error is handed right back to the caller. If it’s an asynchronous call (client.Go), the result goes through a channel.

“Okay, but gob only works with Go services. What if I want to connect to something written in another language?”

Great point. gob is definitely Go-specific, which is fine if your whole system is in Go, but not so helpful if you need to communicate across languages. Luckily, net/rpc supports swapping out the codec, and it even comes with built-in support for a JSON-based codec:

// Server
go rpc.ServeCodec(jsonrpc.NewServerCodec(conn))

// Client
conn, _ := net.Dial("tcp", "localhost:8080")
defer conn.Close()
client := rpc.NewClientWithCodec(jsonrpc.NewClientCodec(conn))

Instead of using rpc.ServeConn, we switch to rpc.ServeCodec, which lets us specify a custom codec. In this case, it’s JSON. Now if you log the request and response, it’s way more human-friendly. The request might look like this:

{ "method": "Service.Hello", "params": ["World"], "id": 0 }

And the response from server:

{ "id": 0, "result": "Hello, World!", "error": null }

If there’s an error, like calling a method that doesn’t exist, you’d see something like:

{
  "id": 0,
  "result": null,
  "error": "rpc: can't find service Service.HelloFake"
}

It’s worth mentioning that net/rpc is considered “frozen.” This means it’s stable and works fine for basic use, but it’s not actively developed anymore. For modern apps, gRPC is often the better choice — it offers more features, supports multiple languages out of the box, and comes with advanced performance perks.

And that’s a wrap for now! If you’re curious about more common gRPC use cases, we’ll look into that in the next articles.

Who We Are

#

If you want to monitor your services, track metrics, and see how everything performs, you might want to check out VictoriaMetrics. It’s a fast, open-source, and cost-saving way to keep an eye on your infrastructure.

And we’re Gophers, enthusiasts who love researching, experimenting, and sharing knowledge about Go and its ecosystem. If you spot anything that’s outdated or if you have questions, don’t hesitate to reach out. You can drop me a DM on X(@func25).

Related articles: