go

22 posts

cloudflare

Scaling Security Insights: how we achieved a 10x increase in global scanning capacity (opens in new tab)

Security Insights needed a 10x throughput increase to scan all customers more frequently and detect risks sooner. The existing system was overwhelmed by Kafka backlogs, slow processing, database inefficiencies, and API timeouts. Cloudflare improved capacity by introducing parallel and lane-based processing, optimizing bulk database writes, and addressing regional latency between its API and database. ## Scaling Kafka Processing - Scans are scheduled and published to Apache Kafka. - Go-based checker services consume these messages, inspect accounts, zones, and DNS records, and send findings to an internal API. - Kafka’s partition ordering limits each consumer group to one active consumer per partition. - Slow messages could block all subsequent messages in the same partition. - Adding partitions was avoided because it would increase resource usage for shared Kafka brokers. ## Introducing Parallel Processing - Checkers were changed to consume messages in batches. - Each message in a batch is processed concurrently in its own goroutine. - This increased throughput without requiring additional Kafka partitions. - The trade-offs were higher memory usage and potentially more work to repeat after a process crash. ## Separating Slow and Fast Work - Some scans took seconds or milliseconds, while unusually large accounts or zones could take minutes or hours. - These slow messages caused head-of-line blocking for faster work. - Consumer groups and checkers were split into: - A fast lane for predictable, short-running scans - A slow lane for messages expected to require substantially more time - Fast-lane consumers skipped slow messages, allowing normal scans to continue without delay. ## Optimizing Postgres Writes - The API originally executed one insert/upsert transaction per insight. - A request containing up to 500,000 insights could therefore generate hundreds of thousands of database round trips. - Bulk insertion with `COPY` into a temporary table was tested but caused bloat in Postgres system tables. - The final hybrid approach used: - `UNNEST` for smaller batches - `COPY` for batches above a configured threshold - This delivered millisecond-level performance for small writes and completion within seconds for very large writes. ## Diagnosing API Timeouts - Client-side timeouts increased as scan volume grew. - Checkers sometimes spent 20–90% of their processing time waiting on a single API call. - Throughput initially rose but then deteriorated under heavy load. - The root cause was network latency: - Postgres was hosted in Portland, Oregon. - The API ran active-active in Portland and Amsterdam. - Requests routed to Amsterdam incurred roughly 50 milliseconds of network round-trip latency. - Amsterdam database queries held client connection-pool connections much longer—nearly three seconds on average versus about 10 milliseconds in Portland. - The connection pool became exhausted, causing requests to wait for available connections and creating uneven Kafka lag across partitions. Cloudflare’s results came from improving the full processing pipeline rather than relying on a single infrastructure change. Parallelize message handling, isolate slow workloads, batch database writes, and place latency-sensitive services close to their databases to achieve large throughput gains and more frequent security scanning.

github

Dungeons & Desktops: Building a procedurally generated roguelike with GitHub Copilot CLI (opens in new tab)

GitHub Dungeons is a terminal-based roguelike that transforms a repository into a procedurally generated dungeon. Built in Go with GitHub Copilot CLI, it uses the latest commit SHA as a seed, making each commit produce a distinct but reproducible map. The project demonstrates how AI-assisted development can let developers focus more on game design and iteration than on implementation details. ## Repository-Driven Procedural Generation - The game generates rooms, corridors, and enemies from the current codebase. - Each repository produces a structurally different dungeon. - The latest commit determines the random seed: - The same commit always creates the same map. - Code changes reshape the dungeon. - Procedural generation creates replayability by producing many layouts from a single set of rules. ## Roguelike Design - GitHub Dungeons draws on classic games such as *Rogue*. - It combines: - Procedurally generated levels - Permadeath - A text-based terminal interface - Players navigate with arrow keys, fight bugs, collect items, and search for the exit. - When the player’s HP reaches zero, the run ends and they must start over. - The Copilot CLI `/yolo` command, an alias for `/allow-all`, reinforces the game’s one-life theme. ## Building with GitHub Copilot CLI - The author began with a high-level prompt asking Copilot to build a Go-based GitHub CLI extension using BSP-generated dungeons. - The `/delegate` command sent feature requests to Copilot’s cloud-based coding agent. - Copilot worked asynchronously and returned changes through pull requests. - Example delegated work included progressively harder levels with: - More enemies - Additional health potions - The author reviewed and refined Copilot’s output, including cheat codes for invincibility. - Copilot also generated a “dungeon scribe” agent that created documentation and ASCII diagrams explaining dungeon generation. - This workflow allowed the author to concentrate on mechanics, balance, player experience, and easter eggs rather than boilerplate and scaffolding. ## Binary Space Partitioning - Binary Space Partitioning (BSP) generates the dungeon by repeatedly dividing a large area into smaller regions. - The process begins with one rectangle representing the entire map. - That space is recursively split into smaller sections, which can then be used to place rooms and connect them. - BSP suits roguelikes because it balances: - Structure, avoiding chaotic layouts - Replayability through controlled randomness - Navigation, by supporting connected maps - The technique naturally produces clean rectangular rooms while retaining variation between generated levels. GitHub Dungeons shows how repository data, classic roguelike mechanics, and AI-assisted coding can combine into a playful development experiment. Using Copilot as an implementation partner lets the developer iterate quickly while remaining focused on designing an enjoyable game.

figma

PGKeeper: Building the Bouncer We Needed for Postgres | Figma Blog (opens in new tab)

Figma built PGKeeper to replace PgBouncer as its PostgreSQL connection and load-management layer. Growing traffic, sharding, and stricter reliability requirements exposed PgBouncer’s limits in scalability, prioritization, backpressure, connection protection, and extensibility. PGKeeper is a custom Go service positioned between Figma’s DBProxy routing layer and PostgreSQL, designed to protect databases from overload and connection churn. ## Figma’s Database Architecture - PostgreSQL powers Figma’s OLTP workloads. - Figma scales through horizontal and vertical sharding across multiple database instances. - DBProxy hides sharding complexity from application code by: - Parsing and analyzing queries. - Selecting the appropriate PostgreSQL instances. - Rewriting requests into queries for the selected targets. - A dedicated set of connection-pooler replicas serves each PostgreSQL machine, creating an n-to-one relationship between poolers and databases. ## Why PgBouncer Was No Longer Enough - **Limited scalability** - PgBouncer’s single-threaded architecture created a vertical scaling ceiling. - Adding replicas helped, but uneven load distribution caused performance degradation. - **Insufficient load management** - PgBouncer could not prioritize critical traffic over lower-priority or misbehaving requests. - It lacked effective backpressure and advanced load-shedding algorithms such as Controlled Delay (CoDel). - CoDel sheds work based on how long requests wait, rather than simply counting queued requests. - **Unsafe connection behavior** - PostgreSQL connections are expensive resources. - Rapid connection creation and churn could destabilize database nodes. - Recovery after overload could trigger another surge of connections, creating cascading failures and prolonged overload. - **Limited extensibility and control** - Figma needed deep observability, feature-flagged rollouts, admission control, and fair resource sharing. - Even maintaining small PgBouncer patches proved costly. - Extending PgBouncer substantially would create an ongoing maintenance burden. ## Why Connection Pooling Could Not Live in DBProxy - Figma generally limits each PostgreSQL instance to roughly 100 pooled connections. - Hundreds of stateless DBProxy replicas sit in front of those databases. - Giving every DBProxy replica its own pool would either exceed database connection limits or require complex coordination. - Centralizing pooling in a separate service provided a better fit for the mismatch between many routers and a small fixed connection budget. ## Why Figma Built PGKeeper - PGCat addressed PgBouncer’s single-threaded scalability problem, but customizing it would require deep changes to its core execution paths. - Those changes would likely require Figma to maintain a long-term fork. - Figma therefore created PGKeeper as a Go-based service tailored to its infrastructure and operational requirements. - Its role is to act like a goalkeeper: protecting PostgreSQL from harmful traffic and protecting connections from uncontrolled churn. PGKeeper was chosen because Figma needed more than a basic connection pooler: it needed a scalable, observable, controllable layer capable of prioritizing traffic and preventing database overload.

github

How GitHub uses eBPF to improve deployment safety (opens in new tab)

GitHub uses eBPF to prevent deployment scripts from depending on GitHub or other services that may be unavailable during an outage. The approach applies network restrictions only to deployment processes, preserving normal traffic for stateful production hosts. By combining Linux cgroups with eBPF’s `BPF_PROG_TYPE_CGROUP_SKB` hooks, GitHub can detect or block unsafe outbound calls before they create circular deployment dependencies. ## The Deployment Circular Dependency - GitHub hosts its own source code on `github.com`, creating a basic dependency: GitHub may need GitHub to deploy a fix. - GitHub mitigates this with: - A code mirror used for “fix-forward” deployments. - Prebuilt assets used to roll back changes. - Additional circular dependencies can still be introduced by deployment scripts, internal services, or tools that download binaries dynamically. ## Three Types of Circular Dependencies The post uses a hypothetical MySQL outage to illustrate how deployment recovery can fail: - **Direct dependencies** - A deployment script downloads the latest release of an open-source tool from GitHub. - If GitHub cannot serve release data, the deployment cannot complete. - **Hidden dependencies** - A required tool is already installed locally but checks GitHub for updates when it runs. - The tool may fail or hang if that update check cannot connect. - **Transient dependencies** - The deployment calls another internal service, such as a migrations service. - That service then attempts to download a binary from GitHub, causing the failure to propagate back to the deployment. ## Why Manual Review Is Insufficient - Teams responsible for stateful hosts traditionally review deployment scripts for circular dependencies. - Many indirect or unexpected dependencies are discovered only during incidents, when they can delay recovery. - Blocking `github.com` at the host level would be too disruptive because stateful hosts continue serving customer traffic during deploys, drains, and restarts. ## Per-Process Network Filtering with eBPF - eBPF allows custom programs to run inside the Linux kernel and attach to low-level operations such as networking. - GitHub focused on `BPF_PROG_TYPE_CGROUP_SKB`, which can inspect network egress for a specific cgroup. - Linux cgroups provide process grouping, isolation, and resource controls without requiring Docker. - The proposed design: - Create a dedicated cgroup. - Place only the deployment script and its processes inside it. - Restrict or monitor outbound network access for that group. - Leave the host’s ordinary production traffic unaffected. ## Proof of Concept with Go and eBPF - The proof of concept uses Go and the `cilium/ebpf` library. - The library simplifies: - Compiling and loading eBPF programs. - Attaching programs to kernel hooks. - Reading and updating eBPF maps. - The example attaches an egress program to `/sys/fs/cgroup/system.slice`. - An eBPF array map tracks the number of egress packets, while the Go program periodically reads and reports the counter. - The same mechanism can be extended from packet counting to selectively allowing or blocking network traffic. GitHub’s approach moves dependency validation from manual inspection into enforcement at runtime. Restricting only deployment processes with cgroups and eBPF provides a practical way to make emergency deployments independent of services that may be down, without blocking the production workloads sharing the same host.

cloudflare

Cloudflare Email Service: now in public beta. Ready for your agents (opens in new tab)

Cloudflare Email Service is entering public beta as infrastructure for applications and AI agents that use email as a primary interface. It combines inbound Email Routing with outbound Email Sending, allowing agents to receive messages, perform asynchronous work, and reply without relying on separate email providers. Cloudflare argues this enables agents to move beyond instant chatbot responses and operate independently across support, billing, verification, and multi-agent workflows. ## Email as an Agent Interface - Email is universally available and requires no custom chat application or channel-specific SDK. - Developers already depend on email for: - Account signups - Notifications - Invoices - Customer support - Verification workflows - Agents increasingly need email to communicate with users and other systems. ## Cloudflare Email Service - **Email Routing** lets applications and agents receive email. - **Email Sending** enables replies and outbound notifications. - The service integrates with Workers and the Agents SDK. - The public-beta toolkit includes: - An Email Sending binding - An Email MCP server - Wrangler CLI email commands - Skills for coding agents - An open-source agentic inbox reference application ## Email Sending in Public Beta - Workers can send transactional email through a native `env.EMAIL` binding. - The binding requires no API keys or secret management inside the Worker. - Applications can also send email through a REST API or TypeScript, Python, and Go SDKs. - Cloudflare automatically configures SPF, DKIM, and DMARC when a domain is added, improving authentication and inbox delivery. - Since the service runs on Cloudflare’s global network, it is designed for low-latency delivery worldwide. - Combined with long-standing Email Routing, developers can receive, process, and send email within one platform. ## Email-Native Agents with the Agents SDK - The Agents SDK already provides an `onEmail` hook for processing inbound messages. - Previously, agents were limited to synchronous replies or messages sent to Cloudflare account members. - Email Sending removes those limitations, allowing agents to: - Process requests for extended periods - Query multiple systems - Schedule follow-ups - Escalate unusual cases - Reply asynchronously after completing work - This turns an agent from a simple chatbot into a system capable of acting independently. ## Support-Agent Workflow - The example `SupportAgent`: - Receives email through `routeAgentEmail` - Parses the raw message with `PostalMime` - Stores ticket details such as sender, subject, body, and message ID in agent state - Starts longer-running work or sends a task to a Queue - Replies using the Email Sending binding - Preserves the conversation with `inReplyTo` and a `Re:` subject - Address-based routing maps addresses such as `support@domain` or `sales@domain` to corresponding agent instances. Cloudflare’s recommendation is to use Email Service when an agent must communicate reliably with people over email, especially for workflows that require persistence, background processing, and delayed or follow-up responses.

slack

From Custom to Open: Scalable Network Probing and HTTP/3 Readiness with Prometheus (opens in new tab)

Slack needed better client-side observability while migrating edge services to HTTP/3, which uses QUIC over UDP rather than TCP. Existing SaaS tools and Prometheus Blackbox Exporter could not probe HTTP/3 endpoints, so an intern added QUIC support using Go’s `quic-go` library and open-sourced it. The result unified HTTP/1.1, HTTP/2, and HTTP/3 monitoring while making the capability available to the broader Prometheus community. ## Limitations of Legacy Monitoring - Slack used a mix of commercial monitoring services and internal tools for network measurements. - HTTP/3 introduced a major observability gap because it runs over QUIC/UDP. - Existing SaaS solutions lacked built-in HTTP/3 probing. - Prometheus Blackbox Exporter had no native QUIC support. - Without probing at scale, Slack could not reliably measure round-trip times, detect regressions to HTTP/2, or monitor hundreds of thousands of HTTP/3 endpoints. ## Adding QUIC Support to Blackbox Exporter - Intern Sebastian Feliciano selected `quic-go` because of its adoption and first-class Go HTTP client support. - The implementation used an `http3.Transport` with TLS and QUIC configuration: ```go http3Transport := &http3.Transport{ TLSClientConfig: tlsConfig, QUICConfig: &quic.Config{}, } ``` - The new transport was attached to a standard Go `http.Client`. - The implementation preserved Blackbox Exporter’s existing configuration and composability patterns. - Sebastian open-sourced the feature and eventually got it accepted upstream. ## In-House Integration and Operational Benefits - Because upstream review could take longer than the internship timeline, Slack built an internal system around the new functionality. - Grafana now provides a unified view of HTTP/1.1, HTTP/2, and HTTP/3 metrics. - Operators can compare protocol performance and correlate it with other telemetry. - Improved visibility supports more accurate alerts and faster debugging of HTTP/3 issues. ## Future Enhancements - **SNI routing tests:** Verify that shared edge infrastructure routes hostnames to the correct backend and presents the correct TLS certificate. - **End-to-end path visualization:** Map network hops between monitoring agents and endpoints to identify latency spikes or packet loss more precisely. ## Broader Lessons - Observability should be established before a major protocol or infrastructure migration. - Filling gaps through open source can benefit both the organization and the wider engineering community. - Supporting emerging protocols such as QUIC early helps future-proof monitoring systems. Slack recommends trying the new QUIC functionality in Prometheus Blackbox Exporter and contributing to its continued development.

grammarly

Superhuman Go Scales Agent Ecosystem With New Partner Agents From Box, Gamma, and Wayground (opens in new tab)

Superhuman Go expands Grammarly’s workflow assistant with agents that connect enterprise knowledge, create visual content, support learning, and improve communication. These integrations let users work directly from their existing context instead of switching between tools, while keeping tasks such as document reuse, presentation creation, research, and feedback in one workflow. ## Enterprise Knowledge and Workflow Automation - **Box** connects document repositories to Go, allowing users to: - Create Box documents in the appropriate folders. - Search existing files for summaries, extracted information, and reusable knowledge. - Find the latest document versions while keeping Box as the source of truth. - **Common Room** brings buyer intelligence from multiple channels into users’ workflows. - **Fireflies** surfaces meeting summaries, action items, and key decisions to speed up follow-up. - **Parallel** checks facts, recommends citations, and adds real-time data for more credible work. - **Latimer** combines internal search with bias detection to support precise, fair writing. ## Visual Content Creation - **Gamma** turns notes, documents, and meeting recaps into polished, structured presentation decks. - **Napkin AI** converts written content into visual frameworks designed to improve clarity and drive action. ## Interactive Learning - **Wayground** creates quizzes and flashcards from content visible on screen, including emails, documents, slides, and web pages. - **Quizlet** transforms notes, essays, and other written materials into flashcards with a single prompt. - **Speechify** supports listening at speeds up to 4.5 times faster using AI voices designed to improve comprehension. ## Communication, Feedback, and Compliance - **Radical Candor®** helps users handle difficult feedback using Kim Scott’s framework. - **Saifr** assists financial organizations with clear, compliant public communications by detecting regulatory risks and suggesting safer language. ## Building Custom Agents - The Superhuman Agents SDK and MCP client allow organizations to build agents that operate across Go. - The SDK is currently in private beta, with applications available for organizations interested in developing their own agents. Superhuman Go is available to Grammarly users through its Chrome and Edge browser extensions, with Mac and Windows support planned. Together, the integrations position Go as a central workspace for turning existing information into documents, presentations, learning materials, research, and compliant communications without constant tool switching.

cloudflare

Cloudflare outage on February 20, 2026 (opens in new tab)

Cloudflare suffered a 6-hour, 7-minute outage on February 20, 2026, after a software change unintentionally withdrew Internet routes for some Bring Your Own IP (BYOIP) customers. The incident was not related to a cyberattack; a buggy automated cleanup task altered customer prefix and service configurations. Cloudflare reverted the change, restored affected prefixes, and is revising its Addressing API workflows to reduce production risk. ## Customer Impact - Approximately 1,100 of Cloudflare’s 6,500 advertised prefixes were withdrawn between 17:56 and 18:46 UTC. - This affected about 25% of the 4,306 BYOIP prefixes advertised globally. - Impacted applications became unreachable from the Internet and experienced connection failures and timeouts. - Customers initially encountered BGP Path Hunting, where networks repeatedly searched for a route until connections timed out. - The `one.one.one.one` website returned HTTP 403 errors and an “Edge IP Restricted” message. - DNS resolution through the 1.1.1.1 resolver, including DNS over HTTPS, was not affected. - The incident did not affect every BYOIP customer because the configuration change was applied incrementally and was reverted before reaching everyone. ## Recovery Efforts - Engineers detected the issue through failures involving `one.one.one.one` and reverted the change. - Cloudflare published dashboard guidance at 19:19 UTC, allowing many customers to re-advertise their prefixes themselves. - Around 800 prefixes were restored by approximately 20:20 UTC. - About 300 prefixes could not be restored through the dashboard because their service configurations had been removed from edge servers. - Engineers manually restored those remaining prefixes at 23:03 UTC. - Some customers continued to experience latency and failures while addressing configuration state propagated back to the edge. ## The Addressing API - Cloudflare’s Addressing API is the authoritative dataset for IP addresses present on its network. - Changes to the API drive workflows that propagate address and routing updates across Cloudflare’s edge. - The normal process is: - Customers request advertisement or withdrawal through the Addressing API or BGP Control. - The API instructs machines to change prefix advertisements. - Routers update BGP after enough machines receive the change. - Customers bind Cloudflare products to their BYOIP ranges. - Because the API is closely connected to production systems, manual changes are risky. - Cloudflare’s “Code Orange: Fail Small” initiative aims to replace manual Addressing API operations with safer, automated, health-checked workflows. ## Root Cause: Faulty BYOIP Cleanup Automation - The failed change automated the removal of prefixes from BYOIP, a task that had previously been performed manually. - A recurring cleanup sub-task searched for BYOIP prefixes marked for deletion and removed them. - The cleanup task issued the API request: ```go /v1/prefixes?pending_delete ``` - The request contained a bug in how the API query was interpreted. - As a result, the cleanup process unintentionally withdrew customer prefixes and removed related service configurations from some edge servers. - The incident lasted much longer than the initial withdrawal because restoring both advertisements and edge configuration state required extensive automated and manual recovery. Cloudflare’s main corrective direction is to make Addressing API changes safer through incremental, health-mediated deployment, stronger safeguards around automated deletion, and elimination of risky manual production workflows.

datadog

How we reduced the size of our Agent Go binaries by up to 77% (opens in new tab)

The Datadog Agent’s Linux artifact grew from 428 MiB in version 7.16.0 to 1.22 GiB in 7.60.0, creating problems for serverless, IoT, and containerized environments. Rather than remove features, Datadog reduced Go binary sizes by up to 77% between versions 7.60.0 and 7.68.0. The effort combined dependency analysis, targeted code refactoring, and renewed use of Go linker optimizations. ## Why the Agent Became So Large - The Agent supports many operating systems, architectures, distributions, and deployment environments. - Its codebase contains hundreds of dependencies, including cloud SDKs, container runtimes, and security tools. - Build tags and dependency injection determine which features are included in each binary. - The compressed Linux amd64 Debian package grew from 126 MiB to 265 MiB. - Its uncompressed size increased from 428 MiB to 1,248 MiB—a 192% increase over five years. - Go binaries represented a substantial portion of that growth and became the primary optimization target. ## How Go Selects Dependencies - Go compiles required packages individually before the linker combines them into a binary. - Files are included only when they: - Are not test files ending in `_test.go` - Match the current operating system, architecture, and build tags - Satisfy other constraints such as CGO settings, compiler version, or architecture features - Starting from the main package, Go transitively includes imported packages and the runtime required by every Go binary. - Unnecessary dependencies can be excluded by: - Adding a build tag to the file that imports them - Moving dependency-using symbols into a separate package imported only by relevant binaries ## Analyzing Imports and Dependencies - `go list` reveals all packages used for a specific OS, architecture, and set of build tags. - `goda` generates dependency graphs, including indirect imports. - `goda` can also show only the paths leading to a particular target package using its `reach` function. - These tools account for `GOOS`, `GOARCH`, and build constraints, making them useful for examining platform-specific builds. ## Why Package Lists Are Not Enough - A package’s presence does not directly indicate its binary size impact. - The linker removes symbols that are not reachable from the program’s entry points. - The same package can therefore contribute different amounts of code depending on how it is used. - Importing a package can still have significant side effects: - `init` functions execute. - Global variables are initialized. - These behaviors may force otherwise unnecessary symbols to remain in the binary. - Certain uses of reflection can also limit linker optimizations. - Datadog used `go-size-analyzer` to measure the contribution of individual dependencies more accurately than import graphs alone. ## Overall Optimization Strategy - Datadog systematically audited dependencies rather than removing product capabilities. - The work focused on restructuring imports, isolating optional functionality, and restoring linker optimizations that had been disabled or undermined over time. - The resulting improvements brought artifact sizes close to levels from roughly five years earlier. - Some compiler and linker behaviors uncovered during the effort led to improvements benefiting other large Go projects, including Kubernetes. The practical lesson is to treat binary size as an ongoing dependency and architecture concern: analyze actual symbol reachability, isolate optional features behind build constraints or packages, and verify each build variant independently.

dropbox

Inside the feature store powering real-time AI in Dropbox Dash (opens in new tab)

Dropbox Dash’s ranking system depends on a hybrid feature store that can combine real-time user behavior with large-scale historical data. Because Dropbox operates across on-premises and cloud environments, and because each query can trigger thousands of feature lookups, off-the-shelf systems could not meet its latency, scale, and integration requirements. The resulting architecture uses Feast for orchestration, Spark for computation, Dynovault for low-latency storage, and a custom Go serving layer, achieving roughly 25–35 ms p95 latency while keeping features fresh. ## Goals and Requirements - Dash ranks documents, images, and conversations using behavioral, contextual, and real-time signals. - A single query can fan out into thousands of feature lookups across many candidate files. - The feature store needed to: - Support sub-100 ms search latency. - Reflect user actions within seconds or minutes. - Bridge Dropbox’s on-premises services and Spark-based cloud infrastructure. - Handle both streaming-style updates and batch computations. - Let engineers develop features without managing serving and orchestration details. ## Choosing a Hybrid Architecture - Dropbox evaluated Feast, Hopsworks, Featureform, Feathr, Databricks, and Tecton. - Feast was selected because: - It separates feature definitions from infrastructure concerns. - Engineers can focus on PySpark transformations. - Its modular adapter system supports existing Dropbox infrastructure. - Feast’s DynamoDB adapter enabled integration with Dynovault, Dropbox’s DynamoDB-compatible storage system. - The architecture combines: - Feast for orchestration and serving APIs. - Spark jobs for feature computation and ingestion. - Cloud storage for offline indexing and data management. - Dynovault for online, low-latency lookups. - A custom Go service replacing Feast’s Python online serving path. - Dynovault is colocated with inference workloads and provides approximately 20 ms client-side latency. - Monitoring covers job failures, feature freshness, and data lineage. ## Replacing Python with Go for Low Latency - The initial Feast-based Python service struggled under heavy concurrency. - CPU-bound JSON parsing and Python’s Global Interpreter Lock became bottlenecks. - A multi-process design helped temporarily but introduced coordination overhead. - The serving layer was rewritten in Go using: - Lightweight goroutines. - Shared memory. - Faster JSON parsing. - The Go service now handles thousands of requests per second. - It adds only about 5–10 ms beyond Dynovault latency and achieves roughly 25–35 ms p95 latency. ## Keeping Features Fresh - Fresh signals are essential for ranking quality; actions such as opening a document should influence subsequent searches quickly. - Fully real-time computation is impractical for features requiring large joins, aggregations, and historical context. - Dropbox therefore built a three-part ingestion strategy. - Batch ingestion handles complex, high-volume transformations using a medallion architecture. - Intelligent change detection updates only modified records rather than rewriting every feature. - This reduced online-store writes from hundreds of millions to fewer than one million per run and significantly shortened update time. ## Practical Takeaway The system demonstrates that a feature store does not need to be entirely off-the-shelf or entirely real-time. Combining a modular framework with custom serving, colocated storage, batch optimization, and freshness monitoring allowed Dropbox to meet demanding latency and scale requirements while keeping feature development manageable.

datadog

From hand-tuned Go to self-optimizing code: Building BitsEvolve (opens in new tab)

Datadog found that small Go-level optimizations can produce substantial infrastructure savings when applied to heavily used, autoscaled services. Manual work—such as removing bounds checks and prioritizing common input paths—delivered improvements ranging from 25% to over 90% in targeted functions. These successes also revealed the need to automate expert optimization techniques through systems like Datadog’s internal BitsEvolve. ## Finding Hotspots That Matter - Micro-optimizations are worthwhile when: - Functions run millions or billions of times. - Services are aggressively autoscaled, allowing CPU savings to reduce machine counts. - Resource usage drops measurably. - Datadog focused on high-throughput services processing timeseries tags and values. - Individual hotspots sometimes represented only 0.5% of compute, but repeated savings could add up to tens of thousands of dollars annually. - The broader goal was a 5–10% reduction in CPU usage across many improvements. ## Removing Bounds Checks from `NormalizeTag` - `NormalizeTag` called `isNormalizedASCIITag`, a frequently executed validator for ASCII tag strings. - AI coding tools suggested changes that were correct but produced no measurable performance gains. - Examining Go assembly with Compiler Explorer revealed two `runtime.panicBounds` calls per loop iteration. - Restructuring the loop eliminated unnecessary bounds checks and enabled further tuning. - The function became 25% faster, reducing service CPU usage by 0.75% and producing projected annual savings of tens of thousands of dollars. ## Using Observability to Optimize for Real Inputs - `NormalizeTagArbTagValue` handled arbitrary input, including invalid UTF-8 and binary data, and consumed 4.5% of CPU in its processing service. - Production data showed: - Nearly all inputs were ASCII. - UTF-8 appeared in fewer than 3% of cases. - Invalid UTF-8 represented less than 0.01% of inputs. - A fast path optimized for common ASCII data made the function more than 90% faster without reducing correctness or safety. - The change generated projected annual savings of hundreds of thousands of dollars. - The result demonstrated that observability is essential: optimization decisions should reflect actual workloads rather than hypothetical edge cases. ## From Manual Optimization to Automation - Deep performance tuning requires specialized knowledge of profiling, compiler behavior, assembly, and workload analysis. - Although the results can be valuable, the process is time-consuming and difficult to scale across a large organization. - Datadog wanted to move beyond isolated “heroic” optimizations toward a repeatable and automated process. - The manual techniques used by performance engineers became the foundation for heuristics in BitsEvolve, an internal agentic system intended to optimize code systematically. Datadog’s experience suggests that organizations should combine production observability with compiler-level analysis, prioritize high-impact hot paths, and automate proven optimization patterns so performance gains do not depend solely on a small group of experts.

datadog

How we tracked down a Go 1.24 memory regression across hundreds of pods (opens in new tab)

Go 1.24 initially caused an unexpected ~20% increase in memory usage across several services, despite its Swiss Tables implementation being expected to reduce memory consumption. The increase appeared in system-level RSS metrics but not in Go’s runtime metrics or heap profiles. Investigation showed that a runtime allocator refactor likely caused more of the Go heap’s virtual memory to be committed to physical RAM. ## The Unexpected Go 1.24 Memory Increase - The issue emerged during an internal rollout of Go 1.24. - Multiple environments showed approximately 20% higher memory usage. - A staging bisect directly linked the increase to the Go 1.24 upgrade. - The behavior was surprising because Go 1.24’s headline Swiss Tables feature promised lower CPU and memory overhead. ## Ruling Out Swiss Tables and Mutex Changes - Swiss Tables were disabled with: ```bash GOEXPERIMENT=noswissmap ``` - Memory usage did not improve, ruling out the new map implementation as the cause. - The new spin-bit mutex implementation was disabled with: ```bash GOEXPERIMENT=nospinbitmutex ``` - The memory increase remained, eliminating this runtime change as the likely culprit. ## System Metrics vs. Go Runtime Metrics - Go runtime metrics showed almost no change after the upgrade. - System metrics reported a significant increase in resident set size (RSS). - RSS measures physical memory currently used in RAM, while Go’s runtime accounting primarily reflects allocated virtual memory. - This discrepancy matters operationally because systems such as Kubernetes and the Linux OOM Killer rely on physical-memory metrics. ## Examining the Go Heap with `/proc/[pid]/smaps` - Linux’s `/proc/[pid]/smaps` exposed memory usage for individual mappings. - In Go 1.24, the main Go heap mapping had roughly: - 1.28 GiB of virtual memory allocated - 1.26 GiB resident in physical RAM - In Go 1.23, a similarly sized heap mapping had about 300 MiB less RSS than its virtual size. - Other memory regions were not significantly affected, indicating that the increased RSS was isolated to the Go heap. - Upstream changes to label Go-allocated memory regions should make future `maps` and `smaps` investigations easier. ## The Suspected Allocator Regression - The evidence suggested Go 1.24 was not requesting substantially more virtual memory. - Instead, previously uncommitted virtual memory was being committed to physical RAM, increasing RSS without changing Go’s internal memory totals. - A major refactoring of the runtime’s `mallocgc` function stood out in the Go 1.24 changelog. - The investigation therefore focused on this allocator change as the likely source of the regression. Go 1.24’s memory increase was caused not by Swiss Tables or mutex changes, but likely by altered heap allocation behavior in the runtime. Comparing RSS with Go’s runtime metrics—and inspecting `/proc/[pid]/smaps`—was essential for identifying the allocator-related discrepancy.

datadog

How Go 1.24's Swiss Tables saved us hundreds of gigabytes | Datadog (opens in new tab)

Datadog’s article explains how Swiss Tables provide a faster and more memory-efficient hash-table design for Go. The approach replaces traditional bucket-based lookup with compact control metadata and group probing, allowing the runtime to reject non-matching entries quickly. The article concludes that Swiss Tables can improve map performance and memory usage, while requiring careful attention to compatibility, implementation complexity, and workload-specific benchmarking. ## Why Traditional Go Maps Have Limitations - Conventional hash tables organize entries into buckets and may require several memory accesses during lookup. - As maps grow, collisions and overflow buckets can increase lookup costs. - Pointer-heavy layouts also add memory overhead and reduce cache locality. - These costs matter for Datadog workloads that maintain large numbers of maps containing metrics, tags, and other high-cardinality data. ## How Swiss Tables Work - Swiss Tables store compact metadata alongside groups of key-value slots. - Each entry’s hash is divided into: - A portion used to select the initial table location. - A short fingerprint stored in control metadata. - Lookups compare fingerprints across multiple slots before examining full keys. - Empty and deleted markers in the metadata make it possible to skip large portions of the table quickly. - Group-oriented probing improves cache locality and reduces the number of key comparisons. ## Adapting the Design to Go - A Go implementation must account for Go-specific features such as: - Garbage collection. - Generic types. - Interface and pointer representations. - Map growth and deletion semantics. - The implementation needs to preserve expected Go map behavior while changing the underlying storage strategy. - Careful handling of memory layout is essential because metadata, keys, values, and garbage-collector scanning all affect performance. ## Performance and Memory Trade-offs - Swiss Tables can reduce memory overhead by storing compact fingerprints instead of repeatedly examining full keys. - Better locality can improve lookup and insertion speed, particularly for large maps. - Results depend on factors such as: - Map size. - Key and value types. - Read/write ratios. - Collision rates. - Frequency of growth and deletion. - Benchmarks are therefore necessary before replacing an existing map implementation in production. ## Practical Lessons - Data-structure improvements should be evaluated against real application workloads, not only synthetic benchmarks. - Memory layout and garbage-collector behavior can be as important as algorithmic complexity. - Swiss Tables are a promising foundation for efficient Go maps, but their advantages must be balanced against implementation complexity and compatibility requirements. Datadog’s recommendation is to use Swiss Table techniques where map performance or memory usage is a meaningful bottleneck, and to validate the change with representative benchmarks and production measurements.

datadog

How Go 1.24's Swiss Tables saved us hundreds of gigabytes (opens in new tab)

Go 1.24 initially caused a Go runtime regression that increased RSS across Datadog services, but some high-traffic workloads ultimately used substantially less memory. The reduction came from Go 1.24’s Swiss Tables map implementation, which made a large, mostly read-only routing cache more compact. Profiling also revealed opportunities to reduce memory further by removing redundant data from the cached values. ## The Unexpected Memory Reduction - Datadog observed roughly **500 MiB less live heap** in the `shardRoutingCache` map after upgrading to Go 1.24. - With `GOGC=100`, that translated to approximately **1 GiB less total memory usage**. - Even after accounting for an expected **400 MiB RSS increase** from the `mallocgc` regression, the service achieved a net reduction of about **600 MiB**. - The improvement was most visible in high-traffic environments because they contained larger routing caches. ## The `shardRoutingCache` Data Structure - The cache maps routing keys to shard information: ```go map[string]Response ``` - Each `Response` contains: - `ShardID int32` - `ShardType` - `RoutingKey string` - `LastModified *time.Time` - The map is populated mainly during service startup by querying a database. - It is rarely modified afterward, making its memory layout and initial allocation particularly important. - The routing key is stored both as the map key and again inside the value, creating potential redundancy. ## Estimating Memory per Entry - On a 64-bit system, a map key’s string header occupies **16 bytes**. - The value requires approximately: - 4 bytes for `ShardID` - 8 bytes for `ShardType` - 16 bytes for the `RoutingKey` string header - 8 bytes for the `LastModified` pointer - The value totals 36 bytes before alignment, or roughly **40 bytes with padding**. - Including the key header, each key-value pair requires about **56 bytes**, excluding the separately allocated string and `time.Time` data. ## Go 1.23 Bucket-Based Maps - Go 1.23 maps used hash tables organized into an array of buckets. - The number of buckets was always a power of two, and each bucket contained **eight slots**. - Reads and writes required scanning the slots in the selected bucket to find a matching key or an empty position. - When a bucket filled, Go added linked overflow buckets, which increased memory usage and made lookups more expensive. - Map growth occurred when the average load factor exceeded **13/16, or 6.5 of 8 slots**. - The map then allocated twice as many buckets. - To avoid a large latency spike, growth was incremental: old and new bucket arrays coexisted while entries were gradually moved during subsequent writes. ## Why Workload Shape Matters - The routing cache is populated in a startup-heavy phase and then primarily read. - Such a workload benefits from a compact map representation because it does not need frequent insertions or growth. - Differences in cache size and traffic patterns explain why the memory improvement was significant in some environments but not uniform across the fleet. Go 1.24’s Swiss Tables implementation can substantially reduce memory usage for large, stable maps, even when another runtime change causes RSS growth. Teams should profile real production heaps after Go upgrades and inspect large structs for duplicated strings, unnecessary pointers, and other avoidable per-entry overhead.