One of my projects required speed (as most should), the most piece intensive being redirects, and while it could deliver I couldn’t transition 100%.
Gin Gonic came out based off the popularity of the Martini framework, boosting some nice graphs of impressive stats saying it’s close to Martini, which you can see I have written about extensively. I briefly drank the juice of fearing Martini may not be able to scale when push came to shove because it’s “slow” compared to other frameworks, and looked down upon by many developers, I decided to give Gin a shot since it included some middleware that would ease the process (templating, redirects, binding) of transitioning over quickly.
One of the first issues I ran into right away was when you are creating your application, by default it’s in a “debug” environment which is fine, but there’s a massive bug where templating does not work correctly. It’s a documented bug with a fix in place, but even after running
go get -u it didn’t seem to work for me. The only way I was able to get templates to work where it could fetch all of the files and place them in a cache was to run the application in production mode while developing. This wasn’t a huge deal, I just had to make sure my environment variable was set and I lost some routes debugging, but in general it wasn’t a deal breaker.
The deal breaker that made me revert back was ultimately not the fault of Gin, but the fault of httprouter which is how I decided to use Gin in the first place because of it’s performance stats. To get performance, httprouter unfortunately does not support regex patterns in it’s URL structure. So something such as:
Which can take a URL such as www.example.tld/keyname.js and translate the
keyname into a parameter I can search in a database or do what I want to output a rendered JS file on the fly. This is something I’ve done when I used to use PHP and was able to set up routes easily with any framework I used previously along with Apache/Nginx, but httprouter doesn’t support anything close to getting a route like that (if I am wrong, please let me know).
There are a few things I could have done to get around this issue, which I didn’t. For example:
/js/:keynameand been done with it, but these script filenames are in production.
This application is hosted on Heroku, and since I’m using more than one dyno I have some nice stats in front of me so I was able to see the performance of gin vs martini when I had deployed the code. Unfortunately as you may have guessed, I deployed this bug with the bad router to production and it went unnoticed for a few hours. It was a curse, but also a blessing since I was able to get a real-world comparison of Gin vs. Martini.
A lot of the application is cached behind a CDN, for the most part the only thing that isn’t cached are the server-side redirects so we can direct the flow of incoming traffic. Heroku shows that we were receiving an average of 6k req/min. In that time, the CPU load dropped a bit when we launched with Gin. Go is pretty efficient for a few reasons and on average Gin showed a .2 CPU load median while Martini did show about a .25-.3 CPU load median.
The request timeout with Gin was 2ms median, and was 4ms median with Martini. That number is suspiciously low, so I have a feeling it’s the time that it takes Heroku’s router to talk to the application and receive a response, not a true representation of the browser response time. You could see it as the response doubled, but the response time is so low to begin with I’m not going to invest hours in a project that doesn’t call for a 2ms performance gain unless there is a huge gain in profit because of those 2ms.
Interestingly enough, according to Heroku Gin did consume more memory, a 24 MB footprint compared to Martini with a 13 MB footprint. The only parts of the code that were changed were necessary to support Gin, but none of the logic of saving to an in-memory cache of saving to the database had changed.
I should have known up front that Gin wasn’t quite ready for primetime, as on the github readme.md it explains what needs to be done to reach a v1 release, but I figured I’d give it a shot. Unfortunately, the router issue is most likely not going to be fixed by the Gin team because it’s not really an issue or bug, but it’s a feature of httprouter.
If I am to try this again, and I probably will when I have another 2 hours to spare, I will probably try Negroni with Gorilla Mux since Negroni was created by the same developer of Martini, and I’ve had experience with the Gorilla libraries before and am a previous fan.
UPDATE: I updated the code to use negroni/mux, took about an hour. I will write a follow-up oncen I get some performance data
Last Updated: 2015-01-16 00:46:44 +0000 UTC
What are your thoughts on this?