MongoDB

MongoDB ist die führende Open-Source, Document Datenbank die für einfache Entwicklung und Skalierung aber auch für Big Data Szenarien entwickelt wurde.

Tuning von MongoDB & Linux für zehntausende von Verbindungen

Marc-David Militz
Experte
  • Artikel von Henrik Ingo

    • englischer Originalartikel
      https://www.mongodb.com/blog/post/tuning-mongodb--linux-to-allow-for-tens-of-thousands-connections
      Übersetzung mit freundlicher Genehmigung von MongoDB

      "Böse Zungen" (und manche sagen, ich hätte auch so eine) in der IT beschreiben Red Hat (RHEL) gerne als "für die Beratung optimiert". (Implizit sind dies auch Centos und Amazon Linux.) Aus irgendeinem Grund wird RHEL mit Standard-"ulimit" und anderen für Ihren Laptop geeigneten Konfigurationen ausgeliefert. Damit Sie die volle Leistung eines großen Produktionsservers erhalten, müssen sie viel tunen, um verschiedene Limits und Puffer zu erhöhen. Dies schafft einen lukrativen Markt für Berater, die alle Drehknöpfe kennen, die gedreht werden müssen. Vielleicht ist das der Grund warum im Grunde jede Firma, bei der ich bisher das Thema MongoDB mit eingeführt habe, unbedingt auf RHEL setzen wollte.

      Die folgenden Erkenntnisse stammen aus einem Benchmarking, wie sich MongoDB bei einer großen Anzahl von Verbindungen verhält. Um das zu erreichen und um eine große Anzahl von Verbindungen und Threads auf einem Linux-Server zu erstellen, musste an einigen Schrauben gedreht werden.

      • MongoDB Konfiguration

        • Auch MongoDB selbst hat die Möglichkeit, die maximale Anzahl eingehender Verbindungen zu begrenzen. Der Standardwert ist 64 KB.
          https://docs.mongodb.com/manual/reference/configuration-options/#net.maxIncomingConnections
          # mongod.conf
          net:
          maxIncomingConnections: 999999

          Dabei gilt es zu beachten, dass MongoDB standardmäßig einen dedizierten Arbeitsthread für jede eingehende Verbindung erstellt. Um diese Standardeinstellung testen, muss man jedoch darauf hinweisen, dass eine verwandte Einstellung in einem Worker-Pool-Modell geändert werden muss.
          https://docs.mongodb.com/manual/reference/configuration-options/#net.serviceExecutor
          Dies ermöglicht vermutlich eine größere Anzahl eingehender Verbindungen und die Verwendung weniger Threads. Beachten Sie, dass diese Option auch dann als experimentell gekennzeichnet ist, wenn sie offiziell dokumentiert ist:
          net:
          serviceExecutor: adaptive

          Für die Tests werden wir einen Thread pro Verbindung erstellen, daher wurde auch die folgende Konfiguration benötigt ...

          • Linux Konfiguration

            • Um die "ulimits" richtig zu setzen, muss man sich erstmal an alle grundlegenden Unix-Prinzipien erinnern:
              • Alles ist eine Datei. Insbesondere TCP / IP-Verbindungen sind für ulimit offene Dateien.
              • Aus historischen Gründen ist nproc wirklich die Anzahl der Threads. In der Vergangenheit bestand ein Linux-Prozess aus einem einzelnen Thread, und gleichzeitig aus mehreren Prozessen.
              • Threads ordnen Speicher aus dem Stapel zu, der auch eine maximale Größe hat.


                • # Connections are files because in Unix everything is a file.
                  echo "ec2-user soft nofile 9999999" | sudo tee -a /etc/security/limits.conf
                  echo "ec2-user hard nofile 9999999" | sudo tee -a /etc/security/limits.conf
                  # nproc is really number of threads.
                  echo "ec2-user soft nproc 9999999" | sudo tee -a /etc/security/limits.conf
                  echo "ec2-user hard nproc 9999999" | sudo tee -a /etc/security/limits.conf
                  # Threads need memory from the stack.
                  echo "ec2-user soft stack 9999999" | sudo tee -a /etc/security/limits.conf
                  echo "ec2-user hard stack 9999999" | sudo tee -a /etc/security/limits.conf

                  Weitere Informationen finden Sie in der MongoDB-Dokumentation zu den ulimit-Einstellungen.
                  https://docs.mongodb.com/manual/reference/ulimit/#recommended-ulimit-settings

                  Doch einen Augenblick noch, es gibt noch mehr! Das Erstellen von Threads verwendet mmap, um Speicher zuzuweisen.
                  http://man7.org/linux/man-pages/man2/mmap.2.html
                  Und auf der Kernel-Ebene gibt es eine Einstellung für die maximale Anzahl von mmapped Speicherblöcken pro Prozess, die ebenfalls erhöht werden muss:
                  echo 9999999 > /proc/sys/vm/max_map_count
                  # If you want to persist across reboots
                  echo "vm.max_map_count=9999999" | sudo tee -a /etc/sysctl.conf

                  Schließlich wurden, auf dem Benchmark-Client, TCP / IP auf Einschränkungen festgestellt. Im TCP-Protokoll wird ein Socket mit dem Tupel (lokale Adresse, lokaler Port, entfernte Adresse, entfernter Port) identifiziert, und dieses Tupel muss pro Socket eindeutig sein. Die Portnummern reichen von 1 bis 65535, daher kann man von einem einzelnen Benchmark-Client nur 65535 ausgehende Verbindungen erstellen. Um mit mehr Verbindungen zu arbeiten, gibt es nur die Möglichkeit mehr als einen Client-Host oder mindestens mehr als eine IP-Adresse für den Client zu haben. Auf der Serverseite ist der Port natürlich der bekannte mongod Port 27017.

                  Etwas überraschend war die Erkenntnis, dass Linux standardmäßig nicht einmal die gesamte Palette von 65k-Ports nutzen würde, die TCP ermöglicht. Auch das musste konfiguriert werden:
                  echo 1024 65530 > /proc/sys/net/ipv4/ip_local_port_range
                  # If you want to persist across reboots
                  echo "net.ipv4.ip_local_port_range = 1024 65530" | sudo tee -a /etc/sysctl.conf

                  Die beiden Zahlen sind die min. Und max. Werte für ausgehende Ports. Beachten Sie, dass diese Konfiguration auf einem Server NICHT erforderlich ist, sondern nur auf dem Benchmark-Client.

                  • EC2 Konfiguration

                    • Bei AWS gab es erstmal folgende Erkenntnisse: In der M5-Familie von EC2-Instanzen (getestet bis zu m5.2xlarge) lassen sich nur 32k-Verbindungen und -Threads erstellen. Mit genau der gleichen Konfiguration, aber mit dem Wechsel zum Instanztyp c3.8xlarge, ist es möglich mehr als das erstellen und die von "ip_local_port_range" nach oben vorgegebene Grenze von fast 65.000 zu erreichen. Es scheint dazu keine AWS-Dokumentation zu geben, die das bestätigt. Der AWS Support hat dies auch nicht bestätigt. Es könnte also auch ein Fehler in der getesteten Konfiguration sein.

                      • Zusammenfassung

                        • Hier sind also alle Schritte in einem Copy & Paste Skript. Dieses wurde speziell für AWS-Instanzen entwickelt, auf denen Amazon Linux 2 ausgeführt wird. Möglicherweise müssen Sie Anpassungen für andere Linux-Versionen vornehmen. Insbesondere bei Centos und RHEL müssen Sie den Benutzernamen von "ec2-user" in "root" ändern.

                          # This assumes a fresh Linux host from standard Amazon Linux 2 images.
                          # Adaptable to Centos/RHEL too.

                          sudo su

                          sed -i .orig 's/net\:/net\:\n maxIncomingConnections: 999999/' /etc/mongod.conf

                          # Connections are files because in Unix everything is a file.
                          echo "ec2-user soft nofile 9999999" | sudo tee -a /etc/security/limits.conf
                          echo "ec2-user hard nofile 9999999" | sudo tee -a /etc/security/limits.conf
                          # nproc is really number of threads.
                          echo "ec2-user soft nproc 9999999" | sudo tee -a /etc/security/limits.conf
                          echo "ec2-user hard nproc 9999999" | sudo tee -a /etc/security/limits.conf
                          # Threads need memory from the stack.
                          echo "ec2-user soft stack 9999999" | sudo tee -a /etc/security/limits.conf
                          echo "ec2-user hard stack 9999999" | sudo tee -a /etc/security/limits.conf

                          # Threads allocate memory with mmap
                          echo 9999999 > /proc/sys/vm/max_map_count
                          # If you want to persist across reboots
                          echo "vm.max_map_count=9999999" | sudo tee -a /etc/sysctl.conf

                          # Needed for outgoing connections (on client)
                          echo 1024 65530 > /proc/sys/net/ipv4/ip_local_port_range
                          echo "net.ipv4.ip_local_port_range = 1024 65530" | sudo tee -a /etc/sysctl.conf

                          # Checks EC2 instance type but doesn't do anything about it
                          curl http://169.254.169.254/latest/meta-data/instance-type

Neueste Mitgliederaktivitäten

Tags

Diesen Community Beitrag weiterempfehlen