Microservice Architect Pattern. In the past two years, with the crazy growth of services and the progress of cloud computing technology, microservice architecture has attracted attention. Microservice architecture is an architecture model, which advocates the division of a single application into a group of small services, which coordinate and cooperate with each other to provide users with the ultimate value. Each service runs in its own separate process and communicates with each other using a lightweight communication mechanism (usually RESTful apis based on HTTP). Each service is built around a specific business and can be independently deployed to a production environment, class production environment, and so on. In addition, the unified and centralized service management mechanism should be avoided as far as possible. For a specific service, appropriate language and tools should be selected to build it according to the business context.
Firstly, it briefly introduces the connotation and advantages of Microservices. The essence of Microservices architecture is to solve larger and more practical problems by using some services with more clear functions and more refined services. Microservice architecture separates the services into relatively independent services to manage all aspects, and uses a unified interface to communicate with each other. As a result, the architecture becomes complex and has obvious advantages:
Controllable complexity: The application is decomposed while avoiding the endless accumulation of complexity. Each microservice focuses on a single function and clearly expresses service boundaries through well-defined interfaces. Due to its small size and low complexity, each microservice can be fully controlled by a small development team, making it easy to maintain high maintainability and development efficiency.
Independent deployment of microservices architecture: Because microservices have independent running processes, each microservice can also be deployed independently. There is no need to compile and deploy the entire application when a microservice changes. Applications made up of microservices have a series of parallel distribution processes, making distribution more efficient, reducing the risk to the production environment, and ultimately shortening the application delivery time.
Flexible technology selection: Under the microservice architecture, technology selection is decentralized. Each team is free to choose the most appropriate technology stack based on its own service needs and industry development status. Because each microservice is relatively simple, the risk is low when upgrading the technology stack, and even a complete refactoring of a microservice is feasible.
Fault tolerance: When a component fails, in the traditional single-process architecture, the failure is likely to spread throughout the process, resulting in application-wide unavailability. In a microservice architecture, faults are isolated within a single service. If well designed, other services can achieve fault tolerance at the application level through retry, smooth degradation and other mechanisms.
Scale-out: Monolithic applications can also achieve scale-out by copying the entire application to different nodes. Microservices architectures are flexible when different components of an application have different scaling requirements, because each service can scale independently based on actual needs.
Internet high concurrency related nouns
Page Views
Unique PageViews
Unique visitors
Number of repeat visitors
Page Views per user
Before the high concurrency, I mistakenly thought that the solution of high concurrency could be solved by threads or queues, because when the high concurrency is accessed by many users, the system data is incorrect and the data is lost. Therefore, I thought of using queues to solve the problem, but actually queue solution can also be handled. For example, when we are bidding for goods, forwarding comments on weibo or killing goods in seconds, the volume of traffic is particularly large at the same time. The queue plays a special role in this. All requests are put into the queue in milliseconds and orderly, so as to avoid data loss and incorrect system data.
After checking the data, there are two solutions to high concurrency, one is to use caching, the other is to use static page generation; There is also from the most basic place to optimize our code to reduce unnecessary waste of resources 🙁
1. Avoid frequent new objects and use the singleton pattern for classes that require only one instance in the entire application. For String concatenation, use StringBuffer or StringBuilder. Classes of utility type are accessed through static methods.
Avoid using the wrong method, for example, Exception can control method rollout, but Exception should retain stackTrace consumption, and do not use Instanceof for conditional determination unless necessary. Using efficient JAVA classes such as ArrayList performs better than Vector.
High concurrency – Problems that need to be solved
- The application cache
- HTTP cache
- Multistage cache
- pooling
- Asynchronous concurrent
- capacity
- Queue high concurrency – Apply cache heap cache: Use Java heap memory to store cache objects. The advantage of using heap cache is that there is no serialization/deserialization and it is the fastest cache. The disadvantages are also obvious, when there is a large amount of data in the cache, GC pauses can be longer and storage capacity is limited by the size of the heap. Generally, cache objects are stored by soft/weak references, that is, when the heap memory is insufficient, it can be forcibly reclaimed to release the heap memory space. The heap cache is typically used to store hot data.
Guava Cache: The Cache and ConcurrentMap are very similar, but they are not exactly the same. The fundamental difference is that ConcurrentMap holds all added objects until they are removed from the display. Caches, to limit their memory usage, are often configured to automatically remove objects. This is useful in cases where objects are not automatically removed, such as LoadingCache, which automatically loads cached objects.
Ehcache 3.x: is a widely used open source Java distributed cache. Targeted at general-purpose caches,Java EE and lightweight containers. It features memory and disk storage, cache loaders, cache extensions, cache exception handlers, a GZIP cache servlet filter, support for REST and SOAP apis, and more.
MapDB: MapDB is an embedded pure Java database that provides concurrent HashMap, TreeMap, Queue, and can store data either off-heap or on disk
High concurrency – Application Cache Out-of-heap cache: The cache data is stored in out-of-heap memory, which reduces GC pause time (fewer objects are scanned and moved by the GC when the heap objects are moved out of the heap), but the data is serialized/deserialized when read, so it is much slower than the heap cache. Ehcache 3.x, MapDB implementation
Disk cache: Where cached data is stored on the track and still exists when the JVM restarts, but the heap/off-heap cache data is lost and needs to be reloaded. Ehcache 3.x, MapDB implementation
Distributed cache: in-process cache and disk cache. In the case of multiple JVM instances, there are three problems:
1. Single machine capacity problem;
2. Data consistency issues (what if the cache data of multiple JVM instances is inconsistent?) Since data is allowed to be cached, it means that inconsistencies are allowed within a certain period of time. Therefore, you can set the expiration time of cached data to update data periodically.
3, cache miss, need to return to the source DB/ service request changeability problem: each instance in the case of cache miss will return to the source DB to load data, so after multi-instance DB overall access quantity changes more, the solution is to use such as consistent hash sharding algorithm. Therefore, these situations can be addressed using distributed caching.
JAVA interprocess distributed caching can be implemented using EhCache-clustered (in conjunction with Terracotta Server). The best approach is to use Redis for distributed caching.
High concurrency – HTTP cache The browser cache means that when we use the browser to access some web pages or HTTP services, we set the response header according to the cache returned by the server and cache the response content to the browser. Next time, we can directly use the cache content or just check whether the content expires on the server. This reduces the amount of data transferred back and forth between the browser and server, saving bandwidth and improving performance.
Solution: Content doesn’t need to be dynamic (computed, rendered, etc.) to be faster, the closer the content is to the user, the faster it is. Technologies such as Apache Traffic Server, SQUID, Varnish, and Nginx can be used for content caching.
CDN is used to speed up user access:
That is, users first access CDN nodes across the country (using such as ATS and Squid), if the CDN fails, the source will be returned to the central Nginx cluster, if the cluster does not hit the cache (the cache of the cluster is not necessary, according to the actual hit situation, etc.), and finally back to the source to the back-end application cluster.
High concurrency – Multi-level cache (distributed cache) High concurrency – pooling
In the process of application system development, we often use pooling technology, such as object pool, connection pool, thread pool, etc., through pooling to reduce some consumption, to improve performance.
Object pooling reduces the overhead of object creation and garbage collection by reusing objects. However, the pooling should not be too large because it will affect the scan time during GC.
Connection pooling, such as database connection pooling, Redis connection pooling, and Http connection pooling, improves performance by multiplexing TCP connections to reduce the time it takes to create and release connections.
Thread pools are similarly used to improve performance by reusing threads. In other words, the purpose of pooling is to improve performance through reuse.
High concurrency – Capacity expansion
1, read and write separation: when the database traffic is not very large, we can appropriately increase the server, database master and slave replication will separate the read and write
2. Vertical partitioning: Once the write operation is increased, the master and slave databases will spend more time on data synchronization, and the server will be overwhelmed at this time. We can separate the two tables and put them on different servers. If there is a join table query between these two tables and other tables, we can create a vertical partition of the data. If there is a join table query between these two tables and other tables, we can create a vertical partition of data. So you can only split the original SQL statement, first query one table, in the query another, although this will consume more performance, but compared to that kind of massive data synchronization, the burden is much less;
3. Horizontal Partition: But often things are not satisfying, may take vertical partition can support for a period of time, because the website is too hot, the page view and daily 100W, suddenly jumped to 1000W, this time can take data separation, we can according to the user Id different allocation, such as %2, form, Of course, this form has a great limit to the future expansion, when I increase from 10 partitions to 20, all the data will have to be repartitioned, so it will be a huge amount of computing; Several common algorithms: hash algorithm: is the use of user_id%; Range: Can be divided according to the user_id character range, for example, 1-1000 is one area, and 1001-2000 is another area. Mapping: The partition corresponding to user_id is saved in the database. Users can query the partition before performing operations.