The meaning of the caching service
Why use caching? In the end it is to improve the speed of the system. Keep users ' frequently accessed content in the most recent, fastest-to-reach places, and increase user responsiveness. A simple structure for a Web application such as.
Typical architecture for Web applications
In this structure, the user's request passes through the user layer to the business layer, and the business layer fetches the data from the data layer and returns it to the user layer. In the case of small user volume, the data volume is not too large, the system runs very smoothly. However, as users become more and more large, the data in the database is more and more, the system user response speed is more and more slow. The bottleneck of the system is generally on the database access. This time, the above schema may be changed to the following to alleviate the pressure of the database.
A master multi-slave structure
In this architecture, the read and write requests for the database are detached. A large number of read requests are allocated from the database, and the primary database is only responsible for writing requests. Keep active and master libraries synchronized from the library. This architecture has a great improvement over the previous, general Internet application. This architecture can be very well supported. One of his shortcomings is more complex, the master-slave library to maintain efficient real-time, or quasi-real-time synchronization is a difficult thing to do. So we have another way of thinking about using a cache server to store hot-spot data, while relational data is used to store persisted data. Structure as shown
Schema read by cache server with cache server Read architecture
In this architecture, when the data is read, the data is fetched from the cache server, and if a tune is obtained, the data is returned directly. If no tune is obtained, the data is fetched from the database. Once acquired, the data is cached in the swap-out database for use by the next access. When inserting or updating data, write the data to the relational database before updating the data in the cached database.
Of course, in order to cope with a larger volume of traffic, we can also combine the above two improved architectures, both read-write separated relational databases, and high-speed access to the cache service.
The premise of the above cache server architecture is that getting data from a cache server is much more efficient than getting it from a relational database. Otherwise, the cache server has no meaning. Redis data is stored in memory, ensuring that the time to obtain data from Redis is much higher than that obtained from a relational database.
Implementation based on Redis cache service
This chapter uses an example to illustrate how to implement a Redis caching service in Java. The code was added on the basis of the code implemented in the previous article, "Using Redis in Java." Code synchronization published in the GitHub repository
Build MAVEN projects and introduce dependencies
Refer to the Pom.xml file content in the article "Using Redis in Java"
Defining the Interface class Com.x9710.common.redis.CacheService
In this interface class, the following interfaces are primarily fixed
- void PutObject (String key, Object value);
- void PutObject (String key, Object value, int expiration);
- Object pullobject (String key);
- Long TTL (String key);
- boolean delobject (String key);
- boolean expire (String key, int expiresecond);
- void Clearobject ();
These interfaces are used for objects that are not in the storage period , store Future expired Objects , get Cache objects , gets the remaining lifetime of the cache object , Delete cache objects , set cache object Expiration Time , Clears the functionality of all cached objects
package com.x9710.common.redis;
/ **
* Cache service interface
*
* @author 杨 高超
* @since 2017-12-09
* /
public interface CacheService {
/ **
* Store the object in the cache
*
* The key stored by @param key
* @param value
* /
void putObject (String key, Object value);
/ **
* Store the object in the cache
*
* The key stored by @param key
* @param value
* @param expiration expiration time, in seconds
* /
void putObject (String key, Object value, int expiration);
/ **
* Get object from cache
*
* @param key to get the key of the object
* @return returns the object if it exists, otherwise returns null
* /
Object pullObject (String key);
/ **
* Set the expiration seconds for the cache object
*
* @param key to get the key of the object
* @param expireSecond expiry seconds
* @return returns the object if it exists, otherwise returns null
* /
boolean expire (String key, int expireSecond);
/ **
* Get the cache object expired seconds
*
* @param key to get the key of the object
* @return If the object does not exist, return -2, if the object has no expiration time, return -1, otherwise return the actual expiration time
* /
Long ttl (String key);
/ **
* Delete objects from cache
*
* @param key The key of the object to be deleted
* @return returns false if an error occurs, otherwise returns true
* /
boolean delObject (String key);
/ **
* Clear objects from cache
* /
void clearObject ();
}
Define serial number auxiliary class com.x9710.common.redis.SerializeUtil
All objects to be saved in the redis database need to have serial numbers as binary arrays. The purpose of this class is to serialize Java objects into secondary arrays or deserialize secondary arrays into objects.
package com.x9710.common.redis;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/ **
* Object serialization tools
*
* @author 杨 高超
* @since 2017-10-09
* /
public class SerializeUtil {
/ **
* Serialize an object into a binary array
*
* @param object The object to be serialized must implement the java.io.Serializable interface
* @return The serialized binary array
* /
public static byte [] serialize (Object object) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream ();
ObjectOutputStream oos = new ObjectOutputStream (baos);
oos.writeObject (object);
return baos.toByteArray ();
} catch (Exception e) {
e.printStackTrace ();
}
return null;
}
/ **
* Deserialize a binary array into an object. The program does not check the object type during deserialization.
*
* @param bytes the binary number to be deserialized
* @return deserialized object
* /
public static Object unserialize (byte [] bytes) {
try {
ByteArrayInputStream bais = new ByteArrayInputStream (bytes);
ObjectInputStream ois = new ObjectInputStream (bais);
return ois.readObject ();
} catch (Exception e) {
e.printStackTrace ();
}
return null;
}
}
Implement redis cache service class com.x9710.common.redis.impl.CacheServiceRedisImpl
package com.x9710.common.redis.impl;
import com.x9710.common.redis.CacheService;
import com.x9710.common.redis.RedisConnection;
import com.x9710.common.redis.SerializeUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import redis.clients.jedis.Jedis;
/ **
* Cache service redis implementation class
*
* @author 杨 高超
* @since 2017-12-09
* /
public class CacheServiceRedisImpl implements CacheService {
private static Log log = LogFactory.getLog (CacheServiceRedisImpl.class);
private RedisConnection redisConnection;
private Integer dbIndex;
public void setRedisConnection (RedisConnection redisConnection) {
this.redisConnection = redisConnection;
}
public void setDbIndex (Integer dbIndex) {
this.dbIndex = dbIndex;
}
public void putObject (String key, Object value) {
putObject (key, value, -1);
}
public void putObject (String key, Object value, int expiration) {
Jedis jedis = null;
try {
jedis = redisConnection.getJedis ();
jedis.select (dbIndex);
if (expiration> 0) {
jedis.setex (key.getBytes (), expiration, SerializeUtil.serialize (value));
} else {
jedis.set (key.getBytes (), SerializeUtil.serialize (value));
}
} catch (Exception e) {
log.warn (e.getMessage (), e);
} finally {
if (jedis! = null) {
jedis.close ();
}
}
}
public Object pullObject (String key) {
log.trace ("strar find cache with" + key);
Jedis jedis = null;
try {
jedis = redisConnection.getJedis ();
jedis.select (dbIndex);
byte [] result = jedis.get (key.getBytes ());
if (result == null) {
log.trace ("can not find caceh with" + key);
return null;
} else {
log.trace ("find cache success with" + key);
return SerializeUtil.unserialize (result);
}
} catch (Exception e) {
log.warn (e.getMessage (), e);
} finally {
if (jedis! = null) {
jedis.close ();
}
}
return null;
}
public boolean expire (String key, int expireSecond) {
log.trace ("strar set expire" + key);
Jedis jedis = null;
try {
jedis = redisConnection.getJedis ();
jedis.select (dbIndex);
return jedis.expire (key, expireSecond) == 1;
} catch (Exception e) {
log.warn (e.getMessage (), e);
} finally {
if (jedis! = null) {
jedis.close ();
}
}
return false;
}
public Long ttl (String key) {
log.trace ("get set expire" + key);
Jedis jedis = null;
try {
jedis = redisConnection.getJedis ();
jedis.select (dbIndex);
return jedis.ttl (key);
} catch (Exception e) {
log.warn (e.getMessage (), e);
} finally {
if (jedis! = null) {
jedis.close ();
}
}
return -2L;
}
public boolean delObject (String key) {
log.trace ("strar delete cache with" + key);
Jedis jedis = null;
try {
jedis = redisConnection.getJedis ();
jedis.select (dbIndex);
return jedis.del (key.getBytes ())> 0;
} catch (Exception e) {
log.warn (e.getMessage (), e);
} finally {
if (jedis! = null) {
jedis.close ();
}
}
return false;
}
public void clearObject () {
Jedis jedis = null;
try {
jedis = redisConnection.getJedis ();
jedis.select (dbIndex);
jedis.flushDB ();
} catch (Exception e) {
log.warn (e.getMessage (), e);
} finally {
if (jedis! = null) {
jedis.close ();
}
}
}
}
Write test cases
package com.x9710.common.redis.test;
import com.x9710.common.redis.RedisConnection;
import com.x9710.common.redis.impl.CacheServiceRedisImpl;
import com.x9710.common.redis.test.domain.Student;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
/ **
* Cache service test class
*
* @author 杨 高超
* @since 2017-12-09
* /
public class RedisCacheTest {
private CacheServiceRedisImpl cacheService;
@Before
public void before () {
RedisConnection redisConnection = RedisConnectionUtil.create ();
cacheService = new CacheServiceRedisImpl ();
cacheService.setDbIndex (2);
cacheService.setRedisConnection (redisConnection);
}
@Test
public void testStringCache () {
String key = "name";
String value = "grace";
cacheService.putObject (key, value);
String cachValue = (String) cacheService.pullObject (key);
// Check if the string obtained from the cache is equal to the original string
Assert.assertTrue (value.equals (cachValue));
// Check if deleting existing objects from cache returns true
Assert.assertTrue (cacheService.delObject (key));
// Check if deleting an existing object from the cache returns false
Assert.assertFalse (cacheService.delObject (key + "1"));
// Check if getting the deleted object from cache returns null
Assert.assertTrue (cacheService.pullObject (key) == null);
}
@Test
public void testObjectCache () {
Student oriStudent = new Student ();
oriStudent.setId ("2938470s9d8f0");
oriStudent.setName ("Liu Bai Ape");
oriStudent.setAge (36);
cacheService.putObject (oriStudent.getId (), oriStudent);
Student cacheStudent = (Student) cacheService.pullObject (oriStudent.getId ());
Assert.assertTrue (oriStudent.equals (cacheStudent));
Assert.assertTrue (cacheService.delObject (oriStudent.getId ()));
Assert.assertTrue (cacheService.pullObject (oriStudent.getId ()) == null);
}
@Test
public void testExpireCache () {
String key = "name";
String value = "grace";
cacheService.putObject (key, value);
cacheService.expire (key, 300);
String cachValue = (String) cacheService.pullObject (key);
Assert.assertTrue (value.equals (cachValue));
Long ttl = cacheService.ttl (key);
Assert.assertTrue (ttl> 250 && ttl <= 300);
Assert.assertTrue (value.equals (cachValue));
Assert.assertTrue (cacheService.delObject (key));
}
}
Test result test result
Redis is a basic usage as a cache service. Only caching based on k-value data is implemented here. The usage of the other Hash, Set, List and other caches are similar.
Later I will also talk about redis implementing distributed locks, globally unique identifiers, LBS services and message queue services.
Welcome to join the learning and communication group 569772982, everyone learn and communicate together.
Why use a cache server and implement a redis cache service in Java