Redis存储序列化方案从JSON迁移到Google Proto Buf

为什么要迁移

各种序列化方案性能比较
个人原创,转载请联系[email protected]

优点

  1. 更快的序列化、反序列化速度
  2. 更小的内存空间占用,网络传输更快

迁移过程中需要考虑的问题

  1. 平滑,不影响已有的业务,迁移过程中性能不能下降
  2. 数据完整,不丢失,不重复
  3. 安全、低成本、风险可控

原创不易,转载请联系[email protected]

五种场景

1. 读非集合数据(无需考虑多线程安全问题) Redis存储序列化方案从JSON迁移到Google Proto Buf_第1张图片

//伪代码如下,无锁
String key = …
String key_map_to_ps = f_ps(key);
Object cached =  Redis.get(key_map_to_ps);
If (cached is not null) {
         return; 
}

String key_map_to_json = f_json(key);
cached = Redis.get(key_map_to_json);
If (cached is not null) {
         cached_ps = to_proto_stuff(cached);
         Redis.write(key_map_to_ps, cached_ps);
         Redis.delete(key_map_to_json);
         logger.warn(“hit old non-protostuff key: {}”, key_map_to_json);
         return;
}

cached = dao.getObject(key);
cached_ps = to_proto_stuff(cached_ps);
Redis.write(key_map_to_ps, cached_ps);
return;

2. 写非集合数据(无需考虑多线程安全问题)

Redis存储序列化方案从JSON迁移到Google Proto Buf_第2张图片

//伪代码如下,无锁
String key = …
String key_map_to_ps = f_ps(key);
Cached_ps = to_proto_stuff(value);
result = Redis.write(Key_map_to_ps,cached_ps);

String key_map_to_json = f_json(key);
if (Redis.exist(key_map_to_json)) {
         Redis.delete(key_map_to_json);
         logger.warn(“delete old non-protostuff key:{}”, key_map_to_json);
}
return;

原创不易,转载请联系[email protected]

3. 读集合数据(需要考虑多线程安全问题)

Redis存储序列化方案从JSON迁移到Google Proto Buf_第3张图片

//伪代码如下,迁移过程中只需要全局锁一次
String key = …
String key_map_to_ps = f_ps(key);
Object cached =  Redis.get(key_map_to_ps);
If (cached is not null) {
         return; 
}

String key_map_to_json = f_json(key);
cached_json = Redis.get(key_map_to_json);
if (cached_json is null) {
		value = dao.getResult();
		cached_ps = to_proto_stuff();
		Redis.write(key_map_to_ps, cached_ps);
		return;
}

If (!try_global_lock(key)) {
	   value = dao.getResult();
       cached_ps = to_proto_stuff(value);
	   Redis.write(key_map_to_ps,cached_ps);
	   return;
}
// 再取一次,因为值有可能在获取全局锁的时候已经失效、被删除或者变化了
cached_json = Redis.get(key_map_to_json); 
if (cached_json is null) {
		release_global_lock(key);
		value = dao.getResult();
		cached_ps = to_proto_stuff();
		Redis.write(key_map_to_ps, cached_ps);
		return;
}

cached_ps = to_proto_stuff(cached_jons);
Redis.write(key_map_to_ps,cached_ps);
Redis.delete(key_map_to_json);
// 原创辛苦,转载请联系作者[email protected]
release_global_lock(key);	
logger.warn(“delete old non-protostuff key:{}”, key_map_to_json);
return;

4. 写集合数据(需要考虑多线程安全问题)

Redis存储序列化方案从JSON迁移到Google Proto Buf_第4张图片

//伪代码如下,迁移过程中只需要全局锁一次
String key = …
String key_map_to_ps = f_ps(key);
Cached_ps = to_proto_stuff(value);
If (Redis.exists(key_map_to_ps)) {
         Redis.write(key_map_to_ps,cached_ps);
         return;
}

String key_map_to_json = f_json(key);
If (!Redis.exists(key_map_to_json)) {
		Redis.write(key_map_to_ps,cached_ps);
        return;
}

// 另一个线程正拿着全局锁,进行处理
If (!try_global_lock(key)) {
		Redis.write(key_map_to_ps,cached_ps);
        return;
}
// 辛苦原创,请尊重作者,转载请联系微信xugangqiang1982
// key_map_to_json已经失效或者被删除
If (!Redis.exists(key_map_to_json)) {
		release_global_lock(key);		
		Redis.write(key_map_to_ps,cached_ps);
		return;
}

// 先在老的key上更新,再读出整个集合并转换
Redis.write(key_map_to_json,value_to_json);
cached_json = Redis.get(key_map_to_json);
cached_ps = to_proto_stuff(cached_json);
Redis.write(key_map_to_ps,cached_ps);
Redis.delete(key_map_to_json);

release_global_lock(key);
logger.warn(“delete old non-protostuff key:{}”, key_map_to_json);
return;

5. 删除数据(无需考虑多线程安全问题)

在这里插入图片描述

//伪代码如下,无锁
string key = ...;
key_map_to_ps = f_ps(key);
key_map_to_json = f_json(key);
redis.del(key_map_to_ps);
redis.del(key_map_to_json);
return; // 辛苦原创,请尊重作者,转载请联系微信xugangqiang1982

潜在问题

  1. 如果多个模块公用同一个redis实例,并且key可能重复交叉
  2. 升级代码的时候,有可能不是同时生效,导致多个不同版本的Redis相关的API存在不同的JVM里面

你可能感兴趣的:(Redis存储序列化方案从JSON迁移到Google Proto Buf)