Netflix / fast_jsonapi

No Longer Maintained - A lightning fast JSON:API serializer for Ruby Objects.
Apache License 2.0
5.07k stars 425 forks source link

Performance is not as expected, what I'm doing wrong? #348

Open luismiv85 opened 5 years ago

luismiv85 commented 5 years ago

Hi everyone! First of all, thanks for your contribution to Rails community. You guys are amazing.

We have an application in production and we have some problems with AMS performance. I'm checking fast_jsonapi to solve this :). I'm testing in my personal project to check the performance about FJA over AMS, but unfortunately I didn't find what I was expecting :( . Maybe I am doing my performance tests in a bad way and you can help me. Here is my benchmark:

Here are my serializers (ASM and FJA)

ASM:

class V1::ReservationSerializer < ActiveModel::Serializer
  attributes :id, :building_id, :reference, :start_date, :end_date,
    :normal_price, :total_price, :status, :createable_id, :createable_type,
    :comment, :accepted_conditions, :channel_id, :discount, :admin_price, :rest,
    :booking_reference, :process, :coupon_id, :discount_id, :reservation_condition_id,
    :childs, :adults, :client_comments, :created_at, :updated_at
end

FJA:

class V2::ReservationSerializer
  include FastJsonapi::ObjectSerializer
  attributes :id, :building_id, :reference, :start_date, :end_date,
    :normal_price, :total_price, :status, :createable_id, :createable_type,
    :comment, :accepted_conditions, :channel_id, :discount, :admin_price, :rest,
    :booking_reference, :process, :coupon_id, :discount_id, :reservation_condition_id,
    :childs, :adults, :client_comments, :created_at, :updated_at
end

BENCHMARKS

With Benchmark ips:

n = 1000
reservations = Reservation.actives.limit(n)
Benchmark.ips do |x|
  x.time = 1
  x.report('ASM'){
    json1 = ActiveModel::Serializer::CollectionSerializer.new(
              reservations, 
              serializer: ActiveModel::Serializer::V1::ReservationSerializer
            )
  }

  x.report('FJA') {
    json2 = ::V2::ReservationSerializer.new(reservations).serialized_json
  }

  x.compare!
end
Calculating -------------------------------------
                 ASM     14.096  (± 0.0%) i/s -     15.000  in   1.065103s
                 FJA      4.048  (± 0.0%) i/s -      5.000  in   1.246974s

Comparison:
                 ASM:       14.1 i/s
                 FJA:        4.0 i/s - 3.48x  slower

With Benchmark measure:

[1, 25, 250, 1000, 5000].each do |reservations_count|
  reservations = Reservation.actives.limit(reservations_count)
  time_ams = Benchmark.measure {
    json1 = ActiveModel::Serializer::CollectionSerializer.new(reservations, serializer: ActiveModel::Serializer::V1::ReservationSerializer)
  }.real * 1000

  time_fastjson = Benchmark.measure {
    json2 = ::V2::ReservationSerializer.new(reservations).serialized_json
  }.real * 1000

  Rails.logger.info("Size collection #{reservations_count}: AMS -> #{time_ams}")
  Rails.logger.info("Size collection #{reservations_count}: FJA -> #{time_fastjson}")
end

Results:

Size collection 1: AMS -> 1.6655579674988985
Size collection 1: FJA -> 0.6660670042037964

Size collection 25: AMS -> 7.491803960874677
Size collection 25: FJA -> 9.159923996776342

Size collection 250: AMS -> 69.97357797808945
Size collection 250: FJA -> 75.90831100242212

Size collection 1000: AMS -> 257.1048479876481
Size collection 1000: FJA -> 317.56329600466415

Size collection 5000: AMS -> 1393.7372969812714
Size collection 5000: FJA -> 1847.1652650041506

Is anything wrong here? Thanks for helping the community, Cheers!

Charizard commented 5 years ago

@luismiv85 In both the AMS serialization, I believe you should do a .as_json at the end else this would just instantiate the object and obviously be faster.

luismiv85 commented 5 years ago

@Charizard I don't understand what you mean. In both case (json1 and json2) return a json. I think is not necessary .as_json after use AMS. ¿Am I missing anything?

davidcelis commented 5 years ago

@luismiv85 You definitely need to call something like .as_json or .serializable_hash against the ActiveModel serializer… The only thing you're doing right now is initializing an instance of the serializer itself. No serialization is happening