12 pictures | A wave of hard work, three-tier cache architecture

939e460c9a96f33649fec9dcb91015fd.png

1. Foreword

In the last lecture, we mentioned that the server side of the Eureka registration center has a three-level cache to store registration information, and the fast reading of the cache can be used to improve system performance. Let’s take a closer look:

Level 1 cache: read-only cache readOnlyCacheMap, data structure ConcurrentHashMap. Equivalent to a database.

Secondary cache: read-write cache readOnlyCacheMap, Guava Cache. It is equivalent to the master node in the Redis master-slave architecture, which can both read and write.

Level 3 cache: local registry registry, data structure ConcurentHashMap. Equivalent to the slave node of the Redis master-slave architecture, it is only responsible for reading.

It is clearer to see the picture, as shown in the figure below:

5493fa46f1da04a30172477e2ebede0c.png

three caches

In addition, ConcurrenthashMap is also a map structure, which is stored in the form of key-value pairs, as shown in the following figure:

76dd5bc8f5159be0d2efe73520117564.png

Map structure

In this article, Brother Wukong will take you to see how Eureka’s cache architecture is. By studying this article, we can also learn from Eureka’s cache design ideas and apply it to the project.

2. Several thoughts triggered

Let’s take a look at the Eureka source code again. It’s not hard to understand, and I’ll explain it below.

f4f18cb73bf76bd5b99349d357dac084.png

  • By default, it will first search from the read-only cache.

  • If not, look for it from the read/write cache.

  • If found, update the read-only cache and return the found cache.

  • If you still can’t find it, load it from the local cache registry.

Three questions arise:

(1) How does the L3 cache data come from?

(2) How is the cached data updated?

(3) How does the cache expire?

3. Local cache

Let’s first look at the local cache registry, which is a data structure defined as ConcurrentHashMap, which has been explained in detail before.

When the client initiates a registration request, it will put the registration information into the registry. As shown in the following code:

registry.putIfAbsent(app)

putIfAbsent means that if there is a duplicate key, no value will be put in. If the value corresponding to the passed key already exists, the existing value will be returned without replacement.

After the putIfAbsent operation, the client’s registration information is put into the registry.

01ef7639643a0f5e90a35bf855db1e.png

Let’s take a look at one of the cache structures: read-write cache.

4. Read and write cache

Read-write cache, as the name suggests, is a cache that can be read or written. Reads are mainly for read-only caches. Writing is mainly to update the cache to its own Map.

The following are answers from several aspects of the principle of write cache, the source code of write cache, the principle of expiration timing, and the source code of expiration timing.

3.1 The principle and source code of write cache

I started to think that when we couldn’t read from the read cache, we would go to the database to check. After searching for a long time, I couldn’t find a place to read the database.

Then I used the IDEA tool to find the place where readOnlyCacheMap was used, and finally I found it.

b44412d1d919c1577961ac3b2d15af7a.png

The read and write cache uses the Guava Cache tool class, which will not be delved into in this article. To put it simply, when accessing the read-write cache, if the key does not exist in the cache, it will be checked locally, and then put back into the cache.

Then the abstract method load(key) is implemented. The function of this method is to get it from the local registry cache when there is no read-write cache.

86d0533fc4bf688efa14a235ca631d7c.png

When the read and write cache expires, there are actually two types: regular expiration and real-time expiration. Since the above source code has defined the time interval of the timed expiration, let’s look at the timed expiration first.

3.2 Timed expiration

When building this read-write cache, you define how often to expire the entire read-write cache. As shown in the following code, 180 s will periodically expire the read and write cache.

expireAfterWrite(180s)

d9f299e6205c1162acc68834f9c3eb65.png

3.3 Real-time expiration

When a new service instance is registered or goes offline, or fails, the cache of the corresponding service instance will be expired.

As shown in the figure below, the top one is the registration center, and the bottom three are service instances. When a service instance registers, goes offline, or fails, the registration center can perceive it, and then actively expires the service instance corresponding to the read and write cache.

8bf4489f7fe50e0fdbf5c8bfbfe4a2d2.png

3.4 Real-time expiration source code

From the source code level, let’s look at the source code of the read and write cache expiration. The invalidateCache method is called to expire.

File path: com/netflix/eureka/registry/AbstractInstanceRegistry.java

eec9467b687356a38acef4815c2c80e2.png

5. Read-only cache

5.1 Regular update

The read-only cache readOnlyCacheMap has a timing update mechanism, which updates some keys in the read-only cache every 30 seconds.

efe4779f34cb8a132f1236f6910181eb.png

It actually traverses all its registration information, and then compares it with the read-write cache. If the registration information is inconsistent, it replaces it with the data in the read-write cache.

The source code is as follows. There is a scheduled task scheduled every 30 seconds.

4e35e60ce3cb012f7459f0f4d3428ffe.png

5.2 update

In addition, when the client obtains the registration information, it will also read the read-only cache first. If it is not in the read-only cache, it will find it from the read-write cache, and put it in the read-only cache after finding it. If there is not in the read-write cache, it will be loaded from the local registry registry into the read-write cache, and then the registry information will be returned.

Do you have a question here: Since this cache is called a read-only cache, how can it be updated? Shouldn’t it be unchanged?

In fact, the change here is relative to the client. When the client obtains registry information, it first accesses the read-only cache, similar to the master-slave architecture of a database or Redis. The master is responsible for reading and writing, and the slave is responsible for reading. Then the system internally synchronizes the information of the master node to the slave node. Do you understand?

6. Cache related configuration

Let’s take a look at what configurations Eureka Server has for caching?

6.1 Whether to enable read-only cache

eureka.server.useReadOnlyResponseCache

When the client obtains registration information, whether to obtain it from the read-only cache first. If false, fetch directly from the read-write cache. Defaults to true.

6.2 Interval time for regularly updating the read-only cache

eureka.server.responseCacheUpdateIntervalMs

By default, the updated cache of the read-write cache is synchronized to the read-only cache every 30 seconds.

7. Problems caused by caching

L3 cache seems to bring performance improvements. But it also introduces other problems, such as cache inconsistency.

The read-only cache will be refreshed every 30s, and the read-write cache will cause data inconsistency. The registry information obtained by the client within 30s is lagging behind.

When using the Eureka cluster, the problem of cache inconsistency will be more obvious, and the data in the read-only cache will also be inconsistency between different nodes, so Eureka can only guarantee high availability, not strong consistency, that is, guarantee AP does not guarantee CP. In addition, we can choose a registration center with strong consistency, such as Zookeeper and Nacos, which will be discussed later.

How to alleviate the inconsistency problem?

(1) On the server side, we can set the time interval for updating the read-only cache. The default is 30 seconds. If it is shortened, such as 15 seconds, the frequency is too high, which may cause performance problems for Eureka.

(2) On the server side, we can also consider turning off reading registry information from the read-only cache, and Eureka Client reads directly from the read-write cache.

8b9234a1ea21c9c4abdab49b9dd16ac5.png

8. Summary

5b767928db49ed3b5878874623ab6ff9.png

Eureka Server registry three-level cache architecture

This article learns the three-tier cache architecture on the server side of the Eureka registry, which is divided into registry, readOnlyCacheMap, and readWriteCacheMap, which are used to store service registration information.

  • By default, registration information is updated from the read-write cache to the read-only cache every 30 seconds.

  • By default, when the client reads the registry, it first reads from the read-only cache, if not, reads from the read-write cache, and if not, reads from the local registry registry.

  • By default, the read and write cache expires every 180 seconds.

  • When a service instance registers, goes offline, or fails, the read and write cache will expire in real time.

  • The introduction of multi-level cache will also bring about the problem of cache inconsistency.

References:

www.passjava.cn

“Deep Analysis of Microservice Architecture”

Eureka source code

Back-end exclusive technology group

Build a high-quality technical exchange community, welcome to join the group who are engaged in programming development and technical recruitment HR, and also welcome everyone to share your company’s referral information, help each other, and make progress together!

Civilized speech, mainly focusing on communication technology, job referral, industry discussion

Advertisers do not enter, do not trust private chats, to prevent being cheated

a9ab32a7af3bd6a669c932f717899bf0.jpeg

Add me as a friend and pull you into the group
The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge Java skill tree Using JDBC to operate the databaseDatabase operation 118810 people are learning the system