In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-02 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >
Share
Shulou(Shulou.com)05/31 Report--
Today, the editor will show you how to analyze the Reactor model in the high-performance server Server. The knowledge points in this article are introduced in great detail. Friends who feel helpful can browse the content of the article with the editor, hoping to help more friends who want to solve this problem to find the answer to the problem. Let's follow the editor to learn more about "how to analyze the Reactor model in high-performance server Server".
In this era full of clouds, it can be said that 99% of the software we use is based on Cmax S architecture!
The Outlook,Foxmail you use to send e-mail.
You watch Youku, Tudou and so on.
The Office365,googleDoc,Evernote you use to write documents, etc.
IE,Chrome, etc., which you use to browse the web (Bhand S is a special Cplink S)
One of the obvious benefits of software based on the CCompact S architecture is that as long as you have a network, you can do the same thing anywhere.
For example, you write documents in Office365 at home. When you get to the company, just open the editing address and you can see the document written at home, display it or continue editing. Even read and edit on the mobile phone. You don't need USB disk handcuffs anymore.
The Cpact S architecture can be abstracted into the following models:
C is Client, and B above is Browser.
S is Server: the server manages a resource and provides some service to its clients by manipulating the resource
One of the main reasons why Cpact S architecture is popular is the improvement of network speed and the reduction of cost, especially the improvement of wireless network speed. Just imagine that in the 2G era, the most you can do is to look at text pages, novels and so on. Look at the picture, it's a luxury! Let alone watch the video!
With the improvement of Internet speed, more and more people use the Internet, such as Youku and Wechat, not to mention Tmall's instant visits on Singles Day. This has very high requirements for the server! Can quickly deal with a large number of user requests! So how can the server process the user's request quickly?
High performance server
High-performance servers must meet at least the following requirements:
High efficiency: since it is high performance, the efficiency of processing client requests is of course very high
High availability: you can't just hang up.
Programming is simple: business development based on this server needs to be simple enough
Scalable: easily extensible function
Scalable: capacity can be simply scaled through deployment, that is, services need to be stateless
One of the bases to meet the above requirements is high-performance IO!
Socket
Whether you are sending email, browsing the web, or watching video ~ the bottom layer is actually using TCP/IP, and the programming abstraction of TCP/IP is Socket!
I have been very confused about the Chinese translation of Socket. Personally, I think it is the most baffling translation of technical terms I have come into contact with.
Socket is translated into "socket" in Chinese! What the hell? I can't associate it with network programming for a long time! Later, I specifically found some information, and * found a satisfactory answer on Zhihu (for a specific link, see the Resources link at the end of the article)!
The original meaning of Socket is socket, which means the relationship between socket and slot! "send socket" is inserted into "receive socket", a link is established, and then you can communicate!
The translation of sockets should refer to the socket (such as the following figure)! From this level, it is a little interesting!
Socket translation is already the standard, do not worry about this!
Let's take a look at the process of establishing links and communication between Socket! It is actually an abstraction of the process of TCP/IP connection and communication:
The server Socket will bind to the specified port, and the Listen client will "insert"
The client Socket will Connect to the server
When the server Accept connects to the client
You can send and receive messages.
After the communication is completed, you can Close.
For IO, what we hear more is:
BIO: blocking IO
NIO: non-blocking IO
Synchronous IO
Asynchronous IO
And its combination:
Synchronous blocking IO
Synchronous non-blocking IO
Asynchronous blocking IO
Asynchronous non-blocking IO
So what are blocking IO, non-blocking IO, synchronous IO, asynchronous IO?
An IO operation is actually divided into two steps: initiating an IO request and the actual IO operation.
The difference between blocking IO and non-blocking IO lies in the * step: whether the originating IO request will be blocked, if blocking until completion, then the traditional blocking IO;, if not blocking, is non-blocking IO.
The difference between synchronous IO and asynchronous IO lies in whether the second step is blocked. If the actual IO reads and writes block the request process, it is synchronous IO, so blocking IO, non-blocking IO, IO multiplexing, and signal-driven IO are all synchronous IO;. If the operating system helps you finish the IO operation and then returns the result to you, it is asynchronous IO.
Take an inappropriate example: for example, if your network is down, you call China Telecom to report for repair!
You dial-- the client connects to the server
The phone is through-- the connection is established
You say, "my network is down, please fix it for me"-- send a message
After that, you wait there, then you are blocking the IO.
If something happens to you, you put down the phone and take care of other things. After a while, you will ask if it has been fixed-- that is, non-blocking IO.
If the customer service says, "I'll take care of it for you right away, just a moment"-- synchronize IO
If the customer service says, "I'll take care of it for you right away, I'll let you know when it's ready", and then hang up the phone-Asynchronous IO
This article only discusses the popularity of BIO and NIO,AIO usage, so I won't discuss it for the time being!
Let's take a look at the process of BIO and NIO from the code level!
BIO
Client code
/ / Bind,Connect Socket client = new Socket ("127.0.0.1", 7777); / / read and write PrintWriter pw = new PrintWriter (client.getOutputStream ()); BufferedReader br= new BufferedReader (new InputStreamReader (System.in)); pw.write (br.readLine ()); / / Close pw.close (); br.close ()
Server code
Socket socket; / / Bind,Listen ServerSocket ss = new ServerSocket (7777); while (true) {/ / Accept socket = ss.accept (); / / generally create a new thread to read and write BufferedReader br = new BufferedReader (new InputStreamReader (socket. GetInputStream ()); System.out.println ("you input is:" + br.readLine ());}
The above code can be said to be the entry-level code for learning Java's Socket.
The code flow and the previous diagram can be matched one by one.
The model diagram is as follows:
Advantages and disadvantages of BIO
Advantages
Simple model
Coding is simple
Shortcoming
Low performance bottleneck
The advantages and disadvantages are obvious. The main drawback here is that the main bottleneck is on the thread. A thread is established for each connection. Although thread consumption is less than a process, the number of valid threads that a machine can actually build is limited. In the case of Java, after 1.5, a thread consumes about 1m of memory! And with the increase in the number of threads, the consumption of CPU switching thread context also increases, after higher than a certain threshold, continue to increase threads, performance does not increase but decline! And also because a connection on a new thread, so the coding model is very simple!
With regard to the performance bottleneck, it is determined that BIO is not suitable for the development of high-performance servers! Web servers like Tomcat have been changed from BIO to NIO since 7 to improve server performance!
NIO
NIO client code (connection)
/ / get socket channel SocketChannel channel = SocketChannel.open (); channel.configureBlocking (false); / / get channel manager selector=Selector.open (); channel.connect (new InetSocketAddress (serverIp, port)); / / register SelectionKey.OP_CONNECT event channel.register (selector, SelectionKey.OP_CONNECT) for this channel
NIO client code (listening)
While (true) {/ / Select events for registered io operations (* times SelectionKey.OP_CONNECT) selector.select (); while (SelectionKey key: selector.selectedKeys ()) {if (key.isConnectable ()) {SocketChannel channel= (SocketChannel) key.channel (); if (channel.isConnectionPending ()) {channel.finishConnect () / / if you are connecting, complete the connection} channel.register (selector, SelectionKey.OP_READ);} else if (key.isReadable ()) {/ / there are readable data events. SocketChannel channel = (SocketChannel) key.channel (); ByteBuffer buffer = ByteBuffer.allocate (10); channel.read (buffer); byte [] data = buffer.array (); String message = new String (data); System.out.println ("recevie message from server:, size:" + buffer.position () + "msg:" + message);}
NIO server code (connection)
/ / get a ServerSocket channel ServerSocketChannel serverChannel = ServerSocketChannel.open (); serverChannel.configureBlocking (false); serverChannel.socket () .bind (new InetSocketAddress (port)); / / get the channel manager selector = Selector.open (); / / bind the channel manager to the channel and register the SelectionKey.OP_ACCEPT event for the channel, serverChannel.register (selector, SelectionKey.OP_ACCEPT)
NIO server code (listening)
While (true) {/ / when a registered event arrives, the method returns, otherwise blocking. Selector.select (); for (SelectionKey key: selector.selectedKeys ()) {if (key.isAcceptable ()) {ServerSocketChannel server = (ServerSocketChannel) key.channel (); SocketChannel channel = server.accept (); channel.write (ByteBuffer.wrap (new String ("send message to client"). GetBytes ()) / / register the SelectionKey.OP_READ event for the client channel after a successful connection with the client. Channel.register (selector, SelectionKey.OP_READ);} else if (key.isReadable ()) {/ / there are readable data events SocketChannel channel = (SocketChannel) key.channel (); ByteBuffer buffer = ByteBuffer.allocate (10); int read = channel.read (buffer); byte [] data = buffer.array (); String message = new String (data) System.out.println ("receive message from client, size:" + buffer.position () + "msg:" + message);}
An example of the NIO model is as follows:
Acceptor registers Selector and listens for accept events
When the client connects, the accept event is triggered
The server builds the corresponding Channel, registers the Selector on it, and listens for read and write events
When a read and write event occurs, the corresponding read and write processing is performed
Advantages and disadvantages of NIO
Advantages
High performance bottleneck
Shortcoming
Complex model
Complex coding
Need to deal with the half-package problem
The advantages and disadvantages of NIO are the exact opposite of BIO! High performance, do not need a connection to build a thread, you can handle all connections with one thread! Accordingly, the coding is much more complex, as you can clearly see from the code above. There is also a problem, because it is non-blocking, the application can not know when the message has been read, so there is a half-packet problem!
Semi-package problem
Take a brief look at the picture below to understand the half-package problem!
We know that TCP/IP may unpack when sending a message (figure 1 above)! This makes it impossible for the receiver to know when the data received is a complete data. For example: the sender sends three ABC,DEF,GHI messages respectively, and the sender is split into four AB,CDRFG,H,I packets to send. How does the receiver restore them? In the BIO model, it blocks when the data cannot be read, but not in NIO! So you need to deal with it on your own! For example, a newline character is used as a basis, or a fixed length message occurs, or a custom protocol!
Although NIO has high performance, it is complex to encode and needs to deal with the problem of half-packet. In order to facilitate NIO development, there is a Reactor model!
Reactor model
AWT Events
The Reactor model is very similar to the AWT event model in that messages are placed in a queue and consumed through an asynchronous thread pool!
Components in Reactor
Reactor:Reactor is the dispatcher of the IO event.
Acceptor:Acceptor accepts client connections, establishes a Handler for the corresponding client, and registers this Handler with Reactor.
Handler: an entity that communicates with an client, following this process to achieve business processing. There is generally a further hierarchical division based on the basic Handler to abstract processes such as decode,process and encoder. For example, for Web Server, decode is usually the parsing of HTTP requests, and the process of process further involves calls to Listener and Servlet. The processing of business logic is broken by scattered IO events in the Reactor pattern, so Handler needs to have appropriate mechanisms to preserve the context when the required information is not complete (halfway through reading) and to continue interrupted processing when the next IO event arrives (the other half is readable). To simplify the design, Handler is usually designed as a state machine, implemented according to GoF's state pattern.
Corresponding to the above NIO code:
Reactor: equivalent to Selector with distribution function
The decision branch in Acceptor:NIO that establishes the connection
Handler: operation classes such as message read and write processing
Reactor can be subdivided into the following categories in terms of thread pool and Reactor selection:
Reactor single thread model
This model is similar to the NIO process above, except that message-related processing is independent of Handler!
Although it is mentioned above that NIO can support all IO processing in a single thread. But the bottleneck is also obvious! Let's look at the case of a client. If the client makes multiple requests, and if the processing speed in Handler is slow, then the subsequent client requests will be backlog, resulting in a slow response! So the Reactor multithreading model is introduced!
Reactor multithreading model
The Reactor multithreading model separates IO operations from non-IO operations in Handler. Threads that operate IO are called IO threads, and threads that operate non-IO operations are called worker threads! In this way, the client's request will be thrown directly into the thread pool, and the client's request will not be blocked!
But when the number of users increases further, Reactor will have a bottleneck! Because Reactor not only handles IO operation requests, but also responds to connection requests! In order to share the burden of Reactor, the master-slave Reactor model is introduced!
Master-slave Reactor model
The master Reactor is used to respond to connection requests, and the slave Reactor is used to process IO operation requests!
Netty
Netty is a high-performance NIO framework that is an implementation of the Reactor model!
Netty client code
EventLoopGroup workerGroup = new NioEventLoopGroup (); try {Bootstrap b = new Bootstrap (); b.group (workerGroup); b.channel (NioSocketChannel.class); b.option (ChannelOption.SO_KEEPALIVE, true); b.handler (new ChannelInitializer () {@ Override public void initChannel (SocketChannel ch) throws Exception {ch.pipeline (). AddLast (new TimeClientHandler ());}}) ChannelFuture f = b.connect (host, port). Sync (); f.channel (). CloseFuture (). Sync ();} finally {workerGroup.shutdownGracefully ();}
Netty Client Handler
Public class TimeClientHandler extends ChannelInboundHandlerAdapter {@ Override public void channelRead (ChannelHandlerContext ctx, Object msg) {ByteBuf m = (ByteBuf) msg; try {long currentTimeMillis = (m.readUnsignedInt ()-2208988800L) * 1000L; System.out.println (new Date (currentTimeMillis)); ctx.close ();} finally {m.release () } @ Override public void exceptionCaught (ChannelHandlerContext ctx, Throwable cause) {cause.printStackTrace (); ctx.close ();}}
Netty server code
EventLoopGroup bossGroup = new NioEventLoopGroup (); EventLoopGroup workerGroup = new NioEventLoopGroup (); try {ServerBootstrap b = new ServerBootstrap (); b.group (bossGroup, workerGroup) .channel (NioServerSocketChannel.class) .childHandler (new ChannelInitializer () {@ Override public void initChannel (SocketChannel ch) throws Exception {ch.pipeline () .addLast (new TimeServerHandler () ) .option (ChannelOption.SO_BACKLOG, 128) .childOption (ChannelOption.SO_KEEPALIVE, true); / / Bind and start to accept incoming connections. ChannelFuture f = b.bind (port). Sync (); f.channel (). CloseFuture (). Sync ();} finally {workerGroup.shutdownGracefully (); bossGroup.shutdownGracefully ();}
Netty Server Handler
Public class TimeServerHandler extends ChannelInboundHandlerAdapter {@ Override public void channelActive (final ChannelHandlerContext ctx) {final ByteBuf time = ctx.alloc () .buffer (4); time.writeInt ((int) (System.currentTimeMillis () / 1000L + 2208988800L)); final ChannelFuture f = ctx.writeAndFlush (time) F.addListener (new ChannelFutureListener () {@ Override public void operationComplete (ChannelFuture future) {assert f = = future; ctx.close ();}});} @ Override public void exceptionCaught (ChannelHandlerContext ctx, Throwable cause) {cause.printStackTrace (); ctx.close () }}
From the point of view of the Netty server code, it corresponds to the Reactor model!
EventLoopGroup is equivalent to Reactor,bossGroup corresponding to master Reactor,workerGroup corresponding to slave Reactor.
TimeServerHandler is Handler.
The method that begins with child configures the client-side channel, and the method that does not start with child configures the server-side channel.
For specific Netty content, please visit the Netty official website!
The problem with Netty
An obvious problem in Netty development is callback. First, it breaks the habit of linear coding.
The second is Callback Hell!
Look at the following example:
A.doing1 (); / / 1 a.doing2 (); / / 2 a.doing3 (); / / 3
If the code is synchronized, it will be executed in sequence! But what if it's not synchronized? I still want 2 to be executed after 1 and 3 after 2! What should I do? Think of AJAX! We need to write code like this!
A.doing1 (new Callback () {public void callback () {a.doing2 (new Callback () {public void callback () {a.doing3 ();})}))
Is there any way to solve this problem? In fact, it is not difficult to achieve a function similar to Future! When Client gets the result, block it, and then continue to go down when you get the result! One solution is to use locks, and the other is to use RingBuffer. After testing, the use of RingBuffer than the use of lock TPS has about 2000 improvement!
Thank you for your reading, the above is the whole content of "how to analyze the Reactor model in high-performance server Server", learn friends to hurry up to operate it. I believe that the editor will certainly bring you better quality articles. Thank you for your support to the website!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.