Arsitektur Pluggable
Tukar antara Token Bucket, Leaky Bucket, Fixed Window, Sliding Window Log, dan Sliding Window Counter secara fleksibel tanpa mengubah storage driver Anda.

distlimit?Sebagian besar rate limiter memaksakan satu algoritma saja atau mengunci global mutex saat pembersihan latar belakang. distlimit mengatasi kelemahan ini dengan ketahanan tingkat enterprise:
Arsitektur Pluggable
Tukar antara Token Bucket, Leaky Bucket, Fixed Window, Sliding Window Log, dan Sliding Window Counter secara fleksibel tanpa mengubah storage driver Anda.
Engine Zero Allocation
Evaluasi memori berjalan sub-100 nanodetik dengan overhead 0 B/op untuk sepenuhnya menghilangkan jeda Go Garbage Collection pada beban tinggi.
Half-Open Circuit Breaker
Driver Hybrid dua tingkat menggunakan pola atomic single-request probing untuk mencegah lonjakan Thundering Herd ke Redis saat pemulihan sistem.
Pelindung Anti-IP Spoofing
Inspeksi WithTrustedProxies ber-validasi CIDR melindungi API Anda dari pemalsuan header X-Forwarded-For dan X-Real-IP.
Aman untuk Redis Cluster
Menerapkan format Redis Hash Tags {} (distlimit:{key}) secara bawaan untuk mencegah error routing CROSSSLOT pada cluster Redis.
Observabilitas Bawaan
Dukungan bawaan untuk metrik Prometheus dan observer tracing OpenTelemetry tanpa penalti performa saat dinonaktifkan.
Install library via Go Modules:
go get github.com/balramadan/distlimitInisialisasi dan lindungi aplikasi Anda:
package main
import ( "context" "fmt" "time"
"github.com/balramadan/distlimit" "github.com/balramadan/distlimit/algorithm/slidingcounter" "github.com/balramadan/distlimit/driver/memory")
func main() { // Inisialisasi Memory Driver 64-Shard (TTL 5 menit) memDriver := memory.New(5 * time.Minute) defer func() { _ = memDriver.Close(context.Background()) }()
// Buat Limiter: 10 request per 1 menit menggunakan Sliding Window Counter limiter, _ := distlimit.New( memDriver, distlimit.WithLimit(10), distlimit.WithWindow(1*time.Minute), distlimit.WithAlgorithm(slidingcounter.New()), )
// Evaluasi Rate Limit untuk sebuah key res, _ := limiter.AllowKey(context.Background(), "user:123")
if res.Allowed { fmt.Printf("Diizinkan! Sisa kuota: %d\n", res.Remaining) } else { fmt.Printf("Ditolak! Coba lagi setelah: %v\n", res.ResetIn) }}Integrasikan distlimit ke dalam framework web Go favorit Anda tanpa boilerplate code:
package main
import ( "time"
"github.com/balramadan/distlimit" "github.com/balramadan/distlimit/algorithm/tokenbucket" "github.com/balramadan/distlimit/driver/memory" distlimitfiber "github.com/balramadan/distlimit/middleware/fiber" "github.com/gofiber/fiber/v3")
func main() { memDriver := memory.New(5 * time.Minute) limiter, _ := distlimit.New(memDriver, distlimit.WithLimit(100), distlimit.WithWindow(1*time.Minute), distlimit.WithAlgorithm(tokenbucket.New()))
app := fiber.New()
// Middleware aman dengan pemeriksaan CIDR Trusted Proxy app.Use(distlimitfiber.New( limiter, distlimitfiber.WithTrustedProxies([]string{"10.0.0.0/8"}), ))
app.Get("/api/ping", func(c fiber.Ctx) error { return c.SendString("pong") })
app.Listen(":3000")}package main
import ( "time"
"github.com/balramadan/distlimit" "github.com/balramadan/distlimit/algorithm/tokenbucket" "github.com/balramadan/distlimit/driver/memory" distlimitgin "github.com/balramadan/distlimit/middleware/gin" "github.com/gin-gonic/gin")
func main() { memDriver := memory.New(5 * time.Minute) limiter, _ := distlimit.New(memDriver, distlimit.WithLimit(100), distlimit.WithWindow(1*time.Minute), distlimit.WithAlgorithm(tokenbucket.New()))
r := gin.Default() r.Use(distlimitgin.New(limiter))
r.GET("/api/ping", func(c *gin.Context) { c.JSON(200, gin.H{"message": "pong"}) })
r.Run(":8080")}package main
import ( "time"
"github.com/balramadan/distlimit" "github.com/balramadan/distlimit/algorithm/tokenbucket" "github.com/balramadan/distlimit/driver/memory" distlimitecho "github.com/balramadan/distlimit/middleware/echo" "github.com/labstack/echo/v4")
func main() { memDriver := memory.New(5 * time.Minute) limiter, _ := distlimit.New(memDriver, distlimit.WithLimit(100), distlimit.WithWindow(1*time.Minute), distlimit.WithAlgorithm(tokenbucket.New()))
e := echo.New() e.Use(distlimitecho.New(limiter))
e.GET("/api/ping", func(c echo.Context) error { return c.String(200, "pong") })
e.Logger.Fatal(e.Start(":8080"))}package main
import ( "net/http" "time"
"github.com/balramadan/distlimit" "github.com/balramadan/distlimit/algorithm/tokenbucket" "github.com/balramadan/distlimit/driver/memory" distlimithttp "github.com/balramadan/distlimit/middleware/nethttp")
func main() { memDriver := memory.New(5 * time.Minute) limiter, _ := distlimit.New(memDriver, distlimit.WithLimit(100), distlimit.WithWindow(1*time.Minute), distlimit.WithAlgorithm(tokenbucket.New()))
mux := http.NewServeMux() mux.HandleFunc("/api/ping", func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte("pong")) })
protectedHandler := distlimithttp.New(limiter)(mux) _ = http.ListenAndServe(":8080", protectedHandler)}package main
import ( "net" "time"
"github.com/balramadan/distlimit" "github.com/balramadan/distlimit/algorithm/tokenbucket" "github.com/balramadan/distlimit/driver/memory" distlimitgrpc "github.com/balramadan/distlimit/middleware/grpc" "google.golang.org/grpc")
func main() { memDriver := memory.New(5 * time.Minute) limiter, _ := distlimit.New(memDriver, distlimit.WithLimit(100), distlimit.WithWindow(1*time.Minute), distlimit.WithAlgorithm(tokenbucket.New()))
server := grpc.NewServer( grpc.UnaryInterceptor(distlimitgrpc.UnaryServerInterceptor(limiter)), grpc.StreamInterceptor(distlimitgrpc.StreamServerInterceptor(limiter)), )
lis, _ := net.Listen("tcp", ":50051") _ = server.Serve(lis)}