An overview of the
Some time ago, the project was going to be servitization, so I compared the advantages and disadvantages of several popular RPC frameworks as well as the application scenarios, and finally chose dubbox as the basic RPC service framework based on the actual situation of my project. The following is a brief introduction to the selection process of RPC framework technology.
RPC is briefly
This series of articles will describe the following EXAMPLES of HELLOWord RPC framework and brief introduction of its implementation principle. Since the principle implementation of each RPC framework is different and complicated, please go to the official website or other technical blogs for further study. RPC framework responsibilities The RPC framework shields complexity from callers and from service providers:
- The caller feels as if calling a local function
- The service provider implements the service as if it were a local function
RPC framework is the primary basic component of architecture (micro) servitization, which can greatly reduce the cost of architecture (micro) servitization, improve the r&d efficiency of callers and service providers, and shield all kinds of complex details of cross-process calling functions (services). The responsibilities of RPC framework are as follows: Let the caller call the remote function as if it were a local function, and let the service provider implement the service as if it were a local function
For those who do not understand servitization, you can read these two articles: Evolution and Practice of servitization Architecture
Benefits of servitization Why should the Internet architecture be servitized?
Principles for unbundling the service architecture
Source: Li Linfeng’s article: How does Huawei implement the micro-service architecture internally? It’s basically based on these five principles
Service separation principle: Vertical and horizontal separation based on service functions. Size and granularity is the difficulty and a point of contention for the team.
Bad practice
- Use code volume as a yardstick, such as less than 500 lines.
- The granularity of the split should be as small as possible, such as the operation granularity of a single resource.
Recommended Principles
- Functional integrity, single responsibility.
- Moderate granularity acceptable to the team.
- Iterative evolution does not happen overnight.
- API version compatibility is preferred.
The amount of code cannot be used as a criterion to judge whether microservices are properly divided, because we know that the same service has different amounts of code depending on the complexity of the function itself. It’s also important to emphasize that at the beginning of the project, don’t expect the microservices division to happen overnight. The evolution of microservices architecture should be a gradual process. In a company, in a project team, it also needs a gradual evolution process. It doesn’t matter if the stroke is bad at the beginning. It’s a good microservice for your team to evolve to a stage where the cost of deploying, testing, and operating a microservice is very low.
Development principles for service architecture
The development of microservices will also face the problem of lagging dependency. For example, user A needs to perform id verification on service provider B. As B prioritized the development of id card number verification service, it could not meet the delivery time of A. A will either wait or implement an ID card number verification function.
In the previous monomer architecture, we often liked to write what we needed, which was not too serious a dependency problem. However, in the era of micro-services, micro-services are provided by a team or a group. At this time, it must be impossible to provide all services at the same time, and “demand realization lag” is inevitable.
A good practice strategy is interface first, language neutral, service provider and consumer decoupling, parallel development, and increased productivity. No matter how many services there are, interfaces need to be identified and defined first, and then contract-driven development on both sides based on the interfaces, using Mock service providers and consumers to decouple each other and develop in parallel to achieve dependency decoupling.
With contract-driven development, if requirements are unstable or constantly changing, you will face the problem of an interface contract changing frequently. Service providers should not delay providing interfaces because they are worried about interface changes, and consumers should embrace change rather than complain and resist it. To solve this problem, a good practice is to combine management and technology:
- Interface changes are allowed, but the frequency of changes is strictly controlled.
- Provide full online API documentation services (such as Swagger UI) to convert offline API documentation into full online, interactive API documentation services.
- Active notification of API changes, so that all consumers of the API can be aware of the changes in time.
- Contract-driven testing, used to regression test compatibility.
Testing principles for service architecture
Once the microservices are developed, they need to be tested. The testing of microservices includes unit test, interface test, integration test and behavior test, among which the most important is contract test:
Using micro service framework provides a Mock mechanism, simulation can be generated respectively by consumer client test pile, the pile and the provider’s server can be based on both the Mock test pile testing micro service interface contracts, both sides do not need to wait for each other function code development, implements the parallel development and testing, raise the efficiency of micro service building. Interface-based contract testing can also quickly find incompatible interface changes, such as changing field types and deleting fields.
Deployment principles for the service architecture
After testing is complete, automated deployment of microservices is required. Principles of microservice deployment: independent deployment and lifecycle management, infrastructure automation. An assembly line similar to CI/CD is needed to automate infrastructure. For details, please refer to Spinnaker, Netflix’s open source continuous delivery line for microservices:
Finally, take a look at running containers for microservices: Microdeployments can be deployed on Dorker containers, PaaS platforms (VMS), or physical machines. Deploying microservices with Docker brings many priorities:
- Consistent environment, consistent online and offline environment.
- Avoid dependency on specific cloud infrastructure providers.
- Reduce the burden on the operation and maintenance team.
- High performance is close to bare performance.
- Multi-tenancy.
Compared with the traditional physical machine deployment, the PaaS platform can realize the automatic deployment and life cycle management of microservices. In addition to deployment and operation and maintenance automation, the cloud of microservices can also fully enjoy more flexible resource scheduling:
- The resilience and agility of the cloud.
- Cloud dynamics and resource isolation.
Governance principles for service architecture
Once a service deployment goes live, service governance is the most important task. Micro service governance principle: online governance, real-time dynamic implementation. Common governance strategies for microservices:
- Flow control: dynamic and static flow control.
- The service is degraded.
- Timeout control.
- Priority scheduling.
- Traffic migration.
- Call chain trace and analysis.
- Service routing.
- Service on-line approval, offline notification.
- SLA policy control.
- The microservice governance model is as follows:
The top layer is the UI interface for service governance, providing online and configured governance interfaces for o&M personnel to use. The SDK layer provides various interfaces for microservice governance, which can be invoked by the service governance Portal. At the bottom is the managed microservice cluster. Each node of the cluster listens to the operation of the service governance to refresh in real time. For example, after the flow control threshold is changed, the service governance service flusits the new flow control threshold to the service registry. After the service provider and consumer detect the change, the service provider and consumer obtain the new threshold and refresh it to the memory for the change to take effect in real time. Since the current service governance policy data volume is not very large, you can put the service governance data in the service registry (for example, ETcd /ZooKeeper), there is no need to make a separate set.
Service best Practices
After introducing microservices implementation, let’s take a look at best practices for microservices. Service route: local short-circuit policy. Key technical points: calls to service providers within the JVM are made first, followed by calls to the same host or VM, and finally calls across the network. The local short circuit avoids the network overhead of remote invocation, reduces the service invocation delay, and improves the success rate. The principle is as follows:
Service invocation: synchronous invocation, asynchronous invocation, parallel invocation. A service invocation usually means that one service invocation thread is suspended. Asynchronous invocation can avoid thread blocking and improve system throughput and reliability. However, asynchronous invocation also has some disadvantages in real projects, resulting in less widespread use:
Asynchronous callback logic needs to be written, which is inconsistent with the use of traditional interface calls, making it more difficult to develop.
Context information needs to be cached in some scenarios, which introduces reliability problems.
Parallel invocation applies to multiple service invocations without context dependence and can be logically processed in parallel, similar to JDK Fork/Join. Parallel service invocation involves synchronous to asynchronous, asynchronous to synchronous, and result aggregation, etc., which is difficult to implement and not supported by many service frameworks at present. By using parallel service invocation, the traditional serial service invocation can be optimized into parallel processing, which can greatly shorten the service invocation delay.
Microservice fault isolation: thread level, process level, container level, VM level, physical machine level, etc. Key technical points:
- Support service deployment to different threads/thread pools.
- Core and non-core services are deployed in isolation.
- To prevent thread bloat, both shared and exclusive thread pool strategies are supported.
When it comes to distribution, transactional consistency is a problem: most businesses can be solved through final consistency, and very few require strong consistency.
Specific strategies are as follows:
- The ultimate consistency can be achieved based on messaging middleware.
- Strong consistency, using TCC framework. The service framework itself does not provide “distributed transactions” directly, but often migrates into the distributed transaction framework to support distributed transactions according to actual needs.
Three elements of microservice performance:
- The I/O model, which is usually non-blocking, may use Java native in Java.
- Thread scheduling model.
- Serialization mode.
It is recommended to use asynchronous non-blocking I/O (Netty), binary serialization (Thrift compressed binary), and Reactor thread scheduling model for scenarios that require high performance.
Finally, let’s take a look at the interface compatibility principles of microservices: technical support and management collaboration.
- Formulate and strictly implement the Microservice Forward Compatibility Specification to avoid incompatible modifications or unauthorized modifications without informing the surrounding.
- Interface compatibility: For example, the IDL of Thrift supports the creation, modification, and deletion of fields, the irrelevance of field definition positions, and the out-of-order of code streams.
- Daily build and contract-driven testing of the continuous delivery pipeline enables rapid identification and discovery of incompatibilities.
Currently popular RPC frameworks:
Service governance
- dubbo
- dubbox
- motan
Multilingual type
- grpc
- thrift
- avro
- Protocol Buffers (google)
The image above is from Dubbo. The structure of service governance RPC framework is mostly like this, which can be roughly divided into service provider, service consumer, registry, monitoring and alarm center.
Service performance
In servitization, or microservitization, the first consideration is performance because of the following additional performance overhead after servitization:
- The client needs to serialize the message, which consumes CPU computing resources.
- Serialization requires the creation of binary arrays, which costs the JVM either heap memory or off-heap memory.
- The client needs to send the serialized binary array to the server, occupying network bandwidth resources.
- After the server reads the code stream, it needs to deserialize the request datagram into the request object, occupying CPU computing resources.
- The service provider implementation class is invoked by the server through reflection, and reflection itself has a significant impact on performance.
- The server serializes the response results, consuming CPU computing resources.
- The server sends the reply code stream to the client, occupying network bandwidth resources.
- The client reads the response code stream and deserializes it into a response message, occupying CPU resources.
RPC framework high performance design
In order to improve efficiency, in addition to hardware improvement, the following three aspects are mainly considered:
- I/O scheduling model: Synchronous blocking I/O (BIO) versus non-blocking I/O (NIO).
- Choice of serialization framework: text protocol, binary protocol, or compressed binary protocol.
- Thread scheduling model: serial scheduling or parallel scheduling, lock contention or lock-free algorithm.
IO scheduling is now the mainstream of Netty. High performance serialization currently the best performance is ICE, Google PB protocol, FB Thrift protocol, etc. It could also be AKKA (Java)
conclusion
To sum up, servitization is now the mainstream architecture mode of large Internet companies. There are also more popular micro-services and Docker deployment.
I recommend dubbox, which integrates with various other protocols, and the performance comparison of each protocol is provided at the end of this series.
The reason why WE recommend dubbox is that Dubbox has a well-balanced service governance model, including ZK registry, service monitoring, etc., which can serve us very conveniently. Although Dubbo itself does not support multiple languages, we can integrate other serialization protocols, such as Thrift and Avro, to support multiple entry-level languages, making collaboration between departments more flexible
Of course, in the actual use, especially in the process of integrating other protocols, you must have a deep understanding of the protocol itself to use it correctly.
motan
Sina Weibo open source RPC framework
Helloword example directly go to the official website to download and run
Github address: github.com/weibocom/mo… Document address: github.com/weibocom/mo… User guide; Github.com/weibocom/mo…
# grpc
Chinese version Official document: Chinese version of gRPC official document
HelloWord example, I am based on this article to do, write quite detailed: RPC framework gRPC learning – Hello world
GRPC principle: GRPC principle analysis
dubbo
Dubbo has stopped maintenance upgrades with the end of 12 years, ignored
thrift
Please refer to another article I wrote: Thrift Study Notes (I) Thrift Introduction and the first HelloWord program
dubbox
Dubbox is a version of Dubbo that the Dangdang team has upgraded. Is a distributed service architecture that can be used directly in production environments as an SOA service framework. Dubbo official website homepage: Dubbo. IO/There is a detailed user guide and official documentation, which will not be described here in detail.
Dangdang official Github address: github.com/dangdangdot…
Github address for upgrading to spring 4.x (and other dependent components) versions of Dubbox: github.com/yjmyzz/dubb… .
Reference [blog: Under the Bodhi Tree Yang Guo’s article is very comprehensive, the introduction has been very detailed] : Dubbox Upgrade Spring to 4.x and add Log4j2 support distributed services framework Dubbo/Dubbox Getting started example dubbox various management and supervision Dubbo/Dubbox added native thrift and Avro support
# Performance comparison of each RPC framework
The test environment
jdk7
Windows 7 64 – bit
idea
Personal Notebook configuration:
Person objects:
private int age;
private String name;
private boolean sex;
private int childrenCount;
Copy the code
- 1
- 2
- 3
- 4
Test data, input:
private int ageStart;
private int ageEnd;
Copy the code
- 1
- 2
The return value:
Person.PersonBuilder builder = Person.builder();
List<Person> list = new ArrayList<Person>();
for (short i = 0; i < 10; i++) {
list.add(builder.age(i).childrenCount(i).name("test" + i).sex(true).build());
}
return list;
Copy the code
- 1
- 2
- 3
- 4
- 5
- 6
The configuration used for each protocol test
- grpc
rpc getPersonList (yjmyzz.grpc.study.dto.QueryParameter) returns (yjmyzz.grpc.study.dto.PersonList) {}
- motan
<motan:basicService export="demoMotan:8002" group="motan-demo-rpc" accessLog="false" shareChannel="true" module="motan-demo-rpc" application="myMotanDemo" registry="registry" id="serviceBasicConfig"/>
- dubbox
<dubbo:protocol name="dubbo" serialization="kryo" optimizer="com.alibaba.dubbo.demo.SerializationOptimizerImpl"/>
<dubbo:service interface="com.alibaba.dubbo.demo.person.PersonService" ref="personService" protocol="dubbo"/>
Copy the code
- 1
- 2
- 3
- thrift
TNonblockingServer + TFramedTransport
The test results
RGPC 100000 NettyServer calls, time: 53102 ms, average 1883 times/SEC 【 simple GRPC 】 RGPC 100000 NettyServer calls, elapsed time: 51800 ms, average 1930 times/SEC RGPC 100000 NettyServer calls Dubbo service Server started! 【dubbox. Kryo 】 RGPC 100000 NettyServer calls, 55133 ms, 1813 ms/SEC 【dubbox. Kryo 】 RGPC 100000 NettyServer calls, 52280 ms, average 1912 times/SEC 【dubbox. Kryo 】 RGPC 100000 NettyServer calls, 44414 ms, average 2251 / SEC. 【dubbox.fst】 RGPC 100000 NettyServer calls, 44805 ms, 2231 seconds on average, Dubbo service Server started! [2016-10-08 19:14:43] RGPC 100000 NettyServer calls, 46245 milliseconds, 2162 times/SEC [2016-10-09 19:52:34] RGPC 100000 NettyServer calls started 【dubbox. Thrift 】 RGPC 100000 NettyServer calls, 14142 milliseconds, 7071 times/SEC 【dubbox. Thrift 】 RGPC 100000 NettyServer calls, 13762 ms, average 7266 times/SEC 【 Dubbox. thrift】 RGPC 100000 NettyServer calls, duration: 44334 ms, average: 2255 / SEC 【motan】 RGPC 100000 NettyServer calls, elapsed time: 39007 ms, average 2563 times/SEC 38610 milliseconds, average 2590 cycles/SECCopy the code
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
Test Results
Using your own laptop, the test may not be professional, but it's telling. As you can see from the above results, thrift has the best performance and is quite goodCopy the code
- 1
- 2
- 3
Tests taken by other people on the Internet
Ice-dubo-thrift – GRPC performance test Comparison Comparison of RPC framework performance
conclusion
The main factors affecting RPC performance are as follows:
- Serialization performance
- IO performance
- The threaded
Serialization, certainly is Google’s PB protocol and thrift best, IO and thread, the first popular performance is better to use multithreaded non-blocking IO.
GRPC is produced by Google, using the PB protocol, but because it appeared relatively late, not how mature, and the USE of HTTP protocol, very suitable for the micro services now, but the performance is much worse, and like service governance and monitoring need additional development work, so give up GRPC. Thrift has the same performance as GRPC, but is a little harder to develop than Dubbox and Motan, requiring you to write proto files (which isn’t really that hard for a programmer). Things like service governance and monitoring also require additional development work. Dubbo is getting old, so it’s going to go away. Dubbox, and later Motan, were a good fit for our team. Dubbox was later developed by Dangdang.com to introduce the REST style HTTP protocol and support other protocols such as Kryo/FST/Dubbo/THRIFT. Dubbo is also used by other teams, which has convenient integration and complete service governance monitoring functions. Therefore, Dubbox was finally adopted.
In fact, I personally prefer thrift, because it is very young, and in a large distributed system, even a small performance improvement can add up to a lot. However, the specific selection process should be combined with the current situation of the team and the acceptance of other developers in the team.
Copyright notice: This article is the blogger’s original article, without the permission of the blogger shall not be reproduced, reproduced please indicate the source. Blogger blog address is blog.csdn.net/liubenlong0… https://blog.csdn.net/fgyibupi/article/details/54692241