Knuckles (Because Sonic was Taken)
Knuckles is a performance focused data serialization pipeline. More simply, it tries to serialize models into large JSON payloads as quickly as possible.
What's it all about?
- Emphasis on caching as a composable operation
- Reduced object instantiation
- Complete instrumentation of every discrete operation
- Entirely agnostic, can be dropped into any project and integrated over time
- Minimal runtime dependencies
- Explicit serializer view API with as little overhead and no DSL
Is It Better?
Knuckles is absolutely faster and has a lower memory overhead than uncached
or cached usage of ActiveModelSerializers, and significantly faster than
cached use of ActiveModelSerializers with the perforated gem.
Here are performance and memory comparisons for an endpoint that has been cached with Perforated and with Knuckles. All measurments were done with production settings over the local network.
| average | longest | shortest | allocated | retained | |
|---|---|---|---|---|---|
| perforated/ams | 230ms | 560ms | 190ms | 148,735 | 18,203 |
| knuckles/ams | 30ms | 60ms | 20ms | 19,603 | 136 |
These are measurements for a sizable payload with hundreds of associated records.
Installation
Add this line to your application's Gemfile:
gem "knuckles"
Configuration
There isn't a hard dependency on Oj or Readthis, but you'll find they are
drastically more performant.
require "activesupport"
require "oj"
require "readthis"
Knuckles.configure do |config|
config.cache = Readthis::Cache.new(
marshal: Oj,
compress: true,
driver: :hiredis
)
config.keygen = Readthis::Expanders
config.serializer = Oj
end
With the top level module configured it is simple to jump right into rendering, but we'll look at configuring the pipeline first.
Defining Views for Rendering
While you can use Knuckles with other serializers, you can also use the provided view layer. Knuckles views are simple templates that let you build up data and relations. They look like this:
module ScoutView
extend Knuckles::View
def self.root
:scouts
end
def self.data(object, )
{id: object.id, email: object.email, name: object.name}
end
def self.relations(object, )
{things: has_many(object.things, ThingView)}
end
end
See Knuckles::View for more usage details.
Contributing
- Fork it ( https://github.com/sorentwo/knuckles/fork )
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create a new Pull Request