Beiträge von ronald drunk

    Das mtasa:// URL-Schema unterstützt auch Passwort und Nickname und kann als Startparameter verwendet werden.

    D.h. ein Aufruf von

    Code
    "C:\Program Files (x86)\MTA San Andreas 1.5\Multi Theft Auto.exe" mtasa://Guenther:[email protected]:22003

    ...verbindet dich mit dem Server 127.0.0.1 auf Port 22003 als Spieler Guenther mit dem Passwort secretpw.

    MySQL Logs sollten von der Performance um einiges besser sein. Quelle: @ronald drunk

    Zur Erklärung: Es geht nicht unbedingt darum, dass MySQL Zugriffe an sich schneller sein könnten. Ob sie das in der Praxis sind oder nicht hängt von verschiedenen Faktoren ab (Datenbankeinstellungen, werden Indexe erstellt? usw.).
    Der Grund, warum MySQL für MTA manchmal besser ist, ist, dass MTA für die Datenbankoperationen asynchrone Funktionen bereitstellt. D.h., dass beim Aufruf von dbExec/dbQuery nicht sofort geschrieben wird und die Scriptausführung währenddessen hängt, sondern es wird nur der Befehl zum Speichern gegeben, der dann parallel von einem anderen Thread ausgeführt wird.

    Daraus lassen sich 2 Dinge folgern:
    1) Für die Scriptausführung ist die Schreiboperation damit quasi kostenlos, weil sie nur den Befehl zum Schreiben gibt statt selbst zu schreiben.
    2) Wenn die Scriptausführung unmittelbar nach dem Logaufruf crasht, wird der Logeintrag u.U. nicht erstellt.

    Durch diese Methode wird ebenfalls verhindert das bei gleichzeitigen Zugriffen, sich die Dateien gegenseitig überschreiben
    [...]
    File in Buffer laden ---> Bearbeiten ---> überschreiben der File

    Das stimmt so nicht ganz. Es ist zwar richtig, dass Dateien gepuffert werden, um Lese-/Schreibzugriffe auf die langsame Festplatte zu reduzieren. Dass gegenseitig etwas überschrieben wird, passiert aber nur, wenn dein Programm selbst größere Teile der Datei einliest und den Inhalt dann wieder als ganzes schreibt. Wenn du vor jedem Schreiben an das Ende der Datei springst und dann schreibst (wie es bei Logging üblich ist), wird der Inhalt nicht überschrieben. Das sicherzustellen wird dabei vom Betriebssystem geregelt (das Betriebssystem weiß ja welche Dateien in welchem Puffer gespeichert sind und kann somit anwendungsübergreifend die Puffer entsprechend aktualisieren). (Der einzige Präzedenzfall wäre hier wenn zwischen dem Verschieben des Zeigers und dem Schreiben ein anderes Programm schreiben würde. Da in diesem Fall aber höchstwahrscheinlich nur MTA die Datei zum Schreiben geöffnet hat, sollte das kein Problem sein.)

    Fazit
    Eine allgemeine perfekte Lösung gibt es nicht. Je nach Grad an nötiger Datensicherheit und Zugriffshäufigkeit sollte man für den Einzelfall abwägen.
    Es macht z.B. Sinn Informationen, die zur Diagnose eines Absturzes notwendig sind, synchron auf die Festplatte in eine Datei zu schreiben, um sicherzustellen, dass sie dann auch wirklich da sind. Dahingegen ist es bei den meisten "Spielerlogs" (e.g. Spieler hat Aktion X ausgeführt) nicht schlimm, wenn mal ein paar Logeinträge verschwinden. Da diese oftmals auch in höherer Anzahl auftreten, wäre hier folglich eine schnellere, ggf. asynchrone Variante weitaus sinnvoller.
    Da MTA bisher keine asynchronen Dateifunktionen hat, ist hier die MySQL Datenbank eine gute Alternative und ermöglicht gleichzeitig schnelle Suchen und Filterung in den Daten.

    Ich frage mich nur ob das bei einer kleinen Anzahl (2-3) an Entwicklern Sinn macht solch eine Infrastruktur aufzubauen.

    Bei einem einzelnen Entwickler könnte man sich vielleicht darüber streiten, aber bei spätestens 2 Entwicklern bin ich der Meinung, dass es sich schon nach kurzer Zeit rechnet. Und da die meisten etwas professionelleren Teams sowieso Versionskontrolle z.B. via Git verwenden und über einen dedizierten/virtuellen Server verfügen, ist die nötige Infrastruktur zu einem Großteil sowieso schon da.

    Wie lange habt ihr denn fürs Einrichten gebraucht?

    Für das Entwickeln der Tools und Beheben der Bugs (z.B. hatten wir am Anfang etwas Probleme mit dem sauberen Herunterfahren des Servers) sind schon einige Stunden draufgegangen. Wenn wir aber vom reinen Einrichten sprechen, sollte sich das Ganze für ein anderes Projekt an einem Abend einrichten lassen.

    Hallo Leute,

    in diesem Tutorial möchte ich euch vorstellen wie die Release-Pipeline, die ich zusammen mit dem eXo-Team für ihren Server entworfen habe, funktioniert.
    Dieses Tutorial ist eindeutig an fortgeschrittene Nutzer gerichtet und ist keine Schritt-für-Schritt Anleitung, sondern soll vielmehr einen Anreiz geben, die eigene Release-Pipeline ähnlich aufzubauen (alles andere würde außerdem den Rahmen eines einzelnen Tutorials deutlich sprengen).
    Davon abgesehen lässt sich das vorgestellte Konzept nicht sinnvoll einsetzen und den eigenen Bedürfnissen anpassen, wenn man die einzelnen Schritte nicht versteht. Es ist also in jedem Fall notwendig sich mit den verwendeten Tools zu beschäftigen.

    Damit ihr das Tutorial versteht, solltet ihr zumindest folgende Vorkenntnisse mitbringen:

    • Git-Grundkenntnisse
    • Linux-Grundkenntnisse
    • zumindest schonmal was von Docker gehört haben

    Tools und Codebeispiele, die in diesem Zusammenhang entstanden sind, habe ich z.T. hier hochgeladen: https://github.com/Jusonex/mtasa-deployment-tools

    Motivation
    Dieses Tutorial richtet sich auch an die, die bisher ihr Script per FTP auf ihren Server laden und das Script per Dropbox oder Skype zwischen den Teammitgliedern synchronisieren.
    Dieser "Ablauf" bringt mehrere Probleme mit sich:

    • Das Synchronisieren per Dropbox/Skype führt sehr leicht zu Konflikten und nicht selten zu einer komplett kaputten Codebasis, die nur nach viel Anstrengung wiederhergestellt werden kann. Die Lösung dafür ist ein Versionskontrollsystem - in unserem Fall Git. Um Versionskontrolle soll es in diesem Tutorial jedoch nicht gehen (es sei hier auf jede Menge gute Git Tutorials im Internet verwiesen - z.B. Git Cheatsheet).
    • Wenn das Script zusätzlich kompiliert werden soll oder weitere Schritte bis zum Release notwendig sind, steigt die Komplexität ungemein. Dementsprechend wäre der Ablauf üblicherweise: Lokal mit einem Tool kompilieren (sei es direkt per luac oder über grafische/batched Tools) und anschließend per FTP o.ä. auf den Server hochladen.

    Schnell stellt man fest, dass dieser Ablauf überhaupt nicht skaliert. Wenn einmal im Monat ein Update releast wird, mag das mit mehrminütigen Downtimes vielleicht (oder auch nicht ;) ) funktionieren.
    Wenn nicht, kann es schonmal eine Weile dauern, bis die Ursache des Problems gefunden und ausgemerzt wurde.
    Wenn man aber nun nicht 1x pro Woche, sondern im Extremfall 1x pro Stunde updaten möchte (z.B. für einen Testserver, der ebenfalls alle "Release-Schritte" durchlaufen muss, endet man mit sehr viel Aufwand
    und gleichzeitig einer hohen Anfälligkeit für Fehler).

    Daraus lässt sich eigentlich nur eines folgern: Wir müssen diese Schritte automatisieren.

    Anforderungen
    Darüber hinaus gab es ein paar weitere Anforderungen, die bei eXo eingehalten werden sollten:

    • Integration mit GitLab
    • verschiedene Release-Stufen:

      • Produktivserver (Hauptserver): Wird langfristig alle 1-2 Wochen geupdatet
      • Testserver: Server für jeweils kommendes Update, das vom Team auf Fehler getestet werden muss (dieser Stand wird dann 1:1 zum Produktivserver)
      • Devserver: Server, auf dem die aktuelle Version aus dem Git-Repositories (Entwicklungsbranch) läuft
    • vollautomatisch und zentral gesteuert (niemand will lokal extra ein Script ausführen, um die "Release-Schritte" zu starten)
    • portable Server: Die Server sollen nicht an eine bestimmte Betriebssystemkonfiguration gebunden sein, sodass Server innerhalb weniger Minuten auf andere dedizierte Server umgezogen werden könnten
    • Upload der Assets (Bilder, Soundeffekte, Musik, Modelle etc.) via HTTP auf einen externen Webserver (zur Lastverteilung der Downloads und damit Entlastung des MTA-Servers bei vielen gleichzeitigen Connects)
    • Steuerung des MTA-Servers über ein Webinterface (mit Funktionen Start/Stopp/Restart/Logs live einsehen/Befehle ausführen)
    • MTA-Server überwachen (z.B. bei Crash automatisch neustarten)

    Implementierung

    In diesem Abschnitt möchte ich nun für jeden der oben genannten Punkte aufzeigen wie wir sie schließlich umgesetzt haben:

    1) Integration mit GitLab
    Hier lag es auf der Hand GitLab CI zu benutzen. GitLab CI ist das in GitLab integrierte CI (Continous Integration) System (für die, die mit CI nichts anfangen können:
    Grob umschrieben bedeutet das, dass nach jedem Commit das Projekt kompiliert und Tests ausgeführt werden, um Fehler frühzeitig zu erkennen und zu beheben).
    Wenn GitHub genutzt wird, bietet sich z.B. TravisCI an (Tipp: https://education.github.com/pack) - ansonsten geht aber auch fast jede andere CI-Lösung.

    GitLab CI hat insbesondere den Vorteil, dass es sich nahtlos in GitLab integriert.
    Auf dem Bild sieht man die grünen Häkchen, die durch Gitlab CI in die Commitliste kommen. Grünes Häkchen bedeutet dabei: Der Buildprozess (Kompilieren des Gamemodes + Packen der Assets + Hochladen)
    war erfolgreich. Rotes Häkchen bedeutet, dass bei einem dieser Schritte ein Fehler vorliegt (z.B. Syntaxfehler im Script, der dazu führte, dass das Script nicht kompiliert werden konnte).

    Pro Tipp am Rande: GitLab kann super mit Messengern wie z.B. Slack integriert werden, sodass alle Entwickler eine Benachrichtigung per Chat bekommen, dass ein Problem vorliegt.

    2) Verschiedene Release-Stufen
    Um obige Aufteilung sinnvoll hinzubekommen, muss die Lösung dieses Problems mit der Versionskontrolle (in unserem Fall also Git) gefunden werden.
    Dazu wird eine etwas reduzierte Variante von Git Flow eingesetzt.

    Das bedeutet: Es gibt für jede Release-Stufe einen Git-Branch:

    • release/production für den Releaseserver: In diesen Branch wird von release/testing gemerged, wenn ein neues Update releaset werden soll
    • release/testing für den Testserver: Hier werden die annährend stabilen Änderungen aus dem Entwicklungsbranch gemerged, wenn das kommende Update getestet werden soll
    • develop bzw. master: Hier finden alle Änderungen statt

    Ganz am Rande: Featurebranches kommen für neue Features ebenfalls zum Einsatz, sind jedoch für die Release-Pipeline nicht relevant.

    3) Vollautomatisch, zentral und portabel
    Ein Teil von 'vollautomatisch' und 'zentral' haben wir durch das Kompilieren durch GitLab CI schon abgedeckt. Fehlt also nur noch der Upload auf den tatsächlichen Server bei gleichzeitiger Portabilität.

    Beim Punkt "Portabilität" haben wir uns entschieden diese mit Docker umzusetzen. Docker ist grob eine Möglichkeit Anwendungen mit einem mehr oder weniger komplett fertig installierten Betriebssystem als Abbild auszuliefern, welches dann in einer Art virtuellen Maschine läuft. Das hat den wesentlichen Vorteil, dass man sich nicht mehr manuell um die Einrichtung des Systems (z.B. Installation der Abhängigkeiten wie z.B. fehlende Bibliotheken wie libmysqlclient.so.16 oder der Einrichtung der acl.xml) kümmern muss.
    Dabei ist zu beachten, dass es sich bei "Docker-VMs" nicht wirklich um vollvirtualisierte Maschinen handelt (die verhältnismäßig langsam sind), sondern um sogenannte Containervirtualisierung, welche im
    Unterschied zu einer Vollvirtualisierung Features des Linux-Kernels nutzt, um Container auf demselben Linux-Kernel laufen zu lassen, aber in einer isolierten Umgebung.

    Docker Images werden mit sog. Dockerfiles beschrieben und müssen daher ebenfalls "kompiliert" werden (was im Wesentlichen alle Installationsschritte automatisiert ablaufen lässt und dann in eine Binärdatei schreibt, die irgendwo (z.B. DockerHub) hochgeladen wird).

    Um das Ganze noch portabler zu machen, legen wir nicht nur den MTA-Server an sich in das Docker-Image, sondern das kompilierte Script mitsamt aller Configfiles (mtaserver.conf, acl.xml etc) gleich mit.
    Das bedeutet aber auch, dass wir das Docker-Image bei jeder Änderung am Script (also bei jedem Commit) ebenfalls mit erstellen müssen.
    Kein Problem - da kann uns Gitlab CI weiterhelfen.

    Bleibt also für diesen Aspekt nur noch der Upload auf den Releaseserver. Dieser Schritt ist etwas tricky, denn die einzige sinnvolle Möglichkeit von GitLab aus irgendwelche externen Ereignisse
    auszulösen ist über den Aufruf eines Webhooks, welches eigentlich nur ein HTTP-Request an einen bestimmten Server ist. Dieser Schritt kann relativ leicht über einen Aufruf des
    Linux-Kommandozeilentools curl realisiert werden.
    Problem ist aber jetzt folgendes: Der Docker-Dienst auf dem Server, über den die Container auf Basis des gerade erstellten Images gestartet werden, kann nur mit root-Rechten gesteuert werden.
    Einen HTTP-Server mit root-Rechten laufen zu lassen wäre jedoch äußerst fahrlässig, da ein Angreifer, der den HTTP-Server übernimmt, dann volle Kontrolle über das System hätte.
    Ein PHP-Script mit Zugangsdaten für den root-Nutzer ist besser, wirkt aber auch eher wie ein Hack.

    Das führt uns zu einem Tool, das ich für diesen Zweck entwickelt habe (https://github.com/Jusonex/deployron). Die Idee dahinter ist recht simpel: Wir haben 2 Dienste:
    Der eine Dienst ist ein HTTP-Server, der auf Anfragen von GitLab wartet und mit normalen Benutzerrechten läuft und ein Dienst, der mit root-Rechten läuft. Diese beiden Dienste sind dann über einen
    Unix-Socket verbunden sind (Möglichkeit zum Datenaustausch zwischen Prozessen), der aber nur auf den Befehl "starte Script für Deployment X" reagiert. Alle weiteren Informationen werden dann
    aus einer Configdatei (siehe GitHub-Repository) ausgelesen.
    In dieser Konfigurationsdatei können wir den Benutzer, der das Script ausführen soll (in unserem Falle also 'root') angegeben. Das Script dazu holt dann per docker pull unserer gerade
    erstelltes Image herunter und führt dann den Befehl docker run ... aus und erstellt so unseren Container.

    Damit sind wir nun bei folgender Pipeline angekommen:

    "Setup Env" führt dabei einige Initialisierungsschritte aus (z.B. prüft es, ob alle Abhängigkeiten aktuell sind) und "Clean Env" bereinigt erstellte Dateien (löscht z.B. das Docker-Image direkt wieder,
    da es im Deploy-Schritt schon hochgeladen wurde)

    4) Upload der Assets
    Dieser Schritt ist relativ analog zum vorherigen realisiert. Hier benutzen wir wieder curl, laden aber dieses Mal direkt das Archiv hoch.

    5) Steuerung des MTA-Servers über ein Webinterface und MTA-Server überwachen
    In diesen Schritt mussten wir ebenso etwas mehr Aufwand investieren. Denn bisher haben wir zwar den MTA-Server erfolgreich starten können, haben aber keine Möglichkeit diesen im Nachhinein zu steuern oder zu überwachen. Die Docker API ist zwar durchaus umfangreich, schränkt uns aber an ein paar Stellen - insbesondere den MTA-spezifischen - zu sehr ein.
    Die Lösung war dann ein kleines Programm, das nochmal vor den MTA-Server geschaltet wird und diesen dann kontrolliert.
    Zur Steuerung stellt es dann eine REST-API bereit, die folgende Funktionen besitzt:

    • Start/Stop/Restart
    • Logs einsehen (um Größe zu reduzieren, werden hier nur die letzten 10000(?) Zeilen zurückgegeben)
    • Befehle ausführen
    • Status abfragen
    • Ressourcen ersetzen (für schnelles Hochladen zum erleichterten Debuggen)

    Der Vorteil dieser REST-API ist vor allem, dass sie durch jedes beliebige Programm, das einen HTTP-Client hat, benutzt werden kann.
    So ist auf dem Weg zu einem umfangreicheren Monitoring-CP als Zwischenziel folgendes CP durch das eXo-Team entstanden:

    Dieses konnte mit relativ wenigen Zeilen PHP-Code realisiert werden.

    Damit haben wir schließlich alle Anforderungen abgedeckt :)

    Literaturverweise
    Hier schließlich noch eine kurze Auflistung zur Dokumentation der Tools, die verwendet werden:

    Ich hoffe ich konnte euch dazu motivieren die eigene Release-Pipeline ähnlich oder sogar noch besser aufzubauen. Für Verbesserungsvorschläge oder konkrete Fragen habe ich stets ein offenes Ohr - also einfach hier im Thread fragen (oder bei sehr speziellen Fragen eine PN schicken).

    Viele Grüße

    [mtex](u-3)^2 = (u + 5)(u - 5) + 2 \\\Leftrightarrow u^2 - 6u + 9 = u^2 - 5^2 + 2 \\\Leftrightarrow -6u = -25 + 2 - 9 = -32 \\\Leftrightarrow u = \frac{32}{6} = \frac{16}{3}[/mtex]

    Zur Erklärung:
    2. Zeile: Links 2. binomische Formel anwenden, rechts 3. binomische Formel
    3. Zeile: u^2 auf beiden Seiten streichen, +9 auf die andere Seite
    4. Zeile: Durch -6 teilen

    Wäre es denn möglich einfach ein zweites externes Netzteil an die Grafikkarte anzuschließen?

    Möglich schon, dann müsstest du dir nur irgendwas bauen, um das Netzteil einzuschalten.

    Allgemein glaube ich aber nicht, dass dieser Adapter wirklich funktioniert - und schon gar nicht für 6€. Vielleicht klappt es mit einer einfachen Modemkarte, aber nicht bei einer Highend-Grafikkarte, die pro Sekunde hunderte Megabyte an Daten zu übertragen hat.

    Wenn man mal rein die Spezifikation von PCIe mit der von USB 3.0 vergleicht, findet man heraus, dass PCI3 3.0 mit 16 Lanes 15754 MB/s übertragen kann, während USB 3.0 gerade mal auf 300 MB/s dotiert ist (https://de.wikipedia.org/wiki/PCI_Express + https://de.wikipedia.org/wiki/Universal…_Bus#Datenraten).

    Von daher ist es schon per Definition unmöglich einen aktuellen PCIe-Standard vollständig mit USB abzudecken.

    Davon abgesehen sieht die Artikelbeschreibung aufgrund der Vielzahl an Übersetzungsfehlern mehr als unseriös aus.

    Dementsprechend: Lass deine Finger davon und investiere das Geld lieber in einen richtigen PC.

    EDIT:

    Auf dem Bild sieht man, dass nur 4(?) Lanes überhaupt verbunden sind. Für alles andere bräuchte man auch viel mehr Logik auf dem Adapter selbst (dort ist bis auf einen Spannungsregler und ein paar Kondensatoren nichts).
    Selbst wenn man also annehme, dass die Grafikkarte irgendwie auf mysteriöse Weise per USB kommunizieren kann, könnte man selbst dann nur 4 Lanes benutzen.

    Das Problem ist, dass die Methode von diesem Programm, um das gerenderte Bild abzugreifen mit MTA so nicht kompatibel ist.

    Wenn du auf der neusten Version bist, kannst du die betroffene Datei (action_x86.dll) mal auf https://upload.mtasa.com hochladen oder hier im Post anhängen, sodass ich oder jemand anderes sich das Problem genauer angucken kann.
    Ansonsten bleibt dir nur die Möglichkeit auf ein anderes Programm zu wechseln (ShadowPlay, Fraps und OBS funktionieren auf jeden Fall)