My life is full of things to care of: university, job, GDG, a girlfriend..
But in some way I always find something new to do and to spend time on.

With a friend we’re trying to build up a website dedicated to small and medium businesses, but that is another story. What I want to write about today is a small, but important feature I’m adding to our web server.

Lately I’ve found Go to be a really good language: fast, good learning curve, low level but higher than C with comparable performances. And moreover It’s thought to make fast and scalable web servers. So, why don’t use it to craft something new and that (hopefully) will need this specs?

I decided to give a chance to the Gin Gonic framework! It’s really good, quick and overall handy even to a newbie of web programming.
It’s nice how Go and Gin gonic make you able to build custom middlewares and to use it in a modular way.

So what? I made a custom middleware!

A problem that fascinates me is the ability to limit the number of requests coming from a single IP address (eg: 100 reqs per hour), but how to do that?

I thought about using something that permits me to have a distinct counter for each IP address, but independent on the Golang code base. Redis! A good use case for such a great tool. But I had never used it and I didn’t know a lot about its complex and powerful data structures.

What I did was a simple rate limiter using the IP address as a key and the counter as the value, setting the expire timer to 1 minute every time I received a call and checking if the counter had exceeded the limit.

Redis client: https://github.com/go-redis/redis

Simple, powerful, but with some drawbacks.

For example, 100 reqs per hour.

What if the user makes 1 request every 59 seconds? After one 1 hour he would get a 429 (too many requests) message.
I could also modify the code in order to set the expire only if the key does not exists and to only increment it. But in that case one could just make a request, wait for 59 seconds and dispatch 99 requests. Then the key expires and he could make 100 requests in a second. It would be possible to guarantee a maximum of 199 reqs per hour and not 100 as our aim.

What I needed was a sliding window technique.

Sliding window example

I searched on the web for something that could help me, but everything I found was just some middleware limiting the global number of requests without the sliding window, but maybe It’s not so clever.
Until I came across this article:

Building a sliding window rate limiter with Redis

It was what I wanted. A sliding window rate limiter with the ability to block the user with error 429 only if it breaks the threshold in the last minute of activity. Perfect.

It uses Redis sorted set data structure in order to store the timestamp of every request, throwing away the ones older than 1 minute with the powerful ZREMRANGEBYSCORE Redis command and using the remaining number of entries to make the check.

My Go implementation of the algorithm

Great! It works and it does very well. I’m curious to see how it will behave with large amount of reqs/sec, that could be a nice challenge.

What to do now? I have my middleware, I can use it wherever I want, It’s pluggable within every path that needs it, also with different limits. But remember that I couldn’t find this implementation before.

So I published it on Github. You can find it also on the Gin-contrib repo.
I like sharing code, and Go is a great shareable language.

Just run go get -u github.com/Salvatore-Giordano/gin-redis-ip-limiter/ to install the package and use it.

Recommendation are accepted and strongly desired. I will post something if I found a better way to accomplish this task or if the web server blows up for too many requests in the future, stay tuned.

Bye, a presto!

💻 Flutter developer @ GetStream • Software engineering student @ PoliTo • Technology enthusiast • https://imtoori.dev/

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store