Applicable scene
- Business Process encountered a large number of asynchronous operations, and business is not very complicated
- Less demanding robust business model
- Do not ask for immediate scene
Introduce the principle of
redis official website Documentation: https://redis.io/topics/notifications#configuration
Integrated spring subscriptions to the publication: https://docs.spring.io/spring-data/redis/docs/1.7.1.RELEASE/reference/html/#redis:pubsub:subscribe
Related demo
Business release .java
// asynchronous notification message String expiredEmail RedisConstants.REDIS_EXPIRE_Email_Send.getExpired = () + UUID; ValueOperations <the Serializable, Object> = Operations redisTemplate3.opsForValue (); // Since org.springframework.data.redis.core.StringRedisTemplate use, so value must be a String operations.set (expiredEmail, "1", email_expire_time, TimeUnit.SECONDS);
EmailSyncEventListener.java
package com.redis.listeners; import com.carapi.services.order.FxjTCarInvoiceOrderService; import com.common.constant.RedisConstants; import com.exception.ErrorException; import com.model.fxjTCarInvoiceOrder.FxjTCarInvoiceOrder; import com.model.fxjTCarOrderList.FxjTCarOrderList; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.connection.Message; import org.springframework.data.redis.listener.KeyExpirationEventMessageListener; import org.springframework.data.redis.listener.RedisMessageListenerContainer; import java.nio.charset.StandardCharsets; import java.util.List; /** * 邮件发送 */ public class EmailSyncEventListener extends KeyExpirationEventMessageListener { private static final Logger log = LoggerFactory.getLogger(EmailSyncEventListener.class); //可以使用自动注入,或者xml配置 public EmailSyncEventListener(RedisMessageListenerContainer listenerContainer) { super(listenerContainer); } @Autowired private FxjTCarInvoiceOrderService tCarInvoiceOrderService; // @Autowired // public EmailSyncEventListener(RedisMessageListenerContainer listenerContainer) { // super(listenerContainer); // } @Override public void onMessage(Message message, byte[] pattern) { String channel = new String(message.getChannel(), StandardCharsets.UTF_8); //过期的key String key = new String(message.getBody(),StandardCharsets.UTF_8); if(StringUtils.isNotEmpty(key) && key.indexOf(RedisConstants.REDIS_EXPIRE_Email_Send.getExpired()) != -1){ System.out.println(key); key = key.substring(key.indexOf(RedisConstants.REDIS_EXPIRE_Email_Send.getExpired())+RedisConstants.REDIS_EXPIRE_Email_Send.getExpired().length()); log.info(key); try { InvoiceOrder = tCarInvoiceOrderService.selectByPrimaryKey FxjTCarInvoiceOrder (Key); {}, key = {}", new String (pattern), channel, key); } IF (invoiceOrder = null!) { tCarInvoiceOrderService.resendEmail (invoiceOrder.getEmail (), invoiceOrder.getInvoiceReqSerialNo ()); } } the catch (ErrorException E) { log.info ( "Mail sent asynchronously failed the verification fails"); } the catch (Exception E) { log.info ( "asynchronous failure sending mail"); e.printStackTrace (); } log.info ( "asynchronous transmit mailing successfully"); log.info ( "expired Redis Key: pattern = {}, } = {Channel, Key = {} ", new new String (pattern), Channel, Key); } }
spring-cache.xml
<bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate"> <property name="connectionFactory" ref="jedisConnFactory"></property> <property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean> </property> <property name="valueSerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean> </property> <property name="hashKeySerializer"> <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/> </property> <property name="hashValueSerializer"> <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/> </property> <property name="stringSerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> </property> </bean> <bean id="jedisConnFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <property name="hostName" value="${redis.host}" /> <property name="port" value="${redis.port}" /> <property name="password" value="${redis.password}" /> <property name="database" value="2" /> <property name="timeout" value="${redis.timeout}" /> <property name="poolConfig" ref="jedisPoolConfig" /> <property name="usePool" value="true" /> </bean> <!--去掉redis client的CONFIG--> <util:constant static-field="org.springframework.session.data.redis.config.ConfigureRedisAction.NO_OP"/> <bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"> <property name="maxInactiveIntervalInSeconds" value="3600" /> </bean> <!-- 将监听实现类注册到spring容器中 --> <bean id="emailSyncEventListener" class="com.redis.listeners.EmailSyncEventListener"> <constructor-arg ref="redisMessageListenerContainer"></constructor-arg> </bean>
Emerging issues
- After the user's session is stored in redis, redis load imbalance, there has been the key 0 ttl to remove lingering longer
Redis does not guarantee the survival time (TTL) becomes the key 0 will immediately be deleted: If the program does not have access to this key expired, or with the survival time of a lot of the key, then key in the survival time becomes 0, until the key it really is deleted middle, there may be a more significant time interval.
Therefore, Redis is generated when time expired notice to expire key is deleted, but not when survival time is 0 keys. If Redis is configured correctly and reasonable load, the delay will not exceed more than 1s.
RedisExpiredQuartz.java
Package com.redis.quart; Import com.common.constant.RedisConstants; Import com.redis.listeners.EmailSyncEventListener; Import org.slf4j.Logger; Import org.slf4j.LoggerFactory; Import org.springframework.data.redis.core. RedisTemplate; Import javax.annotation.Resource; Import java.util.Set; / ** * Redis does not guarantee the survival time (TTL) becomes the key 0 will immediately be deleted: * If the program does not have access to this key expired, or with there are key survival time of a lot of words, * then the survival time key becomes 0, * until the middle of this key really is deleted, there may be a more significant time interval. * * SO plus timer * / public class RedisExpiredQuartz { Private static final Logger log = LoggerFactory.getLogger(EmailSyncEventListener.class); @Resource private RedisTemplate redisTemplate3; public synchronized void onRedisExpiredQuartz(){ log.trace("------------------------------------------"); for (RedisConstants value : RedisConstants.values()) { Set keys = redisTemplate3.keys(value.getExpired() + "*"); log.debug("业务需要正常通知的keys:{}",keys); } } }
RedisConstants.java
com.common.constant Package Penalty for; public enum RedisConstants { / ** * monthly card expired cancel key prefix * / REDIS_EXPIRE_Sub_Card ( "redisExpiredSubCard_"), / ** * delay mailing key prefix * / REDIS_EXPIRE_Email_Send ( "redisExpiredEmail_Send_"), ; expired The String Private; RedisConstants (expired The String) { this.expired = expired The; } public String getExpired () { return expired The; } public void setExpired (expired The String) { this.expired = expired The; } // get the object enum public static RedisConstants get(String expired) { for (RedisConstants item : values()) { if (expired == item.getExpired()) { return item; } } return null; } }