Статьи

5 причин, почему New Relic — лучший друг разработчика

Как только вы начнете копаться в New Relic, вы начнете понимать, сколько интересных функций имеет сервис, помогающий отслеживать производительность и работоспособность вашего приложения. Было действительно трудно выбрать только пять вещей для обсуждения, поэтому вместо того, чтобы сосредоточиться на очевидных функциях, давайте рассмотрим некоторые из менее раскрученных функций, которые предоставляет New Relic, и то, как мы можем использовать их интересными, а иногда и неортодоксальными способами.

Когда мы покидали вас в последний раз , у нас было простое приложение Rails «Hello World» (называемое New Relic_rails1 , проживающее в ~/project/tmp/New Relic ). Мы продолжим использовать это приложение, расширим его и посмотрим, сможем ли мы использовать его для демонстрации функций New Relic, которые мы рассмотрим.

Спонсированный контент

Это содержание было заказано New Relic и было написано и / или отредактировано командой Tuts +. Наша цель в отношении спонсируемого контента состоит в том, чтобы публиковать соответствующие и объективные учебные пособия, тематические исследования и вдохновляющие интервью, которые предлагают реальную образовательную ценность нашим читателям и позволяют нам финансировать создание более полезного контента.


Это одна из функций New Relic, которая обычно не попадает на первую страницу маркетингового материала. В этом нет ничего особенного, но если подумать, что важнее, чтобы убедиться, что ваше приложение действительно запущено и доступно для ваших пользователей?

Во-первых, когда вы настраиваете мониторинг доступности, ваше приложение получает красивую звездочку на главной панели приложений:

newrelic_availability_asterisk

Это хорошее визуальное напоминание, так что вы можете видеть, какие приложения все еще нуждаются в мониторинге доступности.

Давайте теперь посмотрим, как мы можем настроить мониторинг доступности и что мы можем из него получить. Во-первых, вам нужно перейти в свое приложение, а затем перейти в Настройки-> Мониторинг доступности . Вы увидите что-то вроде этого:

newrelic_availability_monitoring

Вам нужно указать URL, который вы хотите, чтобы New Relic отправил эхо-запросы, поставьте галочку, сохраните изменения и все готово. Новая реликвия начнет попадать на ваш URL каждые 30 секунд. Но веселье на этом не заканчивается. New Relic будет проверять ваш URL через запрос HTTP HEAD (и будет считать, что все в порядке, если он получает код ответа 200), но вы можете указать строку ответа, которую вы хотите, чтобы New Relic искал, в этом случае он выполнит запрос GET и проверьте ответ для строки, которую вы предоставили. Это может быть очень удобно, если у вас есть пользовательская страница «Проверка здоровья», на которую вы хотите попасть.

Вы также можете настроить уведомление по электронной почте в случае простоя:

newrelic_availability_notifications

Теперь, когда вы отслеживаете доступность, у вас будет доступ к хорошему отчету, который наглядно покажет вам, когда произошли простои:

newrelic_availability_report

Фактически, многие из ваших диаграмм (например, обзор приложения) будут иметь такую ​​визуальную индикацию:

newrelic_availability_overview

Вы должны признать, что это довольно приятный функционал для такого небольшого усилия.

Конечно, вы можете отключить и снова включить мониторинг (с помощью нового Relic REST API ) при выполнении развертываний, чтобы убедиться, что вы не получаете ложных событий простоя.

Другим интересным побочным эффектом этого является то, что если вы развертываете свой проект питомца в Heroku на одном динамометрическом стенде , вы можете использовать эту функцию ping, чтобы предотвратить спящий режим вашего динамо , что может сделать ваш сайт раздражающе медленным, если у вас нет напряженная ситуация на дороге.


Если в вашем приложении возникают непредвиденные ошибки, New Relic запишет их для вас и предоставит вам хороший график. Наше маленькое приложение «Hello World» на данный момент работает превосходно, поэтому нам нечего видеть в этом плане. Но мы можем намеренно сломать наше приложение и посмотреть, что нам дает New Relic.

Давайте изменим наш HelloController чтобы случайным образом вызывать ошибку примерно в 50% случаев:

1
2
3
4
5
6
7
class HelloController < ApplicationController
  def index
    if rand(2) == 0
      raise ‘Random error’
    end
  end
end

Теперь мы сделаем несколько сотен звонков в наше приложение и посмотрим, что произойдет:

1
ab -n 300 -c 10 http://127.0.0.1:3000/

Наш график ошибок New Relic теперь выглядит намного интереснее:

newrelic_error_overview

И мы можем перейти к деталям:

newrelic_error_detailed

Как вы можете видеть, мы можем сортировать наши ошибки и фильтровать их, а также отдельно рассматривать ошибки из веб-запросов и фоновых задач. Это невероятно мощный инструмент, который поможет вам диагностировать и устранять проблемы с вашим приложением. Конечно, вы также можете увидеть трассировку стека для каждой ошибки:

newrelic_error_trace

Существуют службы, специально предназначенные для регистрации ошибок в вашем приложении, некоторые из наиболее известных — Airbrake и Bugsnag . Это платные сервисы, используемые многими приложениями, но функциональность, которую обеспечивает New Relic, делает эти сервисы избыточными. Фактически, если бы мы могли отправлять пользовательские ошибки в New Relic (вместо того, чтобы позволять ей регистрировать ошибки, которые мы не спасли), мы могли бы сделать веские аргументы в пользу того, чтобы не использовать отдельную службу сбора ошибок (и сэкономить немного денег и избавиться от дополнительных жемчужина в процессе).

В то время как New Relic не документирует какой-либо способ сделать это, мы всегда можем обратиться к источнику, чтобы увидеть, трудно ли то, что мы хотим сделать. Мне кажется, что отправка пользовательских ошибок в New Relic должна быть довольно простой задачей, поэтому давайте попробуем. Мы снова изменим действие нашего контроллера, чтобы спасти все ошибки и отправить новую ошибку в New Relic:

1
2
3
4
5
6
7
8
9
class HelloController < ApplicationController
  def index
    if rand(2) == 0
      raise ‘Random error’
    end
  rescue
    New Relic::Agent.notice_error(StandardError.new(«I caught and reraised an error»))
  end
end

После того, как мы сделаем еще несколько звонков и дождемся поступления данных, мы увидим следующее:

newrelic_error_custom

Это сработало, наша пользовательская ошибка приходит! New Relic может определенно выступать в качестве нашей службы сбора ошибок. Мы, конечно, используем здесь закрытый интерфейс, который не очень хорош, но мы можем поместить вызов notice_error за фасадом, что немного облегчит нам ситуацию, если интерфейс изменится.

Еще лучший подход может заключаться в том, чтобы вообще не обрабатывать пользовательские ошибки как обычные ошибки, а вместо этого создавать настраиваемый показатель для отслеживания, а затем создавать настраиваемую панель мониторинга для визуализации. Таким образом, мы не используем недокументированную функциональность и все равно получили бы все преимущества — блестящие!


New Relic обычно будет отслеживать ваши транзакции для вас:

newrelic_transaction_tracking

Вы сможете увидеть, где ваше приложение проводит большую часть своего времени (например, в контроллере, модели, базе данных и т. Д.). Однако New Relic не будет захватывать детальную трассировку, если транзакция не займет больше времени, чем Appdex * 4 секунды. Обычно это нормально, но иногда у вас есть транзакции, которые гораздо важнее для вашего приложения или для вашего бизнеса. Возможно, эти транзакции имеют чрезвычайно большой объем или связаны с такими важными событиями, как платежи. Достаточно сказать, что вы должны убедиться, что этот тип транзакции всегда работает очень хорошо.

Дело в том, что когда транзакция настолько важна, она, вероятно, уже получила от вас достаточно любви и может показаться довольно хорошей. Допустим, у вас есть транзакция с чрезвычайно высокой пропускной способностью (происходит много раз в минуту). Если эта транзакция работает оптимально, то все в порядке, но если производительность немного снизится, из-за объема трафика это может оказать непропорционально пагубное влияние на ваше приложение. То, что вы хотите, это что-то вроде:

  • отдельное значение Apdex T только для этой транзакции
  • возможность получать оповещения, когда производительность этой транзакции ухудшается
  • подробный след каждый раз, когда эта транзакция выполняется даже немного неоптимально

Это именно то, что дают вам ключевые транзакции!

Прежде чем мы настроим ключевую транзакцию для нашего приложения «Hello World», нам нужно создать более интересную транзакцию, которая обычно будет работать хорошо, но иногда будет работать несколько хуже. Мы создадим возможность смотреть на марки и модели автомобилей и подбирать конкретные марки автомобилей, чтобы замедлить транзакцию. Во-первых, маршрут:

1
2
3
4
5
New RelicRails1::Application.routes.draw do
  get ‘random_car’, to: ‘cars#show_random’
 
  root ‘hello#index’
end

Мы хотим иметь возможность получить случайный автомобиль, который будет отображаться в CarsController :

1
2
3
4
5
6
7
8
class CarsController < ApplicationController
  def show_random
    @car = Car.offset(rand(Car.count)).first
    if @car.make == ‘Ford’
      sleep(2)
    end
  end
end

Мы получаем случайный автомобиль из базы данных, и если марка автомобиля — «Форд», у нас будет медленная транзакция. Конечно, нам нужна модель Car :

1
2
class Car < ActiveRecord::Base
end

Нам нужно настроить нашу базу данных для использования MySql в разработке (я сделал это, но вы можете придерживаться sqlite ):

01
02
03
04
05
06
07
08
09
10
11
12
base: &BASE
  adapter: mysql2
  encoding: utf8
  host: «localhost»
  username: «root»
  max_connections: 10
  timeout: 5000
 
development: &DEV
  <<: *BASE
  database: «New Relic_rails1_development»
  sql_log_level: debug

Нам нужна миграция для создания таблицы cars :

1
2
3
4
5
6
7
8
class Cars < ActiveRecord::Migration
  def change
    create_table :cars, force: true do |t|
      t.string :make
      t.string :model
    end
  end
end

И нам нужны некоторые начальные данные, которые мы поместим в наш файл db/seeds.rb :

1
2
3
4
5
Car.create(make: ‘Ford’, model: ‘Mondeo’)
Car.create(make: ‘Honda’, model: ‘Accord’)
Car.create(make: ‘Audi’, model: ‘A4’)
Car.create(make: ‘Lamborghini’, model: ‘Murcielago’)
Car.create(make: ‘Toyota’, model: ‘Prius’)

Наконец, мы, вероятно, должны иметь представление cars/show_random.html.erb :

1
2
<h1>Make: <%= @car.make %></h1>
<h2>Model: <%= @car.model %></h2>

Вам также необходимо добавить гем Gemfile в Gemfile если вы использовали MySql. После этого нам просто нужно создать и заполнить базу данных, перезапустить наш сервер, и все готово:

1
2
3
bundle
rake db:create && rake db:migrate && rake db:seed
rails s

Вам нужно будет нажать на URL, чтобы убедиться, что New Relic распознает, что эта транзакция существует:

1
curl localhost:3000/random_car

Теперь мы готовы отслеживать эту транзакцию как ключевую транзакцию. Сначала перейдите на вкладку транзакции:

newrelic_transaction_tab

Нажмите кнопку «Отслеживание ключевой транзакции», выберите нашу вновь созданную транзакцию:

newrelic_transaction_create

Мы можем дать нашей новой ключевой транзакции имя, выбрать Apdex T, которым мы довольны, а также настроить некоторые оповещения. Когда наша транзакция займет больше времени, чем выбранный нами Apdex, New Relic захватит подробный след, который мы сможем использовать, чтобы выяснить, откуда возникла проблема с производительностью. Давайте сделаем несколько звонков на наш новый URL и посмотрим, какие данные мы получим:

1
ab -n 300 -c 20 http://127.0.0.1:3000/random_car

Хм, кажется, некоторые из наших транзакций расстраивают наших пользователей:

newrelic_transaction_frustrating

Давайте посмотрим, обнаружил ли New Relic некоторые транзакции для нас:

newrelic_transaction_slow_traces

Давайте посмотрим на один из этих следов. Чтобы ответить, потребовалось около 2 секунд, но только 10 миллисекунд использовали процессор:

newrelic_transaction_cpu_burn

Все наши операторы SQL были быстрыми, поэтому проблема не в базе данных:

newrelic_transaction_sql_trace

Похоже, что большую часть времени тратится на действия контроллера:

newrelic_transaction_controller_action

Давайте углубимся в след. Похоже, что SQL SELECT был быстрым, Car.find также был быстрым. Затем мы теряем около 2 секунд, после чего следует очень быстрый рендеринг шаблона:

newrelic_transaction_trace_detail

Новый Relic любезно подчеркнул для нас, где мы потеряли эти две секунды. Нам нужно взглянуть на код нашего контроллера после вызова Car.find :

1
2
3
4
5
6
7
8
class CarsController < ApplicationController
  def show_random
    @car = Car.offset(rand(Car.count)).first
    if @car.make == ‘Ford’
      sleep(2)
    end
  end
end

Хм, начальный SELECT должен быть вызовом Car.count , а Car.find должен быть Car.offset вызовом Car.offset . Наша большая задержка сразу после этого, хотя. Ага, посмотрите на это, какой-то глупый человек добавил в наш код 2-секундную задержку, когда марка машины — «Форд». Это объясняет, почему наша задержка в 2 секунды происходит только иногда. Я лучше сделаю git blame в наш репозиторий, чтобы узнать, кто поместил туда этот ужасный код! Если подумать, мне лучше этого не делать, потому что это может сказать, что это был я.


Всякий раз, когда вы делаете звонки на другие сервисы из вашего приложения (например, HTTP-запрос к API, например, Twitter ), New Relic будет отслеживать их как внешние вызовы. В наши дни серьезное приложение может интегрироваться с рядом внешних API. Часто эти внешние службы могут значительно снизить производительность вашего приложения, особенно если вы выполняете эти вызовы в процессе. Новая Relic может показать, какие из ваших внешних вызовов являются самыми медленными, какие из них вы вызываете чаще всего, а какие отвечают в среднем медленнее. Вы также можете посмотреть на производительность каждой из внешних услуг, которые вы используете в отдельности. Давайте попробуем.

Мы создадим наш собственный внешний сервис, создав небольшое приложение Sinatra . Сначала мы устанавливаем драгоценный камень:

1
gem install sinatra

Создайте новый файл для нашего сервиса:

1
touch external_service.rb

И поместите туда следующий код:

1
2
3
4
5
6
7
require ‘sinatra’
 
get ‘/hello’ do
  sleep_time = rand(2000)/1000.0
  sleep(sleep_time)
  «Hello External World #{sleep_time}!»
end

Эта служба будет находиться в спящем режиме в течение произвольного времени (от 0 до 2000 миллисекунд), а затем возвращает ответ «Hello» со временем, в течение которого она спала. Теперь все, что нам нужно сделать, это запустить его:

1
ruby external_service.rb

Вернувшись в наше приложение Rails, мы создадим новый контроллер для вызова нашего внешнего сервиса. Мы будем использовать этот маршрут:

1
2
3
4
5
New RelicRails1::Application.routes.draw do
  get ‘external_call’, to: ‘external_calls#external_call’
end

Наш контроллер будет вызывать наш сервис Sinatra через HTTP:

01
02
03
04
05
06
07
08
09
10
11
12
require ‘net/http’
 
class ExternalCallsController < ApplicationController
  def external_call
    url = URI.parse(‘http://localhost:4567/hello’)
    external_request = Net::HTTP::Get.new(url.to_s)
    external_response = Net::HTTP.start(url.host, url.port) do |http|
      http.request(external_request)
    end
    @result = external_response.body
  end
end

И нам нужен вид для отображения результатов:

1
<h1><%= @result %></h1>

Все, что нам нужно сделать, это сделать несколько звонков на нашу новую конечную точку:

1
ab -n 100 -c 10 http://127.0.0.1:3000/external_call

Давайте посмотрим, что New Relic произвела для нас.

newrelic_transaction_external_service

Новая Реликвия действительно приняла наш новый внешний вызов. У нас есть общее количество вызовов в минуту, которые мы делаем на внешнюю конечную точку. И общая сумма, потраченная на ответ внешней службы. Конечно, наш график выглядит немного скудным, поскольку у нас есть только один внешний сервис, что означает, что нам не с чем сравнивать.

Мы также можем получить более подробные данные о конкретном внешнем вызове, а также о том, откуда в нашем приложении делается этот вызов:

newrelic_transaction_external_call

Мы можем видеть, когда были сделаны вызовы, пропускную способность и среднее время ответа. Это может показаться простым, но если у вас есть приложение с большим количеством внешних сервисов, эта функция может дать вам очень хороший обзор того, как работают эти внешние сервисы, а также когда и где они используются. Это может позволить вам принимать решения, касающиеся кэширования определенных ответов внешних служб, если это возможно, или даже отбрасывания определенных внешних служб, если их производительность не до нуля. И вам больше не нужно спорить об этих вещах, основываясь на интуитивных ощущениях и запеченных в домашних условиях показателях, у вас будут точные данные, чтобы доказать свою точку зрения для вас.

Для разработчика нет ничего более разочаровывающего, чем падение приложения из-за резкого увеличения трафика. Все шло гладко, пока не появились эти несколько сотен пользователей и ваше приложение взорвалось. У вас было чувство, что это может произойти, но вы не могли быть уверены — выжидательная позиция казалась самым прагматичным подходом. Что касается отчетов о емкости и масштабируемости New Relic, вам больше не нужно «ждать и видеть». Вы можете сразу сказать, насколько хорошо ваше приложение масштабируется, вы можете выполнить нагрузочные тесты и сразу увидеть, сможет ли ваше приложение справиться с нагрузкой. Вы можете наблюдать тенденции времени отклика вашего приложения по мере роста вашей пользовательской базы и прогнозировать, когда вам нужно будет увеличить емкость. Все это действительно замечательные вещи.

Сначала давайте посмотрим на отчеты о емкости:

newrelic_capacity_instance_busy

Хм, этот показывает большой всплеск, но в остальном ничего. Ну, мы работаем в режиме разработки, так что это понятно. Этот всплеск предназначен для того, когда мы сделали несколько запросов одновременно, совсем недавно. Как вы можете видеть, когда мы выполняли эти параллельные запросы, мы максимально использовали наш бедный одинокий экземпляр Webrick. Если бы это было производство и эта нагрузка была постоянной, наш экземпляр всегда был бы занят на 100%, что, вероятно, указывало бы на то, что нам нужен другой экземпляр.

Отчет анализа экземпляра немного отличается:

newrelic_capacity_instance_analysis

В нашем случае мы мало что получаем от этого, но обычно он показывает нам количество запущенных экземпляров и количество экземпляров, которые нам действительно нужны для обработки нагрузки, если все экземпляры были заняты на 100%. Таким образом, если бы мы запускали 10 экземпляров, а одновременная загрузка экземпляров равнялась 2, мы могли бы легко вдвое (или даже больше, чем вдвое) увеличить количество запущенных экземпляров и вообще не снижать производительность. Для небольшого приложения, которое запускается всего в нескольких экземплярах, это не представляет особой проблемы, но для большого приложения с десятками и сотнями экземпляров это может привести к значительной экономии средств.

И затем есть отчеты о масштабируемости. Отчет о времени отклика, пожалуй, самый интересный / важный:

newrelic_scalability_response

Еще раз, наш график очень искажен, потому что это приложение для разработки, с которым мы играли случайно. Идея этого отчета заключается в том, что по мере увеличения пропускной способности вашего приложения (больше запросов в минуту) время отклика должно оставаться близким к постоянному (т. Е. Производительность не снижается при большем трафике). Это означает, что вы всегда должны видеть что-то похожее на плоскую линию здесь. Если ваша линия значительно наклонена вверх, ваше приложение, вероятно, изо всех сил пытается обработать трафик, и вам может потребоваться увеличить пропускную способность. Где добавить емкость — это совсем другой вопрос (например, емкость базы данных, больше серверов и т. Д.). Два других отчета о масштабируемости помогут вам ответить на него. Есть отчет базы данных:

newrelic_scalability_database

Вы не можете ожидать, что ваша база данных не будет подвержена более высокой нагрузке, поэтому здесь вы должны увидеть линию, которая медленно увеличивается с ростом пропускной способности вашего приложения. Это зависит от вас, когда время отклика базы данных считается неприемлемым (то есть слишком сильно влияет на отклик приложения), но когда вы решаете, что ответы базы данных слишком медленные, вы знаете, что пришло время добавить емкость базы данных. Другой отчет — это процессор:

newrelic_scalability_cpu

Опять же, вы не можете ожидать, что более высокая пропускная способность не повлияет на загрузку вашего процессора, вы должны увидеть линию, которая постепенно увеличивается с увеличением пропускной способности. Это, вместе с отчетами о пропускной способности, о которых мы говорили ранее, может позволить вам решить, когда добавить больше процессов / серверов Rails, чтобы обеспечить достойную производительность.


Если одна или все из этих функций вызвали у вас удивление (или две), хорошая новость заключается в том, что мы только что поцарапали поверхность. Каждая из этих функций более чем заслуживает отдельной статьи. Но у New Relic также есть ряд других функций, которые потенциально могут быть даже более мощными, включая мониторинг реальных пользователей , платформу New Relic , профилировщик потоков , пороговые значения оповещений и уведомления и многие другие. Мы постараемся охватить некоторые или, возможно, даже все из них в следующих уроках.

А пока попробуйте New Relic, разверните агент на своем любимом языке и посмотрите, сможете ли вы найти готовый способ использования некоторых функций, предоставляемых New Relic. И если у вас есть какие-то инновационные способы использования New Relic, обязательно сообщите об этом всем, оставив комментарий.