How much does the privilege system cache design know?

Source: Internet
Author: User
Tags memcached redis

The privilege system is an essential module in the management class system, and a good cache design is the most important of the privilege system, so we can talk about how to design the cache of the privilege system better today.

Single-node caching

Permission check belongs to the use of ultra-high frequency operation, if each time to request the DB, not only will bring pressure to the DB, will also cause the user response too slow, resulting in a very bad user experience, so it is necessary to put the permissions related data into the cache, pseudo-code as follows:

private static final FUNCTION_CACHE_KEY = "function_cache_key";public List<Function> loadFunctions() {    // 优先从缓存中取    List<Function> functions = cacheService.get(FUNCTION_CACHE_KEY);    if(functions != null){        return functions;    }    // 缓存中没有,从数据库中取,并放入缓存    functions = functionDao.loadFunctions();    cacheService.put(FUNCTION_CACHE_KEY, functions);    return functions;}

It is recommended to use Ehcache as the cache component, Ehcache is a pure Java in-process caching framework, supports data persistence to disk, and supports a variety of cache policies, which can be said to be very suitable for caching of the large data volume of permission data.

Cluster cache

Ehcache is a process-level cache, not very friendly to cluster support, although there are some scenarios to achieve distributed cache, but the total feeling is not directly with memcached or Redis, but directly with memcached or Redis, will go through a network call, And for the permission cache such a large amount of memory data, performance is not ehcache this process-level cache good. Is there always a plan that can take into account Ehcache performance advantages and the distributed benefits of Redis?

This problem can be solved by Ehcache and redis in a common way, with the general idea of using Ehcache cache, cache updates communicating between clusters through MQ, and Redis as a level two cache.

The specific options are as follows:

Update data
The data is put into Ehcache and Redis simultaneously, and the other nodes are updated by MQ to update their cache, and the updated data is pulled from the Redis.

Delete data
Delete data from Ehcache and Redis, while notifying other nodes via MQ to delete their own data

In fact, for the permission cache, the general update operation is not frequent, through MQ to make change notification, Redis do two cache, so you can still use the Ehcache in the cluster environment of efficient storage

Ensure the consistency of cascading caches with timestamps

When designing the cache, not all caches are taken from the database, and some caches are taken from other caches, which reduces the computation time when they are used.

数据库 --> 缓存a --> 缓存b

With the above dependency, it can be seen that cache B will cause cache dirty data If it is not re-loaded from cache a when it changes.

The most straightforward scenario is to flush the B-cache synchronously while refreshing the a cache, but from the above dependencies you can see that B-dependent a,a does not rely on the b,b cache for a should be invisible, so logically does not conform to the rules of dependency.

And the above is only a two-level association, if it is level four, level five, the upper cache changes led to too many lower cache changes, it takes a lot of time, so if you can use deferred refresh is probably a better solution.

Time stamping may be a good idea, in the above example, you can add a timestamp to cache A, each time a cache change, and a synchronous update timestamp. When I get B, we just need to check if the timestamp of a is changed, reload B cache if it changes, or return B directly.

The pseudo code is as follows:

Permission information cache keyprivate static Final function_cache_key = "Function_cache_key";//permission information cache timestamp private static final Function_ Time_stamp = "Function_time_stamp";//permission information cache old timestamp private static final function_old_time_stamp = "function_old_time_ Stamp "///user rights information cache keyprivate static Final user_function_cache_key =" Uer_function_cache_key ";//Load All permissions information public List     <Function> loadfunctions () {//First take list<function> functions = Cacheservice.get (Function_cache_key) from the cache;    if (functions! = null) {return functions;    }//Not in cache, fetch from database and put in cache functions = Functiondao.loadfunctions ();    Cacheservice.put (Function_cache_key, functions);    Synchronous update timestamp String TimeStamp = string.valueof (System.currenttimemillis ());    Cacheservice.put (Function_time_stamp, TimeStamp); return functions;} Load user's permission information based on user ID public list<function> loaduserfunctions (Long userId) {list<function> functions = Loadfun    Ctions (); Load user rights information in cache list<function> userfunctions = CacheserVice.get (User_function_cache_key + userId);    String newtimestamp= Cacheservice.get (Function_time_stamp);    String oldtimestamp= Cacheservice.get (Function_old_time_stamp); If there is no user rights information in the cache, or if the timestamp is not equal, reload the user permission information from the permission information if (userfunctions = = NULL | | Newtimestamp! = oldtimestamp) {userfunct ions = getuserfunctions (functions, UserID);//Put user rights information into the cache Cacheservice.put (User_function_cache_key + userid        , functions);        Put the current timestamp into the cache Cacheservice.put (Function_old_time_stamp, Newtimestamp);    return userfunctions; } return userfunctions;}

It should be noted that the above code is just as an example, the actual development of the user's permission information generally have a better way to handle, and not necessarily the above example in each user has a separate cache.

Because the cache above is only two cascade, if the series is more, you can also use timestamps for lazy loading

数据库 --> 缓存a --> 缓存b --> 缓存c --> 缓存d

When you get cache D, you can check the cache a timestamp + cache b timestamp + cache C Timestamp, any time stamp of ABC changes, the cache D will need to reload, the idea is similar to the above, there is not much to repeat.

The Magical magic of guava

It is possible to add another layer of caching where the use of the permission check is high, but the check logic does not change very often.

For example, the general permission system has external interface, can be directly anonymous access, check the code as follows

// ant风格 url 匹配器private AntPathMatcher matcher = new AntPathMatcher();// 可以访问的匿名url集合,通常采用ant风格,例如 /open/api/**// 匿名url通常写在配置文件中,并且在bean初始化时加载到该集合中private Set<String> anonymousUrlPatterns = new HashSet<String>();// 判断url是否能匿名访问public boolean couldAnonymous(String url) {    for (String patternUrl : anonymousUrlPatterns) {        if (matcher.match(patternUrl, url)) {            isMatch = true;            break;        }    }    return isMatch;}

As you can see, every URL access is verified, and you can optimize performance by adding a layer of caching

With distributed cache feel a bit overqualified, Ehcache and a bit too heavy, concurrenthashmap and do not support caching strategy, reasoning guava seems to be the best choice, after the transformation of the code as follows:

 //ant style URL match private antpathmatcher matcher = new Antpathmatcher ();//accessible anonymous URL collection, usually in ant style , for example, the/open/api/**//anonymous URL is usually written in a configuration file and loaded into the collection when the bean is initialized private set<string> anonymousurlpatterns = new hashset< String> (); Anonymous URL access rights cache private static cache<string, boolean> Anonymousurlcache = Cachebuilder.newbuilder (). MaximumSize (5 (initialcapacity). expireafteraccess (1, timeunit.days)//Set how long the object in the cache has not been accessed after it expires. Build ();//Determine if URL can be Name Access public boolean couldanonymous (String URL) {///////////////////To return a Boolean couldanonymousaccess = anonymousurlcache.g    Etifpresent (URL);    if (couldanonymousaccess! = null) {return couldanonymousaccess;    } Boolean isMatch = false;            for (String patternurl:anonymousurlpatterns) {if (Matcher.match (Patternurl, url)) {IsMatch = true;        Break    }}//Match result put into cache anonymousurlcache.put (URL, isMatch); return isMatch;}  
Localstorage Cache

Localstorage is a new feature supported by HTML5, can put some data cache on the client, reduce the pressure on the server, such as can put the menu data to the client, the menu data is expired through the timestamp to judge, pseudo-code as follows:

var timestamp = localStorage.getItem("timestamp" + userId);// 请求后台获取菜单接口,带上时间戳参数 timestamp// 后台校验时间戳是否变更,如果变更,返回新的菜单数据和新的时间戳,否则不需要返回菜单数据,仍旧返回旧的时间戳即可 // 后台接口返回数据格式 result = {menus:{},timestamp:""}var newTimestamp = result.timestamp;// 时间戳变更,把新的菜单数据和新的时间戳 放入 localStorageif (newTimestamp != timestamp) {    localStorage.setItem("menus" + userId, JSON.stringify(result.menus));    localStorage.setItem("timestamp" + userId, newTimestamp);}

Some people worry about putting the cache in Localstorage if the modification will cause security problems, in fact, this worry is not necessary, because the permission check is done on the server side, Localstorage in the cache only for display use, so modify localstorage without any meaning.

Summarize

In different cases, the above scenario uses Ehcache,redis,guava,localstorage to do the cache, it is more explained that there is no best technology, only the most suitable technology. The problem of cache update is solved by introducing the mechanism of this version number of time stamp. The ultimate goal is only one, ensure the consistency of the cache data at the same time, the performance of the ultimate, user experience to do the best.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.