diff --git a/Gemfile b/Gemfile
index cc7d59ef73245797f83122b657132544c99b3263..724c7143119ff1a344da329780367f3523401c55 100644
--- a/Gemfile
+++ b/Gemfile
@@ -341,7 +341,6 @@ group :metrics do
 
   # Prometheus
   gem 'prometheus-client-mmap', '~> 0.12.0'
-  gem 'raindrops', '~> 0.18'
 end
 
 group :development do
diff --git a/Gemfile.lock b/Gemfile.lock
index fcf5acf6c29ebc2f41a31e76b6994ba01dc41687..6b0c9222858af546fb50560b640d74edfde3e0b2 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -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)
diff --git a/changelogs/unreleased/330402-remove-unicorn-gitlab-unicorn-sampler.yml b/changelogs/unreleased/330402-remove-unicorn-gitlab-unicorn-sampler.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1773ea98cab3df29e6c4a68a44b5bbe6aa058710
--- /dev/null
+++ b/changelogs/unreleased/330402-remove-unicorn-gitlab-unicorn-sampler.yml
@@ -0,0 +1,5 @@
+---
+title: Remove Unicorn Sampler
+merge_request: 62090
+author:
+type: removed
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index aee9dd455af1cdcab7d61c697d2e859d1f52c6e8..81eb98783766cd0d9adeadc7e1b2ae51382a0288 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -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
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 8d5e19afc20c31e932c42ae2587544cc872e938e..c00d0c04e5f36a011f29d1a8327c12e814d8e66a 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -902,7 +902,6 @@
 #
 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
diff --git a/config/initializers/7_prometheus_metrics.rb b/config/initializers/7_prometheus_metrics.rb
index a304f861db8fb77a8a19d8103144ebba5f318c89..35acf26c796b4ca617bfe1b39fc814311e2bfb78 100644
--- a/config/initializers/7_prometheus_metrics.rb
+++ b/config/initializers/7_prometheus_metrics.rb
@@ -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 @@ def prometheus_default_multiproc_dir
 
     ::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
 
diff --git a/doc/administration/monitoring/performance/index.md b/doc/administration/monitoring/performance/index.md
index 15c54a36f6c984330ebe563c24179078d6c83d68..f3db6ac9f032f5078367c114317b8b626e831d15 100644
--- a/doc/administration/monitoring/performance/index.md
+++ b/doc/administration/monitoring/performance/index.md
@@ -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`
diff --git a/doc/administration/monitoring/prometheus/gitlab_metrics.md b/doc/administration/monitoring/prometheus/gitlab_metrics.md
index f29db9ead389df8e10f17ecdb78fb17d042d3ebf..faa24e76a0e1fb5235c63d05c25407495541b862 100644
--- a/doc/administration/monitoring/prometheus/gitlab_metrics.md
+++ b/doc/administration/monitoring/prometheus/gitlab_metrics.md
@@ -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`.
diff --git a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
index 588be73e7866411803cfe6f851870d7ce599e7c9..dfa17b4e85d622ad5ea0c59c803b6be487c04b30 100644
--- a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
+++ b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
@@ -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
diff --git a/lib/gitlab/metrics/samplers/unicorn_sampler.rb b/lib/gitlab/metrics/samplers/unicorn_sampler.rb
deleted file mode 100644
index 2fa324f3feab5e0933091ce760431943846df97a..0000000000000000000000000000000000000000
--- a/lib/gitlab/metrics/samplers/unicorn_sampler.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-# 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
diff --git a/spec/lib/gitlab/metrics/samplers/unicorn_sampler_spec.rb b/spec/lib/gitlab/metrics/samplers/unicorn_sampler_spec.rb
deleted file mode 100644
index 7971a7cabd5313977c3e8f0dc57a5ccf85e64b17..0000000000000000000000000000000000000000
--- a/spec/lib/gitlab/metrics/samplers/unicorn_sampler_spec.rb
+++ /dev/null
@@ -1,141 +0,0 @@
-# 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