Skip to content

[Yaroslavzev] #140

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
@@ -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
@@ -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
@@ -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:
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
@@ -36,6 +36,7 @@ latest.dump

# Ignore application configuration
/config/application.yml
/.dockerdev/newrelic-infra.yml
/public/packs
/public/packs-test
/node_modules
@@ -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
@@ -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"
7 changes: 5 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -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"
@@ -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"
@@ -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"
19 changes: 17 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)!
@@ -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)
5 changes: 5 additions & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
@@ -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"]
6 changes: 6 additions & 0 deletions app/controllers/stories_controller.rb
Original file line number Diff line number Diff line change
@@ -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]
4 changes: 3 additions & 1 deletion app/views/stories/_main_stories_feed.html.erb
Original file line number Diff line number Diff line change
@@ -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 %>
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
@@ -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
Loading