很久没有更新博客,因为不知道有什么可以写的。虽然近期学了也用到了kafka,redis这些技术。但是终究停留在会用的层次 。这次做了把原有业务socket协议转为http的需求 。记录一下。
现有业务时拣货员,配送员使用小程序来拣货,配送。完成订单状态变更。但是可能由于网络问题,老是掉线。影响工作效率。原来使用了netty的socketid框架。大家都不太熟悉。后来老大建议转http方式来做。提升稳定性。
原来的做法。socket-io自带了心跳保活。一定时间内,服务端没有收到客户端的心跳,会主动断开与客户端的链接。每当有新订单/订单被撤回的时候,服务器会主动通知客户端消息变更。
现在更改为前台轮询心跳接口,刷新tokenshi时间,并获取此客户端有无订单变化。若有,则重新查询,若无,则等待下一次心跳。心跳接口如下
public JSONObject heartBeat(HttpServletRequest httpServletRequest){
JSONObject json=new JSONObject();
//根据token获得userId
String token=httpServletRequest.getHeader("token");
Integer userId=getUserIdByToken(token);
logger.info("心跳"+userId);
if(userId==null){
json.put("status",Constants.heartBeat.noUser);
return json;
}
//刷新redis缓存时间
redisTemplate.opsForValue().set(CommonUtil.MD5(String.valueOf(userId)),userId.toString(),60, TimeUnit.SECONDS);
Object status=redisTemplate.opsForValue().get(String.valueOf(userId));
redisTemplate.opsForValue().set(userId.toString(),Constants.heartBeat.begin);
json.put("status",status);
return json;
}
登录接口逻辑:登录校验,成功后,则生成token ,存token(key)和userId(value). 用户所有请求在请求头中附带token.服务器获得token后再redis查询userId获取用户信息。
redis用的比较少。碰到下面这些坑。记录一下
序列化配置:
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
GenericToStringSerializer genericToStringSerializer = new GenericToStringSerializer(Object.class);
template.setValueSerializer(genericToStringSerializer);
template.setKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}
redis监听失效key
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.GenericToStringSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfiguration {
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer() {
RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();
redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory);
return redisMessageListenerContainer;
}
@Bean
public KeyExpirationEventListener keyExpiredListener() {
return new KeyExpirationEventListener(this.redisMessageListenerContainer());
}
}
import com.qiancang.transport.client.UserClient;
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.core.RedisTemplate;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
public class KeyExpirationEventListener extends KeyExpirationEventMessageListener {
@Autowired
RedisTemplate redisTemplate;
@Autowired
UserClient userClient;
private Logger logger= LoggerFactory.getLogger(KeyExpirationEventListener.class);
public KeyExpirationEventListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
//监听key失效方法 在这里将失效用户踢下线
@Override
public void onMessage(Message message, byte[] pattern) {
String key = new String(message.getBody());
//
}
}
说实话 感觉这个需求意义不大。但是上面要做就做吧。也算是能学到东西。做完以后稳定性提升了。服务器不需要维护长连接,效率更高。但是有了频繁的心跳请求。已经尽量减少心跳的操作了。但是频繁的心跳还是会消耗不少的服务器资源。性能测试对比,http方式有一定的性能提升。但我感觉测试的结果可能有一些偏差。因为我不觉得自己写的心跳机制比netty好。后续跟着看一下性能把