Performance Testing Rails Applications

1. Mở đầu

Đối với 1 dự án thì việc đảm bảo những yêu cầu khách hàng là rất quan trọng nhưng vấn đề đảm bảo performance khi lượng người truy cập tăng lên hay lượng database records tăng lên cũng quan trọng không kém.

Ngoài RSpec test hôm nay mình xin giới thiệu thêm 1 công cụ để test performance cho rails application.

rails-perftest là 1 gem được thiết kế để test xem vấn đề về memory (sử dụng nhiều bộ nhớ) và tốc độ (sử dụng nhiều CPU) đến từ đâu và có 1 bức tranh toàn cảnh của toàn bộ vấn đề.

2. Cài đặt

gem 'rails-perftest'
gem 'ruby-prof'

và tất nhiên là bundle install

3. Cách sử dụng

Test home_page

rails generate performance_test homepage

lệnh này sẽ tạo ra file homepage_test.rb trong thư mục test/performance

require 'test_helper'
require 'rails/performance_test_help'

class HomepageTest < ActionDispatch::PerformanceTest
  # Refer to the documentation for all available options
  # self.profile_options = { runs: 5, metrics: [:wall_time, :memory],
  #                          output: 'tmp/performance', formats: [:flat] }

  test "homepage" do
    get '/'
  end
end

Hãy giả sư như ta có 1 app như sau

# routes.rb
root to: 'home#dashboard'
resources :posts

# home_controller.rb
class HomeController < ApplicationController
  def dashboard
    @users = User.last_ten.includes(:avatars)
    @posts = Post.all_today
  end
end

# posts_controller.rb
class PostsController < ApplicationController
  def create
    @post = Post.create(params[:post])
    redirect_to(@post)
  end
end

# post.rb
class Post < ActiveRecord::Base
  before_save :recalculate_costly_stats

  def slow_method
    # I fire gallzilion queries sleeping all around
  end

  private

  def recalculate_costly_stats
    # CPU heavy calculations
  end
end

Test controller HomeController#dashboard và PostsController#create

require 'test_helper'
require 'rails/performance_test_help'

class PostPerformanceTest < ActionDispatch::PerformanceTest
  def setup
    # Application requires logged-in user
    login_as(:lifo)
  end

  test "homepage" do
    get '/dashboard'
  end

  test "creating new post" do
    post '/posts', post: { body: 'lifo is fooling you' }
  end
end

test model

require 'test_helper'
require 'rails/performance_test_help'

class PostModelTest < ActionDispatch::PerformanceTest
  test "creation" do
    Post.create body: 'still fooling you', cost: '100'
  end

  test "slow method" do
    # Using posts(:awesome) fixture
    posts(:awesome).slow_method
  end
end

4. Kiểm định kết quả

rake test:benchmark
hoặc để test riêng 1 file
bin/rake test:benchmark TEST=test/performance/homepage_test.rb

Kết quả như sau:

BrowsingTest#test_homepage (58 ms warmup)
        process_time: 63 ms
              memory: 832.13 KB
             objects: 7,882

Wall Time là thời gian thực tế chạy test, nó ảnh hưởng bởi tốc độ của code đã viết và cả bởi trạng thái CPU (Sẽ tùy vào từng tình huống mà ra kết quả khác nhau) Process Time là thời gian mà CPU phải xứ lý code và không phụ thuộc vào trạng thái CPU. Có thể nói đây là thông số để đo tốc độ code CPU Time tương tự như Process Time nhưng chính xác hơn 1 chút User Time là thời gian CPU hoạt động trong chế độ user-mode, không bị ảnh hưởng bới tiến trình khác, không tính thời gian bị blocked. Memory lượng bộ nhớ được sử dụng Objects số object được tạo ra GC Runs số lần GC được gọi (Garbage collection, số lần bộ dọn bộ nhớ của hệ thống được goi) GC Time thời gian bỏ ra để GC "dọn dẹp" bộ nhớ khi không còn sử dụng.

Như vậy từ thông số trên ta sẽ tính được trong 1s. Server sẽ xử lý được bao nhiêu request, tiêu hao mất bao nhiêu bộ nhớ... Từ đó tính được số người dùng server phục vụ được, và cấu hình phần cứng yêu cầu khoảng bao nhiêu.

Kết quả trên được đo bằng CPU 2core. RAM 4GB. 1s CPU xử lý được 1000/63 ~= 15 request. Bộ nhớ tiêu hao: 832.13 *15 ~= 13 MB/s

Như vậy muốn đáp ứng cho khảng 20 request/s. Thì cần nâng CPU lên 1.3 lần hoặc refactor code cho process_time < 48ms

5. Tổng kết

Như vậy, với việc sử dụng gem rails-perftest chúng ta sẽ tìm ra controller nào đang có tốc độ xử lý chậm nhất, tiêu hao nhiều bộ nhớ nhất...Nếu tìm hiểu kỹ hơn chúng ta có thể tìm ra phần code nào trong model, views... gây ra performance kém và sửa. Dưới đây là link tham khảo https://github.com/rails/rails-perftest https://www.youtube.com/watch?v=eojUBB_8V_4