]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 1495741 - memory issues: options to control memory usage
authorDylan William Hardison <dylan@hardison.net>
Tue, 16 Oct 2018 21:33:25 +0000 (17:33 -0400)
committerGitHub <noreply@github.com>
Tue, 16 Oct 2018 21:33:25 +0000 (17:33 -0400)
Bugzilla/Install/Localconfig.pm
Bugzilla/Quantum.pm
Bugzilla/Quantum/Plugin/SizeLimit.pm [new file with mode: 0644]
Makefile.PL
README.rst
conf/checksetup_answers.txt
scripts/c9-install
template/en/default/setup/strings.txt.pl
vagrant_support/checksetup_answers.j2

index 08cd9e80bef80bc39065de0df040a956f47ea27d..4b25b966bdeab3552a8f85d109bd3ea418c58425 100644 (file)
@@ -23,6 +23,7 @@ use Bugzilla::Constants;
 use Bugzilla::Install::Util qw(bin_loc install_string);
 use Bugzilla::Util qw(generate_random_password wrap_hard);
 
+use Mojo::JSON qw(encode_json);
 use Data::Dumper;
 use File::Basename qw(dirname);
 use English qw($EGID);
@@ -148,8 +149,12 @@ use constant LOCALCONFIG_VARS => (
         },
     },
     {
-        name    => 'apache_size_limit',
-        default => 600000,
+        name   => 'setrlimit',
+        default => encode_json({ RLIMIT_AS => 2e9 }),
+    },
+    {
+        name    => 'size_limit',
+        default => 750000,
     },
     {
         name    => 'memcached_servers',
index 7f359830be4c03175af75d92a7cbf0605594d493..927729614e6d736275671938ae123e8281e12e95 100644 (file)
@@ -40,6 +40,8 @@ sub startup {
   $self->plugin('Bugzilla::Quantum::Plugin::Glue');
   $self->plugin('Bugzilla::Quantum::Plugin::Hostage')
     unless $ENV{BUGZILLA_DISABLE_HOSTAGE};
+  $self->plugin('Bugzilla::Quantum::Plugin::SizeLimit')
+    unless $ENV{BUGZILLA_DISABLE_SIZELIMIT};
   $self->plugin('Bugzilla::Quantum::Plugin::BlockIP');
   $self->plugin('Bugzilla::Quantum::Plugin::Helpers');
 
diff --git a/Bugzilla/Quantum/Plugin/SizeLimit.pm b/Bugzilla/Quantum/Plugin/SizeLimit.pm
new file mode 100644 (file)
index 0000000..bd8d264
--- /dev/null
@@ -0,0 +1,77 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::Quantum::Plugin::SizeLimit;
+use 5.10.1;
+use Mojo::Base 'Mojolicious::Plugin';
+use Mojo::JSON qw(decode_json);
+use Bugzilla::Logging;
+
+use constant MIN_SIZE_LIMIT        => 750_000;
+use constant HAVE_LINUX_SMAPS_TINY => eval { require Linux::Smaps::Tiny };
+use constant HAVE_BSD_RESOURCE     => eval { require BSD::Resource };
+
+BEGIN {
+  if (HAVE_LINUX_SMAPS_TINY) {
+    Linux::Smaps::Tiny->import('get_smaps_summary');
+  }
+  if (HAVE_BSD_RESOURCE) {
+    BSD::Resource->import;
+  }
+}
+
+my @RESOURCES = qw(
+  RLIMIT_CPU RLIMIT_FSIZE RLIMIT_DATA RLIMIT_STACK RLIMIT_CORE RLIMIT_RSS RLIMIT_MEMLOCK RLIMIT_NPROC RLIMIT_NOFILE
+  RLIMIT_OFILE RLIMIT_OPEN_MAX RLIMIT_LOCKS RLIMIT_AS RLIMIT_VMEM RLIMIT_PTHREAD RLIMIT_TCACHE RLIMIT_AIO_MEM
+  RLIMIT_AIO_OPS RLIMIT_FREEMEM RLIMIT_NTHR RLIMIT_NPTS RLIMIT_RSESTACK RLIMIT_SBSIZE RLIMIT_SWAP RLIMIT_MSGQUEUE
+  RLIMIT_RTPRIO RLIMIT_RTTIME RLIMIT_SIGPENDING
+);
+
+my %RESOURCE;
+if (HAVE_BSD_RESOURCE) {
+  $RESOURCE{$_} = eval $_ for @RESOURCES;
+}
+
+sub register {
+  my ($self, $app, $conf) = @_;
+
+  if (HAVE_BSD_RESOURCE) {
+    my $setrlimit = decode_json(Bugzilla->localconfig->{setrlimit});
+
+    # This trick means the master process will not a size limit.
+    Mojo::IOLoop->next_tick(sub {
+      foreach my $resource (keys %$setrlimit) {
+        setrlimit($RESOURCE{$resource}, $setrlimit->{$resource}, $setrlimit->{$resource});
+      }
+    });
+  }
+
+  if (HAVE_LINUX_SMAPS_TINY) {
+    my $size_limit = Bugzilla->localconfig->{size_limit};
+    return unless $size_limit;
+
+    if ($size_limit < MIN_SIZE_LIMIT) {
+      WARN(sprintf "size_limit cannot be smaller than %d", MIN_SIZE_LIMIT);
+      $size_limit = MIN_SIZE_LIMIT;
+    }
+
+    $app->hook(
+      after_dispatch => sub {
+        my $c       = shift;
+        my $summary = get_smaps_summary();
+        if ($summary->{Size} >= $size_limit) {
+          my $diff = $summary->{Size} - $size_limit;
+          INFO("memory size exceeded $size_limit by $diff ($summary->{Size})");
+          $c->res->headers->connection('close');
+          Mojo::IOLoop->singleton->stop_gracefully;
+        }
+      }
+    );
+  }
+}
+
+1;
index 27a9e989eff8c466c52cbd1df642722bb042a84f..b73080bea6c746bba6976b6435256365fe4c4d31 100755 (executable)
@@ -300,7 +300,7 @@ my %optional_features = (
   },
   linux_smaps => {
     description => 'Linux::Smaps::Tiny for limiting memory usage',
-    prereqs     => {runtime => {requires => {'Linux::Smaps::Tiny' => '0'}}},
+    prereqs     => {runtime => {requires => {'Linux::Smaps::Tiny' => '0', 'BSD::Resource' => 0}}},
   },
   linux_pdeath => {
     description => 'Linux::Pdeathsig for a good parent/child relationships',
index a857a207d65f150292f22f6804ef4ae0f6f01281..1b556d915f5c5d3a2ef8e2ed7c205eda47231c32 100644 (file)
@@ -362,9 +362,13 @@ BMO_shadowdbhost
 BMO_shadowdbport
    The port of the read-only database.
 
-BMO_apache_size_limit
-  This is the max amount of unshared memory (in kb) that the apache process is
-  allowed to use before Apache::SizeLimit kills it.
+BMO_setrlimit
+    This is a json object and can set any limit described in https://metacpan.org/pod/BSD::Resource.
+    Typically it used for setting RLIMIT_AS, and the default value is ``{ "RLIMIT_AS": 2000000000 }``.
+
+BMO_size_limit
+  This is the max amount of unshared memory the worker processes are allowed to
+  use before they will exit. Minimum 750000 (750MiB)
 
 BMO_mail_delivery_method
   Usually configured on the MTA section of admin interface, but may be set here for testing purposes.
index f5c7559d6c869a36be53a604445020216d8879ac..402039ffc64b72b999e7de821f320cee05770ddb 100644 (file)
@@ -4,7 +4,7 @@ $answer{'ADMIN_PASSWORD'}       = 'vagrant01!';
 $answer{'passwdqc_min'}         = '8, 8, 8, 8, 8';
 $answer{'ADMIN_REALNAME'}       = 'Vagrant User';
 $answer{'NO_PAUSE'}             = 1;
-$answer{'apache_size_limit'}    = 700000;
+$answer{'size_limit'}           = 750000;
 $answer{'bugzilla_version'}     = '1';
 $answer{'create_htaccess'}      = '1';
 $answer{'db_check'}             = 1;
index d5bc537b4cf73dabc3f6e56b4d61f4d848eacf1c..a446e2b8214400c2e35ef3b1d23768a41a7c04a0 100755 (executable)
@@ -35,7 +35,7 @@ $answer{'ADMIN_OK'}             = 'Y';
 $answer{'ADMIN_PASSWORD'}       = 'bmo4c9rocks';
 $answer{'ADMIN_REALNAME'}       = 'BMO Admin';
 $answer{'NO_PAUSE'}             = 1;
-$answer{'apache_size_limit'}    = 700000;
+$answer{'size_limit'}           = 750000;
 $answer{'bugzilla_version'}     = '1';
 $answer{'create_htaccess'}      = '';
 $answer{'diffpath'}             = '/usr/bin';
index cb0ac4fe9bb337f2b3df8a14d8dacd6ed7a52856..f5522aa00269fee0d2ae0d02092b78f81b012eeb 100644 (file)
@@ -272,9 +272,12 @@ and you cannot set this up any other way. YOU HAVE BEEN WARNED!
 If you set this to anything other than "", you will need to run checksetup.pl
 as ##root## or as a user who is a member of the specified group.
 END
-    localconfig_apache_size_limit => <<EOT,
-This is the max amount of unshared memory the apache process is allowed to use
-before Apache::SizeLimit kills it. This is only applicable when run under mod_perl.
+    localconfig_setrlimit => <<EOT,
+This a json object whose keys are the named constants for the setrlimit(1) C library
+function. The default sets RLIMIT_AS to 2GiB.
+EOT
+    localconfig_size_limit => <<EOT,
+This is the max amount of unshared memory the worker processes are allowed to use before they will exit.
 EOT
     localconfig_shadowdb_user => <<EOT,
 The username used to authenticate to the shadow db.
index 0b9c9d3c592dffc902880d4c4e043a635ba36c19..57c84436cd8a1e9ba14e5b5a03bfe82af73d6997 100644 (file)
@@ -4,7 +4,7 @@ $answer{'ADMIN_PASSWORD'}       = 'vagrant01!';
 $answer{'passwdqc_min'}         = '8, 8, 8, 8, 8';
 $answer{'ADMIN_REALNAME'}       = 'Vagrant User';
 $answer{'NO_PAUSE'}             = 1;
-$answer{'apache_size_limit'}    = 700000;
+$answer{'size_limit'}           = 750000;
 $answer{'bugzilla_version'}     = '1';
 $answer{'create_htaccess'}      = '1';
 $answer{'db_check'}             = 1;