Learn how we leveraged Go alongside Laravel using Unix socket RPC communication to handle performance-critical operations and protect proprietary algorithms through compiled binaries.February 13, 2025

Supercharging Laravel with Go: Building a Hybrid Architecture

Learn how we leveraged Go alongside Laravel using Unix socket RPC communication to handle performance-critical operations and protect proprietary algorithms through compiled binaries.

I've been working with polyglot architectures a lot lately, specifically mixing Laravel with Go services. It's a combination that's been working incredibly well for us, as it lets us leverage Laravel's rich ecosystem while tapping into Go's performance benefits and compilation advantages.

Let's dive into how we've structured this hybrid approach and some of the interesting challenges we've solved along the way...

Why Mix Laravel and Go?

When you're working on a PHP application handling high-volume computational operations or processing massive datasets, there might come a point where you need to explore other options to meet your performance requirements. This is especially true for established applications that have scaled significantly over time and now process millions of records or serve thousands of concurrent users. For us, there were two main drivers:

  1. Performance Critical Operations: Some computationally-intensive operations just run faster in Go. While Laravel is fantastic for building feature-rich applications, Go's performance characteristics make it the better choice for certain types of heavy lifting. For Geocodio, part of that heavy lifting entails serving billions of requests, we're averaging 17 billion requests every 30 days.

  2. Compiled Binaries: When you need to ship your application for on-premise installations, being able to distribute pre-compiled binaries is super valuable. Among other reasons, it helps keep your proprietary algorithms and buisienss logic secure. Go makes this pretty straightfoward.

The Communication Layer

One of the most interesting parts of our setup is how we handle communication between Laravel and Go. Rather than using HTTP or shell commands, we opted for Unix socket communication using RPC. This gives us near-native performance for inter-process communication.

Here's how we set up the Laravel side:

class GoService { private static ?RPC $rpc = null; private const SOCKET_PATH = '/run/app/service.sock'; public function __construct() { if (!self::$rpc) { self::$rpc = new RPC( Relay::create('unix://'.self::SOCKET_PATH) ); } } public function call(string $method, $args, $defaultValue = null) { try { $fullMethod = 'Service.'.$method; return self::$rpc->call($fullMethod, $args) ?? $defaultValue; } catch (Exception $e) { Log::error('Go service call failed', [ 'method' => $method, 'error' => $e->getMessage() ]); return $defaultValue; } } }

Then we can wrap specific functionality in dedicated classes:

class ComputeService { private $service; public function __construct(GoService $service) { $this->service = $service; } public function processData(array $data): array { return $this->service->call('processData', $data, []); } }

On the Go side, we set up an RPC server that listens on the Unix socket:

type Service struct{} func (s *Service) ProcessData(args []interface{}, result *[]interface{}) error { // Process data here return nil } func main() { service := new(Service) listener, err := net.Listen("unix", "/run/app/service.sock") if err != nil { log.Fatal(err) } // Ensure correct permissions err = os.Chmod("/run/app/service.sock", 0777) if err != nil { log.Fatal(err) } // Handle shutdown gracefully c := make(chan os.Signal) signal.Notify(c, os.Interrupt, syscall.SIGTERM) go func() { <-c listener.Close() os.Exit(0) }() rpc.Register(service) for { conn, err := listener.Accept() if err != nil { continue } go rpc.ServeCodec(goridge.NewCodec(conn)) } }

Error Handling and Reliability

One challenge with this architecture is handling failure cases gracefully, which is especially critical for an application running on customer installations. If there's a connection issue between Laravel and Go or if the Go service crashes, we need to ensure the main application continues functioning while attempting to recover the connection. For on-premise deployments, these failures need to be handled automatically since there's no DevOps team standing by to intervene. Here's how we approach it:

class GoService { private $retries = 3; private $backoff = 100; // ms public function callWithRetry(string $method, $args) { $attempt = 0; while ($attempt < $this->retries) { try { return $this->call($method, $args); } catch (ConnectionException $e) { $attempt++; if ($attempt === $this->retries) { throw $e; } usleep($this->backoff * 1000 * $attempt); } } } }

Performance Benefits

The Unix socket communication adds minimal overhead - we're talking microseconds. This means we get to take full advantage of Go's performance characteristics. In our production environment, we've seen operations that were taking hundreds of milliseconds in PHP complete in under 50ms with Go.

Some tips for optimizing performance:

  • Keep the data passed between services as small as possible
  • Use batch operations when processing multiple items
  • Cache results when appropriate

Monitoring and Debugging

Debugging distributed systems can be tricky. We've added some tooling to make it easier:

func (s *Service) call(method string, args interface{}) { start := time.Now() // Execute method duration := time.Since(start) metrics.Timing("go_service."+method, duration) if duration > time.Second { log.Printf("Slow call to %s: %s", method, duration) } }

What's Next

I'm super stoked about how this architecture has been working out. We're looking at expanding our Go services to handle more compute-intensive operations and improving our development tooling.

Big thanks to the Spiral Project team for their Goridge library, which made the RPC communication super easy to set up.

Note: The code examples in this article are simplified versions of our production code, but they illustrate the core concepts we're using.

Additional Resources

Subscribe to Code and Coordinates

Get the latest articles about software development, data science, and geospatial technology

Copyright © 2014-2025 Dotsquare LLC, Norfolk, Virginia. All rights reserved.