OpenSim Services and Service Connectors/de

From OpenSimulator
Jump to navigationJump to search


Einführung in OpenSimulator Services und Service Connectors

Das OpenSimulator-Framework wird für so viele Menschen zu so vielen Dingen, dass es den Punkt erreicht hat, an dem die ursprüngliche Architektur der Software selbst, die weitgehend von den Vorgaben des SL-Clients und dem Linden Lab-Grid inspiriert ist, den Fortschritt an all diesen Fronten behindert. Wir müssen die Architektur der Software überdenken, um die Vielfalt der Dinge unterstützen zu können, die Menschen mit OpenSimulator tun möchten, ohne langwierige Designdiskussionen und Verhandlungen führen zu müssen, damit sie "das Richtige" tut, was offensichtlich der Fall ist nicht vorhanden. Für manche ist „das Richtige“ eine Server-Infrastruktur, die eine 100-prozentige Reproduktion von Second Life ist; für andere ist „das Richtige“ eine 3D-Server-Infrastruktur, die zu 100 % mit dem Web kompatibel ist; für andere ist „das Richtige“ ein Desktop-3D-Simulator;

Dieser Vorschlag kommt in der Folge eines E-Mail-Threads auf der -dev-Mailingliste: https://lists.berlios.de/pipermail/opensim-dev/2009-April/006325.html Die allgemeinen Ideen hier ähneln denen bereits darin Ort für die Verwendung von Datenbank- und Physik-Engines. Bei diesem Vorschlag geht es darum, diese allgemeinen Ideen auf alle Ressourcendienste auszudehnen, was die zusätzliche Schwierigkeit mit sich bringt, sich mit Dienstplatzierung und Dienstzusammensetzung befassen zu müssen.

Vorschlagende: Diva und Melanie

Closing date: 5/28/09

Zusammenfassung

Wir schlagen eine neue Softwarearchitektur vor , die problemlos alle Systemarchitekturen aufnehmen kann , die Menschen aufbauen möchten. Die Grundkonzepte dieser neuen Softwarearchitektur sind (1) Dienstschnittstellen; (2) Serviceanschlüsse; (3) Dienstimplementierungen; und (4) Server-Shells. Dienstimplementierungen sind Codeteile, die in eine Server-Shell geladen werden können, zusammen mit ihren „in“-Dienstkonnektoren, die Dienstanforderungen von Clients empfangen. Clients greifen über Dienstschnittstellen auf Dienste zu und indem sie die entsprechenden "Ausgangs"-Dienstkonnektoren laden, die Anforderungen an die Dienstimplementierungen senden. Die obige Abbildung veranschaulicht das allgemeine Konzept.

Ein Dienst ist die Sammlung seiner Implementierung und seiner Konnektoren und gehorcht einer bestimmten Dienstschnittstelle. Die Personen, die den Dienst implementieren, implementieren auch seine Konnektoren. Daher sind die Details des Protokolls zwischen der Clientseite und der Serverseite für die Dienstclients unsichtbar, die nur von der Dienstschnittstelle wissen. Solange die Schnittstelle erhalten bleibt, ist das Wechseln von Dienstimplementierungen eine triviale Angelegenheit, da der Out-Connector im Client ersetzt wird. Die Spezifikation all dieser Elemente erfolgt zum Zeitpunkt der Initialisierung, indem die angegebenen DLLs geladen und/oder eine generische Plugin-Infrastruktur verwendet werden.

Vorteile

Die folgende Abbildung zeigt 4 verschiedene Systemarchitekturen, die einfach konfiguriert werden können, wenn die vorgeschlagene Softwarearchitektur vorhanden ist.

Beachten Sie, dass dies nur 4 aus einer Vielzahl von Kombinationen sind.

Die Vorteile dieser Softwarearchitektur sind die folgenden:

Wir entfernen uns von den aktuellen booleschen Architekturoptionen, die durch die Variable "gridmode=true|false" gegeben sind, und hin zu einem Modell, bei dem Simulatoren in einer Vielzahl von Hybridmodi konfiguriert werden können.

Das dynamische Laden von Dienstkonnektoren in den Simulator ermöglicht eine Vielzahl von Protokollen „on-the-wire“ zwischen dem Simulator und den Diensten, ohne dass der Simulatorcode geändert werden muss. (Solange diese Dienstimplementierung die etablierte Dienstschnittstelle dafür berücksichtigen kann)

[Ergänzung des vorherigen] Alle Diskussionen über Simulator-Service-Protokolle (HTTP vs. XMLRPC vs. ...) werden für das OpenSimulator-Framework selbst irrelevant. Opensim wird weiterhin einige Dienstimplementierungen und ihre Konnektoren out-of-the-box bereitstellen, aber jeder kann diese durch seine eigenen ersetzen, ohne Änderungen am Quellcode des Simulators vornehmen zu müssen, indem er die entsprechende Konnektor-DLL zur Verfügung stellt die Simulatoren.

Alle OpenSimulator-Server werden zu Server-Shells des gleichen Typs. Das heißt, sie werden alle über den .ini-Mechanismus konfiguriert und können alle Dienste und Dienstconnectors ausführen. Daher wird es auch trivialerweise möglich, Systemarchitekturen zu haben, bei denen ein Ressourcendienst einen anderen Ressourcendienst direkt verwendet. Beispielsweise kann der Inventarserver den Asset-Server verwenden, um Betrachtern eine kombinierte IInventoryService+IAssetService-Schnittstelle bereitzustellen.


Implementierung der vorgeschlagenen Softwarearchitektur

Die Umsetzung wird am Beispiel des Asset Service verdeutlicht. Hier ist die Übersicht der neuen Organisation. Die Kästchen hier bezeichnen ungefähr DLLs. Beachten Sie, dass sich dies noch im Aufbau befindet und dass sich Teile dieser Organisation und des Vokabulars ändern können.

OpenSim/
  Region/
    CoreModules/
      ServiceConnectors/
       (place to put all OUT service connectors from the simulator)
        Asset/
          HGAssetBroker.cs
          LocalssetServiceConnector.cs
          RemoteAssetServiceConnector.cs
        Grid/
          ...
        Interregion/
          ...
        Inventory/
          ...
        Messaging/
          ...
        User/ 
          ...
    Server/
      ServerMain.cs (the server shell, produces OpemSim.Services.exe)
      Base/
        (Base and basic classes for the HTTP server, one DLL)
        HttpServerBase.cs
        ServerUtils.cs
        ServicesServerBase.cs
      Handlers/
         (place to put all IN connectors and network service handlers)
         Asset/
           AssetServerConnector.cs
           AssetServerDeleteHandler.cs
           AssetServerGetHandler.cs
           AssetServerPostHandler.cs
         ...
         Base/
           (Base and basic classes for IN connectors)
           ServerConnector.cs
    Services/
      (service implementations, each on its own dll)
       AssetService/
       Base/
       GridService/
       InventoryService/
       MessagingService/
       UserService/
       (meat of the OUT connectors, one DLL)
       Connectors/
         ...
       (service interfaces, one DLL)
       Interfaces/
         ...



Service-Schnittstellen

OpenSim.Services.Interfaces : Diese DLL enthält alle Dienstschnittstellen, die OpenSimulator bekannt sind.

So sieht IAssetService aus:

    public interface IAssetService
    {
        // Three different ways to retrieve an asset
        //
        AssetBase Get(string id);
        AssetMetadata GetMetadata(string id);
        byte[] GetData(string id);
 
        bool Get(string id, Object sender, AssetRetrieved handler);
 
        // Creates a new asset
        // Returns a random ID if none is passed into it
        //
        string Store(AssetBase asset);
 
        // Attachments and bare scripts need this!!
        //
        bool UpdateContent(string id, byte[] data);
 
        // Kill an asset
        //
        bool Delete(string id);
    }

Connectors

Die Richtung eines Connectors wird durch die Richtung der hergestellten Verbindung bestimmt, nicht durch die Richtung des Datenflusses. Daher ist ein OUT-Connector immer ein Client, während ein IN-Connector immer ein Server ist. Umgekehrt stellt ein OUT-Anschluss eine Schnittstelle bereit, während ein IN-Anschluss eine Schnittstelle verbraucht. Schnittstellen sind über die gesamte Konnektorkette hinweg konsistent, daher können IN-Konnektoren direkt mit OUT-Konnektoren verbunden werden, wodurch ein Proxy-Server erstellt würde.

Out Connectors

OpenSim.Region.CoreModules.ServiceConnectors : Hier hängen alle konkreten OUT-Anschlüsse, die vom Simulator verwendet werden.

OpenSim.Services.Connectors : Hier hängen alle Basisklassen der OUT-Konnektoren. Diese können von anderen Servern als dem Simulator wiederverwendet werden.

Ein OUT-Anschluss legt in erster Linie seine Schnittstellen offen, er kann eine sekundäre Schnittstelle haben, um als Regionsmodul geladen werden zu können. Hier ist ein Ausschnitt des RemoteAssetServiceConnector, der, wie der Name schon sagt, eine Verbindung zu einem Remote-Asset-Server herstellt:

    public class RemoteAssetServicesConnector :
            AssetServicesConnector, ISharedRegionModule, IAssetService
    {
 
        private bool m_Enabled = false;
        private IImprovedAssetCache m_Cache;
 
        public string Name
        {
            get { return "RemoteAssetServicesConnector"; }
        }
 
        public override void Initialise(IConfigSource source)
        {
            IConfig moduleConfig = source.Configs["Modules"];
            if (moduleConfig != null)
            {
                string name = moduleConfig.GetString("AssetServices", "");
                if (name == Name)
                {
                    IConfig assetConfig = source.Configs["AssetService"];
                    if (assetConfig == null)
                    {
                        m_log.Error("[ASSET CONNECTOR]: AssetService missing from OpenSim.ini");
                        return;
                    }
                    m_Enabled = true;
                    base.Initialise(source);
                    m_log.Info("[ASSET CONNECTOR]: Remote assets enabled");
                }
            }
        }
 
        public void AddRegion(Scene scene)
        {
            if (!m_Enabled)
                return;
            scene.RegisterModuleInterface<IAssetService>(this);
        }
        ...
     }

Der obige Code ist nur das Regionsmodul, das abhängig von Konfigurationsvariablen (weiter unten beschrieben) aktiviert ist oder nicht. Zwei Dinge sind bemerkenswert:

Dieses Modul registriert sich bei Scene als IAssetService des Simulators. Mit anderen Worten, dieses Modul ist der direkte Anbieter dieser Schnittstelle innerhalb des Simulators. Alle Asset-Operationen durchlaufen es zuerst.

Diese Klasse erweitert AssetServicesConnector, die Klasse, die das „Fleisch“ des Dienstes enthält. Ein kleiner Teil davon wird im Folgenden vorgestellt:


    public class AssetServicesConnector : IAssetService
    {
        private string m_ServerURI = String.Empty;
        private IImprovedAssetCache m_Cache = null;

        public AssetServicesConnector(string serverURI)
        {
            m_ServerURI = serverURI;
        }

        public AssetServicesConnector(IConfigSource source)
        {
            Initialise(source);
        }

        public virtual void Initialise(IConfigSource source)
        {
            IConfig assetConfig = source.Configs["AssetService"];
            if (assetConfig == null)
            {
                m_log.Error("[ASSET CONNECTOR]: AssetService missing from OpenSim.ini");
                throw new Exception("Asset connector init error");
            }

            string serviceURI = assetConfig.GetString("AssetServerURI",
                    String.Empty);

            if (serviceURI == String.Empty)
            {
                m_log.Error("[ASSET CONNECTOR]: No Server URI named in section AssetService");
                throw new Exception("Asset connector init error");
            }
            m_ServerURI = serviceURI;
        }

        public AssetBase Get(string id)
        {
            string uri = m_ServerURI + "/assets/" + id;

            AssetBase asset = null;
            if (m_Cache != null)
                asset = m_Cache.Get(id);

            if (asset == null)
            {
                asset = SynchronousRestObjectRequester.
                        MakeRequest<int, AssetBase>("GET", uri, 0);

                if (m_Cache != null)
                    m_Cache.Cache(asset);
            }
            return asset;
        }
        ...
    }

Die obige Klasse ist diejenige, die tatsächlich den Verweis auf den Remote-Server als URL enthält und die Remote-Aufrufe an ihn durchführt.

Neben diesem Konnektor können derzeit 2 weitere verwendet werden: LocalAssetServiceConnector und HGAssetBroker. Ersteres soll verwendet werden, wenn der Dienst innerhalb des Simulatorprozesses ausgeführt wird; Letzteres soll für Hypergrid-Simulatoren verwendet werden.

In Connectors

OpenSim.Server.Handlers : In dieser DLL hängen alle IN-Konnektoren ab.

IN-Konnektoren lauschen auf Anfragen und decodieren sie zur Verarbeitung. Sie sind normalerweise an einen HTTP-Server gebunden, obwohl andere Transporte möglich sind. Ein IN-Connector erfasst eine Instanz einer Klasse, die die Zielschnittstelle offenlegt, und sendet alle empfangenen und decodierten Daten an diese Klasse, die ein Verbraucher (Datenbank usw.), ein Forwarder/Broker (HGBroker) oder ein OUT-Connector sein kann würde einen Proxy-Server erstellen. IN-Konnektoren können denselben HTTP-Server gemeinsam nutzen, sodass alle Dienste in einem einzigen Serverprozess enthalten oder auf mehrere Prozesse oder Hosts aufgeteilt werden können. Die Proxy-Konfiguration ist von besonderem Interesse, da sie Lastausgleich und Weiterleitung von Schreibanforderungen ermöglicht. Beispielsweise ist es in SQL-Clustern möglich, Schreibanfragen an andere Hosts zu leiten als Leseanfragen.

So sieht der IN-Connector für einen Asset-Server aus:

    public class AssetServiceConnector : ServiceConnector
    {
        private IAssetService m_AssetService;

        public AssetServiceConnector(IConfigSource config, IHttpServer server) :
                base(config, server)
        {
            IConfig serverConfig = config.Configs["AssetService"];
            if (serverConfig == null)
                throw new Exception("No section 'Server' in config file");

            string assetService = serverConfig.GetString("LocalServiceModule",
                    String.Empty);

            if (assetService == String.Empty)
                throw new Exception("No AssetService in config file");

            Object[] args = { config };
            m_AssetService =
                    ServerUtils.LoadPlugin<IAssetService>(assetService, args);

            server.AddStreamHandler(new AssetServerGetHandler(m_AssetService));
            server.AddStreamHandler(new AssetServerPostHandler(m_AssetService));
            server.AddStreamHandler(new AssetServerDeleteHandler(m_AssetService));
        }
    }

Zwei bemerkenswerte Dinge über diesen Anschluss:

   Es richtet die Service-Handler auf dem Server ein
   Es lädt eine DLL, die die Dienstimplementierung enthält (endlich!).


Service Implementations

OpenSim.Services.AssetService : die standardmäßige OpenSimulator-Implementierung des Asset-Dienstes. Hier ist ein Ausschnitt:

    public class AssetService : AssetServiceBase, IAssetService
    {
        public AssetService(IConfigSource config) : base(config)
        {
            if (m_AssetLoader != null)
            {
                IConfig assetConfig = config.Configs["AssetService"];
                if (assetConfig == null)
                    throw new Exception("No AssetService configuration");

                string loaderArgs = assetConfig.GetString("AssetLoaderArgs",
                        String.Empty);

                m_log.InfoFormat("[ASSET]: Loading default asset set from {0}", loaderArgs);
                m_AssetLoader.ForEachDefaultXmlAsset(loaderArgs,
                        delegate(AssetBase a)
                        {
                            Store(a);
                        });
                
                m_log.Info("[ASSET CONNECTOR]: Local asset service enabled");
            }
        }

        public AssetBase Get(string id)
        {
            m_log.DebugFormat("[ASSET SERVICE]: Get asset {0}", id);
            UUID assetID;

            if (!UUID.TryParse(id, out assetID))
                return null;

            return m_Database.FetchAsset(assetID);
        }
        ...
     }

Die obige Klasse wird durch den zuvor gezeigten IN-Anschluss geladen.

Server Shells

OpenSim.Services.exe

Es gibt jetzt eine generische Server-Shell, die alle IN-Dienstkonnektoren zusammen mit ihren angegebenen Dienstimplementierungen laden kann. Diese Server-Shell wird mit einer .ini-Datei konfiguriert, die genau dieselben Konfigurationsvariablen verwendet, die sich auf die Asset-Service-Konfiguration in OpenSin.ini beziehen.

Hier ist die neue Server-Shell:

    public class OpenSimServer
    {
        protected static HttpServerBase m_Server = null;

        protected static List<IServiceConnector> m_ServiceConnectors =
                new List<IServiceConnector>();

        static int Main(string[] args)
        {
            m_Server = new HttpServerBase("Asset", args);

            IConfig serverConfig = m_Server.Config.Configs["Startup"];
            if (serverConfig == null)
            {
                System.Console.WriteLine("Startup config section missing in .ini file");
                throw new Exception("Configuration error");
            }

            string connList = serverConfig.GetString("ServiceConnectors", String.Empty);
            string[] conns = connList.Split(new char[] {',', ' '});

            foreach (string conn in conns)
            {
                if (conn == String.Empty)
                    continue;

                string[] parts = conn.Split(new char[] {':'});
                string friendlyName = parts[0];
                if (parts.Length > 1)
                    friendlyName = parts[1];

                m_log.InfoFormat("[SERVER]: Loading {0}", friendlyName);

                Object[] modargs = { m_Server.Config, m_Server.HttpServer };
                IServiceConnector connector =
                        ServerUtils.LoadPlugin<IServiceConnector>(conn,
                        modargs);

                if (connector != null)
                {
                    m_ServiceConnectors.Add(connector);
                    m_log.InfoFormat("[SERVER]: {0} loaded successfully", friendlyName);
                }
                else
                {
                    m_log.InfoFormat("[SERVER]: Failed to load {0}", conn);
                }
            }
            return m_Server.Run();
        }
    }

Im Wesentlichen lädt dieser generische Server alle DLLs für die angegebene ServiceConnectors-Konfigurationsvariable. Daher ist es trivial, mehrere Dienste in einer einzigen Server-Shell zu kombinieren oder mehrere Server-Shells zu haben, auf denen jeweils ein Dienst ausgeführt wird.

Configuration

Diese Architektur teilt alle Dienste und Dienstconnectors in einzelne Regionsmodule und DLLs auf, die dann in den Konfigurationsdateien des Servers angegeben werden. Jeder Server – OpenSim.exe und alle OpenSim.Services.exe – hat seine eigene INI-Datei. Es gibt zwei Möglichkeiten, die Server zu konfigurieren, die im Folgenden beschrieben werden.

Direct Configuration

Die bekannte .ini-Datei hat jetzt mehrere neue Konfigurationsvariablen für jeden Service-Connector. Siehe Konfiguration von Diensten und Dienstkonnektoren für die zusätzlichen Variablen, die sich auf die Konfiguration des Asset-Dienstes in OpenSim.ini beziehen.

Was die Konfiguration eines Ressourcenservers betrifft, hier ist ein Beispiel für einen Asset-Server im neuen Stil von Server-Shells (diese Variablen werden in OpenSim.Services.ini gespeichert).

[Startup]
; These are also available as command line options

; console = "local" ; Use "basic" to use this on a pipe
; inifile = "OpenSim.Servers.AssetServer.ini"
; logfile = "AssetServer.log" ; Also read from application config file

; Connectors, comma separated
ServiceConnectors = "OpenSim.Server.Handlers.dll:AssetServiceConnector"

[Network]
port = 8003

[AssetService]
LocalServiceModule = "OpenSim.Services.AssetService.dll:AssetService"
StorageProvider = "OpenSim.Data.MySQL.dll"
ConnectionString = "Data Source=localhost;Database=opensim;User ID=opensim;Password=opensim;"
DefaultAssetLoader = "OpenSim.Framework.AssetLoader.Filesystem.dll"
AssetLoaderArgs = "assets/AssetSets.xml"

Prepackaged System Architectures

Während die Aufteilung in kleine Designelemente alle Flexibilität bietet, die man aus dem Framework herausholen kann, nimmt die Anzahl der Konfigurationsvariablen erheblich zu und kann schnell überwältigend werden. Um dieses Problem anzugehen, arbeiten wir an Konfigurations-"includes", die es uns ermöglichen, vorgefertigte Systemarchitekturen bereitzustellen, wobei alle neuen Variablen richtig eingerichtet sind, sodass sie Architekturen wie die im obigen Bild erzeugen können.

Es wird drei vorgefertigte Systemarchitekturen geben: StandaloneGrid, StandardGrid und HyperGrid. Benutzer des Frameworks können weitere definieren.

See Also

Change Log

  • Diva, 5/22/09, added suggestions from Justincc @ -dev.