@func25

Software Engineer @VictoriaMetrics, building VictoriaLogs

Joined August 2014
I have made thousands of static visualizations for Go, it's time to try something new: youtube.com/watch?v=fwHok9Zh…
12
22
1
264
23,197
Some people think we can't learn software design with Go as it has no classes, no inheritance, no method overloading, etc But software design is about how we organize code, manage dependencies, and keep a change in one part from breaking another. E.g., encapsulation, it means controlling how other code can read or change our data. - In Java, we can use classes and private fields. - In Go, we can use packages and unexported names. Of course, they don't work the same way, but both let us choose what other code can access and what we want to keep inside our package or class. Polymorphism means the code can work with different implementations through an interface. Both Java and Go have interfaces but types in Go don't need a shared parent class, if they have the required methods, they satisfy the interface. DI or dependency injection is when we give a component what it needs instead of making it create that dependency itself. Like we can pass a database connection to a service when we create it. If the service accepts an interface, a test can pass a test implementation and we can do this with function parameters, I guess most of us have probably done it without knowing it was called dependency injection. Memory management is a separate (but interesting) topic. Go and Java use garbage collection, so we do not need to free heap objects ourselves. But we still need to understand how much memory our code uses, what happens when code shares data, and how keeping a reference to an object can stop the garbage collector from freeing it. Knowing syntax means we know how to write valid code. But more important is understanding the concept. I mean can we explain what practical problem it solves and when to use it? If we can solve the same problem in 2 different ways, which one is better and why? Actually starting with a complex, feature-rich language can be a good choice. Experience can't be taught, sometimes we need to spend time with that complexity before we can appreciate how simple the next language can be.
3
19
2
168
8,156
I just found an interesting Go repository: github.com/nikolaydubina/go-… If you are learning Go, spend some time here after the syntax tutorials. Learning how to check test coverage, compare benchmark results, and find bugs is also part of learning how to use Go.
3
70
1
579
21,064
You can choose the wrong backend if you only look at which one is faster in a benchmark, even when the results are accurate. The backend that is faster in the test may not be faster for your application. HTTP server performance depends on the complete request path - Routing, - middleware, - logging, - serialization, - external calls These all add work and 2 handlers can return the same responses but performing different things before sending them. Concurrency describes how much work is in progress at once. Increasing concurrent connections can increase throughput (e.g., how many requests finish per unit of time) while our server has limited capacity. But after a resource becomes saturated (reaches its capacity), additional concurrency can increase waiting time without increasing completed requests. A database pool with 100 connections does not mean your API can only handle 100 requests/sec. Each connection can be reused as soon as a request finishes using it. - If database queries finish quickly, the same connections can serve many requests in 1 second. - If queries take longer, connections stay busy longer, and new requests may have to wait for one to become available. Latency and errors give us information that throughput alone cannot. - Average latency can hide slow responses. - The p99 latency describes the point at or below which 99% of measured request latencies fall. - p100 is the maximum measured latency, the slowest request in your sample and gives us a very sensitive signal, since even a single unusually slow request can noticeably change p100. See nitter.cf/valyala/status/2091799… But none of these three tells you how many failed requests or timeouts you had. Memory usage can mean different things depending on what you are looking at. A high memory number does not always mean an application is wasting RAM - Live heap memory covers objects still considered reachable by the garbage collector. - Virtual memory includes address space the process has reserved or mapped. Some of that space may not use physical RAM at all. So seeing 4 GB of virtual memory does not mean the application is using 4 GB of RAM. - RSS shows memory currently in RAM. Some of it can be file-backed memory and is reclaimable, meaning the OS can free that RAM when needed and load the data again if the application uses it later. When the garbage collector reclaims objects, the runtime can keep that memory for reuse, so the memory usage reported by the OS may not drop immediately. So a high memory number alone does not prove waste or tell you how close the application is to OOM. It's better to always check which number you are reading, how much memory is reclaimable, and how usage changes as the application gets closer to its memory limit. If one implementation is faster in your test, that does not mean it will be faster when the workload or setup changes.
Indeed, monitoring of the maximum metric value (aka p100) is better than monitoring p99 or other percentiles: - it shows the exact maximum without any approximations and errors; - it is very easy and fast to calculate the maximum value among many maximum values obtained from different monitoring targets - just get the maximum of maximums - this works fast even if you have hundreds of thousands of monitoring targets; - it reflects the worst case of the monitored system - if you optimise the system for the worst case, it works great in the average case and at any percentile; - it is very easy to calculate p100 in Prometheus-compatible exporters via standard summary metric ( docs.victoriametrics.com/vic… ).
4
7
119
7,436
Phuong Le retweeted
We just published a PostgreSQL 19 Interactive Tour. If you want to know what is comming in the new version of Postgres and want to play with it and see it in action, check it out here: victoriametrics.com/blog/pos…
3
17
1
61
4,354
Cool, our article got featured in golangweekly.com this week. If you don’t know how Go maps work under the hood yet, now's a good time to catch up: victoriametrics.com/blog/go-…
1
9
114
5,523
Phuong Le retweeted
The first @VictoriaMetrics meetup in Spain is going to be at October 2nd, in Valencia. If you are around and interested in observability it is a good opportunity to learn more and do some networking 🙂
3
25
1,915
Phuong Le retweeted
Next week I'll be at @Percona Live in Amsterdam talking about how VictoriaLogs (from the @VictoriaMetrics stack) is able to ingest and query petabytes of logs in an efficient way.
1
4
1
26
2,642
Phuong Le retweeted
I published today an article at the @VictoriaMetrics's blog, sharing the life of a metric. I think it is a good walkthrough about what happens to your metrics once they are scraped, until they gets discarded by the retention policy. victoriametrics.com/blog/the…
2
14
2
67
8,082
This article by @func25 is one of the best Go articles I’ve read. I had no idea what a goroutine was but learnt it due to this article I also learnt more about concurrency in general, and how to effectively wait for a goroutine to finish Would definitely recommend func25.dev/posts/go-goroutin… #Golang #Learning
4
14
1
111
7,637
A dead-simple explanation of Go's Swiss Table map is on the way. Just in case you're interested in how Go maps worked before Go 1.24: victoriametrics.com/blog/go-…
1
8
182
6,164
Go changed the implementation behind sync.Map to a hash trie. The API is still the same, but this is a good time to revisit how sync.Map works, what happens internally, and when to use it instead of a regular map protected by a mutex. Detailed walkthrough here: victoriametrics.com/blog/go-…
4
50
2
356
24,526
func25.dev/posts/go-memory-v… When I first read about data races and the Go memory model years ago, it all felt kind of weird. Why doesn't the snippet below work? The Go memory model is quite long and advanced, so I decided to write a simpler explanation. It turns out this topic has some of the most interesting insights into how Go actually works. --- The Go memory model: go.dev/ref/mem
7
34
1
278
25,139
I thought this article was pretty basic, but it's getting quite a lot of views: func25.dev/posts/go-goroutin…. There might be some gold in it after all. Originally wrote it as a foundation for more advanced articles, but maybe it stands well on its own?
4
33
2
234
9,751
If you want to learn VictoriaLogs in a more interactive and visual way, I've built some colorful documentation with lots of diagrams to make it easier to digest: victorialogs.func25.dev/ It's unofficial documentation :)
2
11
90
5,471
Phuong Le retweeted
Today I'm publishing my article about the linux kernel modules. My approach, going through the loading process from the perspective to the .ko file. Understanding the sections inside, and how the kernel load it. There are some interesting things inside the .ko file: - .gnu.linkonce.this_module: a struct module laid out at build time representing the whole module. - .modinfo: a flat bag of key=value strings. license, vermagic, srcversion, depends, name. - __versions: a CRC per kernel function you call, so a function whose signature changed refuses to load. - The signature, glued on after the ELF ends, which is why no section ever mentions it. One of the thing that help me understand what is happening is to understand that the kernel is playing the role of the linker, it taking a binary with placeholder instead of function addresses, and fill those placeholders with the kernel functions addresses when the module is loaded. Read it here: internals-for-interns.com/po… #Linux #Kernel #Drivers
1
13
1
84
9,750
noCopy is an interesting zero-byte field used in almost every sync struct. But you can still copy the sync struct, it doesn't stop the compiler, it doesn't stop your program from running. So what does it actually do? Here :) func25.dev/posts/go-sync-noc…
2
21
8
300
151,040
Go is faster than Rust: - Low-overhead profilers for memory and CPU are available in every Go program. They help optimizing programs for high performance and low memory usage under production workload. - Typical compile times for Go programs such as VictoriaMetrics are measured in seconds, while typical compile times for Rust programs are measured in minutes.
56
17
7
343
49,836