Commit b30ae67d authored by Aleksei Lipniagov's avatar Aleksei Lipniagov

Remove Unicorn Sampler and its dependencies

With removing Unicorn support in 14.0, UnicornSampler is no longer
needed.
Raindrops was only used with Unicorn, so it could be removed too.
Update the docs related to the change.

Changelog: removed
parent e0f653a5
......@@ -341,7 +341,6 @@ group :metrics do
# Prometheus
gem 'prometheus-client-mmap', '~> 0.12.0'
gem 'raindrops', '~> 0.18'
end
group :development do
......
......@@ -1592,7 +1592,6 @@ DEPENDENCIES
rails-controller-testing
rails-i18n (~> 6.0)
rainbow (~> 3.0)
raindrops (~> 0.18)
rblineprof (~> 0.3.6)
rbtrace (~> 0.4)
rdoc (~> 6.1.2)
......
---
title: Remove Unicorn Sampler
merge_request: 62090
author:
type: removed
......@@ -33,7 +33,7 @@ production: &base
host: localhost
port: 80 # Set to 443 if using HTTPS, see installation.md#using-https for additional HTTPS configuration details
https: false # Set to true if using HTTPS, see installation.md#using-https for additional HTTPS configuration details
# The maximum time unicorn/puma can spend on the request. This needs to be smaller than the worker timeout.
# The maximum time Puma can spend on the request. This needs to be smaller than the worker timeout.
# Default is 95% of the worker timeout
max_request_duration_seconds: 57
......@@ -153,7 +153,7 @@ production: &base
### GraphQL Settings
# Tells the rails application how long it has to complete a GraphQL request.
# We suggest this value to be higher than the database timeout value
# and lower than the worker timeout set in unicorn/puma. (default: 30)
# and lower than the worker timeout set in Puma. (default: 30)
# graphql_timeout: 30
## Repository downloads directory
......@@ -1212,8 +1212,6 @@ production: &base
## Monitoring
# Built in monitoring settings
monitoring:
# Time between sampling of unicorn socket metrics, in seconds
# unicorn_sampler_interval: 10
# IP whitelist to access monitoring endpoints
ip_whitelist:
- 127.0.0.0/8
......@@ -1225,7 +1223,7 @@ production: &base
# address: localhost
# port: 8082
# Web exporter is webserver built in to Unicorn/Puma to expose Prometheus metrics
# Web exporter is a dedicated Rack server running alongside Puma to expose Prometheus metrics
# It runs alongside the `/metrics` endpoints to ease the publish of metrics
web_exporter:
# enabled: true
......
......@@ -902,7 +902,6 @@ Settings.webpack.dev_server['https'] ||= false
#
Settings['monitoring'] ||= Settingslogic.new({})
Settings.monitoring['ip_whitelist'] ||= ['127.0.0.1/8']
Settings.monitoring['unicorn_sampler_interval'] ||= 10
Settings.monitoring['sidekiq_exporter'] ||= Settingslogic.new({})
Settings.monitoring.sidekiq_exporter['enabled'] ||= false
Settings.monitoring.sidekiq_exporter['log_enabled'] ||= false
......
......@@ -8,8 +8,6 @@ def prometheus_default_multiproc_dir
if Gitlab::Runtime.sidekiq?
Rails.root.join('tmp/prometheus_multiproc_dir/sidekiq')
elsif Gitlab::Runtime.unicorn?
Rails.root.join('tmp/prometheus_multiproc_dir/unicorn')
elsif Gitlab::Runtime.puma?
Rails.root.join('tmp/prometheus_multiproc_dir/puma')
else
......@@ -49,9 +47,7 @@ if !Rails.env.test? && Gitlab::Metrics.prometheus_metrics_enabled?
::Prometheus::Client.reinitialize_on_pid_change(force: true)
if Gitlab::Runtime.unicorn?
Gitlab::Metrics::Samplers::UnicornSampler.instance(Settings.monitoring.unicorn_sampler_interval).start
elsif Gitlab::Runtime.puma?
if Gitlab::Runtime.puma?
Gitlab::Metrics::Samplers::PumaSampler.instance.start
end
......
......@@ -69,6 +69,5 @@ The following environment variables are recognized:
- `DATABASE_SAMPLER_INTERVAL_SECONDS`
- `ACTION_CABLE_SAMPLER_INTERVAL_SECONDS`
- `PUMA_SAMPLER_INTERVAL_SECONDS`
- `UNICORN_SAMPLER_INTERVAL_SECONDS`
- `THREADS_SAMPLER_INTERVAL_SECONDS`
- `GLOBAL_SEARCH_SAMPLER_INTERVAL_SECONDS`
......@@ -308,20 +308,8 @@ Some basic Ruby runtime metrics are available:
| `ruby_process_proportional_memory_bytes` | Gauge | 13.0 | Memory usage by process (PSS/Proportional Set Size) |
| `ruby_process_start_time_seconds` | Gauge | 12.0 | UNIX timestamp of process start time |
## Unicorn Metrics
Unicorn specific metrics, when Unicorn is used.
| Metric | Type | Since | Description |
|:-----------------------------|:------|:------|:---------------------------------------------------|
| `unicorn_active_connections` | Gauge | 11.0 | The number of active Unicorn connections (workers) |
| `unicorn_queued_connections` | Gauge | 11.0 | The number of queued Unicorn connections |
| `unicorn_workers` | Gauge | 12.0 | The number of Unicorn workers |
## Puma Metrics
When Puma is used instead of Unicorn, the following metrics are available:
| Metric | Type | Since | Description |
|:--------------------------------- |:------- |:----- |:----------- |
| `puma_workers` | Gauge | 12.0 | Total number of workers |
......@@ -352,8 +340,8 @@ instance (`cache`, `shared_state` etc.).
## Metrics shared directory
The GitLab Prometheus client requires a directory to store metrics data shared between multi-process services.
Those files are shared among all instances running under Unicorn server.
The directory must be accessible to all running Unicorn's processes, or
Those files are shared among all instances running under Puma server.
The directory must be accessible to all running Puma's processes, or
metrics can't function correctly.
This directory's location is configured using environment variable `prometheus_multiproc_dir`.
......
......@@ -863,55 +863,6 @@ license.save
License.current # check to make sure it applied
```
## Unicorn
From [Zendesk ticket #91083](https://gitlab.zendesk.com/agent/tickets/91083) (internal)
### Poll Unicorn requests by seconds
```ruby
require 'rubygems'
require 'unicorn'
# Usage for this program
def usage
puts "ruby unicorn_status.rb <path to unix socket> <poll interval in seconds>"
puts "Polls the given Unix socket every interval in seconds. Will not allow you to drop below 3 second poll intervals."
puts "Example: /opt/gitlab/embedded/bin/ruby poll_unicorn.rb /var/opt/gitlab/gitlab-rails/sockets/gitlab.socket 10"
end
# Look for required args. Throw usage and exit if they don't exist.
if ARGV.count < 2
usage
exit 1
end
# Get the socket and threshold values.
socket = ARGV[0]
threshold = (ARGV[1]).to_i
# Check threshold - is it less than 3? If so, set to 3 seconds. Safety first!
if threshold.to_i < 3
threshold = 3
end
# Check - does that socket exist?
unless File.exist?(socket)
puts "Socket file not found: #{socket}"
exit 1
end
# Poll the given socket every THRESHOLD seconds as specified above.
puts "Running infinite loop. Use CTRL+C to exit."
puts "------------------------------------------"
loop do
Raindrops::Linux.unix_listener_stats([socket]).each do |addr, stats|
puts DateTime.now.to_s + " Active: " + stats.active.to_s + " Queued: " + stats.queued.to_s
end
sleep threshold
end
```
## Registry
### Registry Disk Space Usage by Project
......
# frozen_string_literal: true
module Gitlab
module Metrics
module Samplers
class UnicornSampler < BaseSampler
DEFAULT_SAMPLING_INTERVAL_SECONDS = 5
def metrics
@metrics ||= init_metrics
end
def init_metrics
{
unicorn_active_connections: ::Gitlab::Metrics.gauge(:unicorn_active_connections, 'Unicorn active connections', {}, :max),
unicorn_queued_connections: ::Gitlab::Metrics.gauge(:unicorn_queued_connections, 'Unicorn queued connections', {}, :max),
unicorn_workers: ::Gitlab::Metrics.gauge(:unicorn_workers, 'Unicorn workers')
}
end
def enabled?
# Raindrops::Linux.tcp_listener_stats is only present on Linux
unicorn_with_listeners? && Raindrops::Linux.respond_to?(:tcp_listener_stats)
end
def sample
Raindrops::Linux.tcp_listener_stats(tcp_listeners).each do |addr, stats|
set_unicorn_connection_metrics('tcp', addr, stats)
end
Raindrops::Linux.unix_listener_stats(unix_listeners).each do |addr, stats|
set_unicorn_connection_metrics('unix', addr, stats)
end
metrics[:unicorn_workers].set({}, unicorn_workers_count)
end
private
def tcp_listeners
@tcp_listeners ||= Unicorn.listener_names.grep(%r{\A[^/]+:\d+\z})
end
def set_unicorn_connection_metrics(type, addr, stats)
labels = { socket_type: type, socket_address: addr }
metrics[:unicorn_active_connections].set(labels, stats.active)
metrics[:unicorn_queued_connections].set(labels, stats.queued)
end
def unix_listeners
@unix_listeners ||= Unicorn.listener_names - tcp_listeners
end
def unicorn_with_listeners?
defined?(Unicorn) && Unicorn.listener_names.any?
end
def unicorn_workers_count
http_servers.sum(&:worker_processes)
end
# Traversal of ObjectSpace is expensive, on fully loaded application
# it takes around 80ms. The instances of HttpServers are not a subject
# to change so we can cache the list of servers.
def http_servers
return [] unless Gitlab::Runtime.unicorn?
@http_servers ||= ObjectSpace.each_object(::Unicorn::HttpServer).to_a
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Metrics::Samplers::UnicornSampler do
subject { described_class.new(1.second) }
it_behaves_like 'metrics sampler', 'UNICORN_SAMPLER'
describe '#sample' do
let(:unicorn) { Module.new }
let(:raindrops) { double('raindrops') }
let(:stats) { double('stats') }
before do
stub_const('Unicorn', unicorn)
stub_const('Raindrops::Linux', raindrops)
allow(raindrops).to receive(:unix_listener_stats).and_return({})
allow(raindrops).to receive(:tcp_listener_stats).and_return({})
end
context 'unicorn listens on unix sockets' do
let(:socket_address) { '/some/sock' }
let(:sockets) { [socket_address] }
before do
allow(unicorn).to receive(:listener_names).and_return(sockets)
end
it 'samples socket data' do
expect(raindrops).to receive(:unix_listener_stats).with(sockets)
subject.sample
end
context 'stats collected' do
before do
allow(stats).to receive(:active).and_return('active')
allow(stats).to receive(:queued).and_return('queued')
allow(raindrops).to receive(:unix_listener_stats).and_return({ socket_address => stats })
end
it 'updates metrics type unix and with addr' do
labels = { socket_type: 'unix', socket_address: socket_address }
expect(subject.metrics[:unicorn_active_connections]).to receive(:set).with(labels, 'active')
expect(subject.metrics[:unicorn_queued_connections]).to receive(:set).with(labels, 'queued')
subject.sample
end
end
end
context 'unicorn listens on tcp sockets' do
let(:tcp_socket_address) { '0.0.0.0:8080' }
let(:tcp_sockets) { [tcp_socket_address] }
before do
allow(unicorn).to receive(:listener_names).and_return(tcp_sockets)
end
it 'samples socket data' do
expect(raindrops).to receive(:tcp_listener_stats).with(tcp_sockets)
subject.sample
end
context 'stats collected' do
before do
allow(stats).to receive(:active).and_return('active')
allow(stats).to receive(:queued).and_return('queued')
allow(raindrops).to receive(:tcp_listener_stats).and_return({ tcp_socket_address => stats })
end
it 'updates metrics type unix and with addr' do
labels = { socket_type: 'tcp', socket_address: tcp_socket_address }
expect(subject.metrics[:unicorn_active_connections]).to receive(:set).with(labels, 'active')
expect(subject.metrics[:unicorn_queued_connections]).to receive(:set).with(labels, 'queued')
subject.sample
end
end
end
context 'unicorn workers' do
before do
allow(unicorn).to receive(:listener_names).and_return([])
end
context 'without http server' do
it "does set unicorn_workers to 0" do
expect(subject.metrics[:unicorn_workers]).to receive(:set).with({}, 0)
subject.sample
end
end
context 'with http server' do
let(:http_server_class) { Struct.new(:worker_processes) }
let!(:http_server) { http_server_class.new(5) }
before do
stub_const('Unicorn::HttpServer', http_server_class)
end
it "sets additional metrics" do
expect(subject.metrics[:unicorn_workers]).to receive(:set).with({}, 5)
subject.sample
end
end
end
end
describe '#start' do
context 'when enabled' do
before do
allow(subject).to receive(:enabled?).and_return(true)
end
it 'creates new thread' do
expect(Thread).to receive(:new)
subject.start
end
end
context 'when disabled' do
before do
allow(subject).to receive(:enabled?).and_return(false)
end
it "doesn't create new thread" do
expect(Thread).not_to receive(:new)
subject.start
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment