Heim >Java >javaLernprogramm >Detaillierte Beispiele des RPC-Frameworks
1. Hintergrund
Mit der Entwicklung des Internets nimmt der Umfang der Website-Anwendungen weiter zu und die herkömmliche vertikale Anwendungsarchitektur kann nicht mehr genutzt werden Eine zentralisierte Servicearchitektur und eine Mobile-Computing-Architektur sind zwingend erforderlich, und ein Governance-System ist dringend erforderlich, um die geordnete Entwicklung der Architektur sicherzustellen
Einzelanwendungsarchitektur
Wenn der Website-Verkehr sehr gering ist, ist nur eine Anwendung erforderlich, um alle Funktionen zusammen bereitzustellen, um Bereitstellungsknoten und Kosten zu reduzieren
Zu diesem Zeitpunkt Daten Der Zugriff wird verwendet, um den Arbeitsaufwand beim Hinzufügen, Löschen, Ändern und Überprüfen zu vereinfachen. Framework (ORM) ist der Schlüssel
Vertikale Anwendungsarchitektur
Wann Die Anzahl der Besuche nimmt allmählich zu und die durch das Hinzufügen von Maschinen zu einer einzelnen Anwendung verursachte Beschleunigung wird immer größer. Je kleiner sie ist, desto mehr wird die Anwendung in mehrere unabhängige Anwendungen aufgeteilt, um die Effizienz zu verbessern
Hierbei Gleichzeitig ist das Web-Framework (MVC), das zur Beschleunigung der Front-End-Seitenentwicklung verwendet wird, der Schlüssel
Verteilte Servicearchitektur
Aufgeteilt nach Geschäftsbereichen
RPC-Missbrauch stoppen, vertikalen Unternehmen Vorrang einräumen Durch lokale JAR-Aufrufe werden RPC-Aufrufe unternehmensübergreifend verwendet
, um den Besitz von richtig zu identifizieren Geschäftslogik, maximieren Sie den Zusammenhalt jedes Moduls und reduzieren Sie die Kopplung in Bezug auf Leistung, Verfügbarkeit und Wartbarkeit
Stellen Sie nur einige Server für jede Version bereit
Jeder Knoten kann je nach Bedarf skaliert und erweitert werden
Aktualisierung, Bereitstellung und Ausführung zwischen den einzelnen Anwendungen haben keinen Einfluss auf
Bereitstellungstrennung
Teamtrennung
Datentrennung
Wann Es gibt immer mehr vertikale Anwendungen, Interaktionen zwischen Anwendungen sind unvermeidlich, und das Kerngeschäft wird als unabhängige Dienste extrahiert, wodurch nach und nach ein stabiles Servicecenter entsteht, das es Front-End-Anwendungen ermöglicht, schneller auf sich ändernde Marktanforderungen zu reagieren
Derzeit wird ein verteiltes Service-Framework verwendet, um die geschäftliche Wiederverwendung und Integration (RPC) zu verbessern.
Distributed Service RPC-Framework
Flow-Computing-Architektur
Wenn es immer mehr Dienste gibt, treten Probleme wie z Da es allmählich zu einer Kapazitätsbewertung und Verschwendung kleiner Serviceressourcen kommt, ist es notwendig, ein Versandzentrum für die Echtzeitverwaltung basierend auf der Zugriffsdruckkapazität hinzuzufügen, um die Clusterauslastung zu verbessern 🎜>Derzeit ist das Ressourcenplanungs- und Governance-Center (SOA) zur Verbesserung der Maschinenauslastung der Schlüssel
Netty-Thread-ModellNettys Threading-Modell basiert hauptsächlich auf React, und hat sich aufgrund unterschiedlicher Anwendungsszenarien zu mehreren Versionen entwickelt.
Das heißt, der Empfang von Dienstanfragen und die Ausführung von E/A-Vorgängen werden alle von einem Thread ausgeführt In kleinen Fällen kann der Single-Threaded-Modus auch einige Szenenprobleme lösen.
Einzelner empfangender Multi-Worker-Thread-ModusWenn die Anzahl der Anforderungen zunimmt, wird der ursprüngliche Thread, der alle E/A-Vorgänge verarbeitet, immer unerträglicher. Entsprechende Leistungsindikatoren, Daher wird das Konzept eines Arbeits-Thread-Pools erwähnt. Zu diesem Zeitpunkt ist der Empfang der Dienstanforderung immer noch ein Thread. Nach dem Empfang der Anforderung wird der Thread, der die Anforderung empfängt, dem nachfolgenden Arbeits-Thread-Pool anvertraut und erhält einen Thread vom Thread Pool zur Ausführung.
Multiple-Empfangs- und Multi-Worker-Thread-ModusWenn das Anforderungsvolumen weiter zunimmt, kann ein einzelner Thread, der Serviceanfragen empfängt, nicht alle Clientverbindungen verarbeiten Der Thread-Pool, der Serviceanfragen empfängt, wird ebenfalls erweitert, und mehrere Threads sind für den gleichzeitigen Empfang von Clientverbindungen verantwortlich.
RPC-GeschäftsthreadBei den oben genannten handelt es sich um Nettys eigenes Thread-Modell, Optimierungsstrategien, die mit der Zunahme des Anfragevolumens kontinuierlich weiterentwickelt wurden. Bei RPC-Anfragen ist die Verarbeitung der Geschäftslogik das Wichtigste für Anwendungssysteme, und diese Art von Geschäft kann rechenintensiv oder IO-intensiv sein. Beispielsweise werden die meisten Anwendungen von Datenbankoperationen, Redis oder anderen Netzwerkdiensten begleitet , usw. Wenn die Geschäftsanforderung solche zeitaufwändigen E/A-Vorgänge enthält, wird empfohlen, die Aufgabe der Verarbeitung der Geschäftsanforderung einem unabhängigen Thread-Pool zuzuweisen, da sonst die eigenen Threads von netty blockiert werden können.
Arbeitsteilung zwischen dem Anforderungsthread und dem Worker-Thread
Der Anforderungsthread ist hauptsächlich für die Erstellung des Links und die anschließende Delegierung der Anforderung an den Worker verantwortlich Thread
Der Arbeitsthread ist für die Kodierung, Dekodierung, das Lesen von E/A und andere Vorgänge verantwortlich
Der RPC Ich verwende derzeit den Multi-Receiver-Multi-Worker-Thread-Modus. Der Port ist auf der Serverseite wie folgt gebunden:
public void bind(ServiceConfig serviceConfig) {EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(this.rpcServerInitializer)
.childOption(ChannelOption.SO_KEEPALIVE,true)
;try {ChannelFuture channelFuture = bootstrap.bind(serviceConfig.getHost(),serviceConfig.getPort()).sync();//...channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {throw new RpcException(e);
}
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
boosGroup ist eine Gruppe, die zum Empfangen verwendet wird Serviceanfragen.
workerGroup ist eine Gruppe, die speziell für IO-Operationen verantwortlich ist.
Um Geschäftsthreads hinzuzufügen, müssen Sie nur den Handle-Vorgang weiter an den Thread-Pool delegieren Definieren Sie hier eine Schnittstelle:
public interface RpcThreadPool {Executor getExecutor(int threadSize,int queues);
}
Verwiesen auf den Dubbo-Thread pool
@Qualifier("fixedRpcThreadPool")@Componentpublic class FixedRpcThreadPool implements RpcThreadPool {private Executor executor;@Overridepublic Executor getExecutor(int threadSize,int queues) {if(null==executor) {synchronized (this) {if(null==executor) {
executor= new ThreadPoolExecutor(threadSize, threadSize, 0L, TimeUnit.MILLISECONDS,
queues == 0 ? new SynchronousQueue<Runnable>() :(queues < 0 ? new LinkedBlockingQueue<Runnable>(): new LinkedBlockingQueue<Runnable>(queues)),new RejectedExecutionHandler() {@Overridepublic void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { //...}
});
}
}
}return executor;
}
}
Kleines Zwischenspiel:
Ich erinnere mich, dass einmal ein Freund plötzlich fragte, was die coreSize im Java-Thread-Pool bedeute? Ich war plötzlich kurzgeschlossen, weil ich normalerweise kein Multithreading schreibe. Wenn ich an den Datenbank-Thread-Pool denke, den ich normalerweise häufig verwende, bin ich von den darin enthaltenen Parametern ziemlich beeindruckt, kann mich aber einfach nicht erinnern coreSize. Später habe ich mir einige Parameter des Thread-Pools genauer angesehen. Jetzt kann ich die Gelegenheit nutzen, genauer hinzuschauen, um einen erneuten Kurzschluss zu vermeiden.
Wenn mehrere Thread-Pool-Implementierungen vorhanden sind, wird der Thread-Pool dynamisch anhand des Thread-Pool-Namens ausgewählt.
@Componentpublic class RpcThreadPoolFactory {@Autowiredprivate Map<String,RpcThreadPool> rpcThreadPoolMap;public RpcThreadPool getThreadPool(String threadPoolName){return this.rpcThreadPoolMap.get(threadPoolName);
}
}
Verpacken Sie den Methodenkörper in eine Aufgabe und übergeben Sie ihn zur Ausführung an den Thread-Pool.
@Overrideprotected void channelRead0(ChannelHandlerContext channelHandlerContext, RpcRequest rpcRequest) {this.executor.execute(new Runnable() {@Overridepublic void run() {RpcInvoker rpcInvoker=RpcServerInvoker.this.buildInvokerChain(RpcServerInvoker.this);RpcResponse response=(RpcResponse) rpcInvoker.invoke(RpcServerInvoker.this.buildRpcInvocation(rpcRequest));
channelHandlerContext.writeAndFlush(response);
}
});
}
Es fehlen derzeit Stresstests, daher gibt es noch keinen eindeutigen Datenvergleich.
Das obige ist der detaillierte Inhalt vonDetaillierte Beispiele des RPC-Frameworks. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!