Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions .dockerdev/compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ x-backend: &backend
stdin_open: true
tty: true
volumes:
- ..:/app:cached
- ..:/app
- bundle:/usr/local/bundle
- rails_cache:/app/tmp/cache
- node_modules:/app/node_modules
Expand All @@ -30,9 +30,6 @@ x-backend: &backend
environment: &backend_environment
<<: *env
YARN_INTEGRITY_ENABLED: "false"
ALGOLIASEARCH_APPLICATION_ID: PASTE
ALGOLIASEARCH_API_KEY: YOUR
ALGOLIASEARCH_SEARCH_ONLY_KEY: HERE
REDIS_URL: redis://redis:6379/
DATABASE_URL: postgres://postgres:postgres@postgres:5432
WEBPACKER_DEV_SERVER_HOST: webpacker
Expand Down Expand Up @@ -113,7 +110,20 @@ services:
<<: *env
WEBPACKER_DEV_SERVER_HOST: 0.0.0.0
YARN_CACHE_FOLDER: /app/node_modules/.yarn-cache

agent:
container_name: newrelic-infra
build:
context: .
dockerfile: newrelic-infra.dockerfile
cap_add:
- SYS_PTRACE
network_mode: host
pid: host
privileged: true
volumes:
- "/:/host:ro"
- "/var/run/docker.sock:/var/run/docker.sock"
restart: unless-stopped
volumes:
bundle:
node_modules:
Expand Down
2 changes: 2 additions & 0 deletions .dockerdev/newrelic-infra.dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
FROM newrelic/infrastructure:latest
ADD newrelic-infra.yml /etc/newrelic-infra.yml
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ latest.dump

# Ignore application configuration
/config/application.yml
/.dockerdev/newrelic-infra.yml
/public/packs
/public/packs-test
/node_modules
Expand All @@ -52,4 +53,4 @@ package-lock.json
.idea/

#sitemap
/public/sitemap.xml.gz
/public/sitemap.xml.gz
2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.3.1
3.2.4
1 change: 1 addition & 0 deletions Envfile
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ only_in_test = proc { ENV['RACK_ENV'] == "test" ? "test-test" : nil}
variable :ALGOLIASEARCH_API_KEY, :String, default: only_in_test
variable :ALGOLIASEARCH_APPLICATION_ID, :String, default: only_in_test
variable :ALGOLIASEARCH_SEARCH_ONLY_KEY, :String, default: only_in_test
variable :NEW_RELIC_LICENSE_KEY, :String, default: "Optional"

# AWS for images storages
variable :AWS_ID, :String, default: "Optional"
Expand Down
7 changes: 5 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ gem "uglifier", "~> 4.1"
gem "validate_url", "~> 1.0"
gem "webpacker", "~> 3.5"
gem "webpush", "~> 0.3"
gem 'newrelic_rpm'
gem 'newrelic-infinite_tracing'
gem 'rack-mini-profiler'
gem 'memory_profiler'
gem 'stackprof'

group :development do
gem "better_errors", "~> 2.5"
Expand All @@ -123,7 +128,6 @@ group :development, :test do
gem "erb_lint", "~> 0.0", require: false
gem "faker", git: "https://github.com/stympy/faker.git", branch: "master"
gem "fix-db-schema-conflicts", github: "jakeonrails/fix-db-schema-conflicts", branch: "master"
gem "memory_profiler", "~> 0.9"
gem "parallel_tests", "~> 2.27"
gem "pry-byebug", "~> 3.7"
gem "rspec-rails", "~> 3.8"
Expand All @@ -149,7 +153,6 @@ group :test do
gem "shoulda-matchers", "4.0.0.rc1", require: false
gem "simplecov", "~> 0.16", require: false
gem "sinatra", "~> 2.0"
gem "stackprof", "~> 0.2", require: false, platforms: :ruby
gem "stripe-ruby-mock", "~> 2.5", require: "stripe_mock"
gem "test-prof", "~> 0.7"
gem "timecop", "~> 0.9"
Expand Down
19 changes: 17 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -487,13 +487,19 @@ GEM
representable (~> 3.0)
retriable (>= 2.0, < 4.0)
signet (~> 0.10)
google-protobuf (3.23.4)
googleapis-common-protos-types (1.12.0)
google-protobuf (~> 3.18)
googleauth (0.8.0)
faraday (~> 0.12)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (~> 0.7)
grpc (1.58.0)
google-protobuf (~> 3.23)
googleapis-common-protos-types (~> 1.0)
guard (2.15.0)
formatador (>= 0.2.4)
listen (>= 2.7, < 4.0)
Expand Down Expand Up @@ -612,6 +618,10 @@ GEM
net-http-persistent (3.0.0)
connection_pool (~> 2.2)
netrc (0.11.0)
newrelic-infinite_tracing (9.9.0)
grpc (~> 1.34)
newrelic_rpm (= 9.9.0)
newrelic_rpm (9.9.0)
nio4r (2.3.1)
nokogiri (1.10.1)
mini_portile2 (~> 2.4.0)
Expand Down Expand Up @@ -677,6 +687,8 @@ GEM
rack (2.0.6)
rack-host-redirect (1.3.0)
rack
rack-mini-profiler (3.1.1)
rack (>= 1.2.0)
rack-protection (2.0.4)
rack
rack-proxy (0.6.5)
Expand Down Expand Up @@ -1007,8 +1019,10 @@ DEPENDENCIES
launchy (~> 2.4)
libhoney (~> 1.11)
liquid (~> 4.0)
memory_profiler (~> 0.9)
memory_profiler
nakayoshi_fork
newrelic-infinite_tracing
newrelic_rpm
nokogiri (~> 1.10)
octokit (~> 4.13)
omniauth (~> 1.9)
Expand All @@ -1025,6 +1039,7 @@ DEPENDENCIES
pusher (~> 1.3)
pusher-push-notifications (~> 1.0)
rack-host-redirect (~> 1.3)
rack-mini-profiler
rack-timeout (~> 0.5)
rails (~> 5.1.6)
rails-assets-airbrake-js-client (~> 1.5)!
Expand Down Expand Up @@ -1057,7 +1072,7 @@ DEPENDENCIES
slack-notifier (~> 2.3)
sprockets (~> 3.7)
staccato (~> 0.5)
stackprof (~> 0.2)
stackprof
storext (~> 2.2)
stripe (~> 4.8)
stripe-ruby-mock (~> 2.5)
Expand Down
5 changes: 5 additions & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ class ApplicationController < ActionController::Base
include Pundit
include Instrumentation

def profile_call
return true if params['profile'] == 'true'
false
end

def require_http_auth
authenticate_or_request_with_http_basic do |username, password|
username == ApplicationConfig["APP_NAME"] && password == ApplicationConfig["APP_PASSWORD"]
Expand Down
6 changes: 6 additions & 0 deletions app/controllers/stories_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ class StoriesController < ApplicationController
before_action :authenticate_user!, except: %i[index search show feed new]
before_action :set_cache_control_headers, only: %i[index search show]

before_action do
if profile_call
::Rack::MiniProfiler.authorize_request
end
end

def index
add_param_context(:username, :tag)
return handle_user_or_organization_or_podcast_index if params[:username]
Expand Down
4 changes: 3 additions & 1 deletion app/views/stories/_main_stories_feed.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@
<% if !user_signed_in? && i == 4 %>
<%= render "stories/sign_in_invitation" %>
<% end %>
<%= render "articles/single_story", story: story %>
<% cache(story) do %>
<%= render "articles/single_story", story: story %>
<% end %>
<% end %>
<% end %>
<% if @stories.size > 1 %>
Expand Down
124 changes: 124 additions & 0 deletions case-study.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
## Case Study

## Подготовка

- Запустил проект `dev.to` локально
- Настроил `NewRelic` для 'development'
- Настроил `local_production` для проекта и подкючил `NewRelic`
- Настроил `rack-mini-profiler` для `local_production` и добавил ключ по которому можно включить профайлер

## Оптимизация

Ввиду сложностей запуска, я строго следовал рекомендация из описания.
NewRelic оказался не очень информативен для понимания причины медленной работы ввиду трейсы из коробки не идентифицируют все трейсы.
`rack-mini-profiler` показал, что `single_story` рендерится многократно и это точка для оптимизации.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RMP one love <3


![img.png](img.png)

Утилита ab показала, что среднее время ответа составляет `675.065 [ms]`

<details>
<summary>ab -n 100 -c 5 127.0.0.1:3000/</summary>

```
This is ApacheBench, Version 2.3 <$Revision: 1903618 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient).....done


Server Software:
Server Hostname: 127.0.0.1
Server Port: 3000

Document Path: /
Document Length: 143403 bytes

Concurrency Level: 5
Time taken for tests: 13.501 seconds
Complete requests: 100
Failed requests: 0
Total transferred: 14382600 bytes
HTML transferred: 14340300 bytes
Requests per second: 7.41 [#/sec] (mean)
Time per request: 675.065 [ms] (mean)
Time per request: 135.013 [ms] (mean, across all concurrent requests)
Transfer rate: 1040.31 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.5 0 4
Processing: 108 631 1067.2 377 5300
Waiting: 107 624 1066.9 373 5297
Total: 109 631 1067.2 378 5300

Percentage of the requests served within a certain time (ms)
50% 378
66% 405
75% 440
80% 459
90% 520
95% 5153
98% 5285
99% 5300
100% 5300 (longest request)
```

</details>

После добавления кэширования в метод `single_story` среднее время ответа составило `133.472 [ms]`
и `rack-mini-profiler` показал, что `single_story` рендерится один раз.
![img_1.png](img_1.png)

<details>
<summary>ab -n 100 -c 5 127.0.0.1:3000/</summary>

```
This is ApacheBench, Version 2.3 <$Revision: 1903618 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient).....done


Server Software:
Server Hostname: 127.0.0.1
Server Port: 3000

Document Path: /
Document Length: 143451 bytes

Concurrency Level: 5
Time taken for tests: 2.669 seconds
Complete requests: 100
Failed requests: 0
Total transferred: 14387400 bytes
HTML transferred: 14345100 bytes
Requests per second: 37.46 [#/sec] (mean)
Time per request: 133.472 [ms] (mean)
Time per request: 26.694 [ms] (mean, across all concurrent requests)
Transfer rate: 5263.34 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.2 0 1
Processing: 68 124 26.5 115 206
Waiting: 66 122 26.1 112 205
Total: 68 125 26.5 116 206

Percentage of the requests served within a certain time (ms)
50% 116
66% 135
75% 143
80% 146
90% 157
95% 175
98% 198
99% 206
100% 206 (longest request)
```

</details>

Таким образом, после оптимизации среднее время ответа уменьшилось в 5 раз.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

1 change: 1 addition & 0 deletions config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
module PracticalDeveloper
class Application < Rails::Application
config.load_defaults 5.1
# config.web_console.whitelisted_ips = '192.168.0.0/16'

# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
Expand Down
Loading