背景
Impala数据推送到Redis,平台业务使用方反馈插入到Redis的数据不对:
Redis插入key没有问题;value是0.6nul
有问题,正常的数据应该是0.6
。
排查
往Redis里面写数据的代码片段如下:
private void pushToRedis(Map query, List<Map<String, Object>> datalist) {
if (CollectionUtils.isEmpty(datalist)) {
return null;
}
JedisCluster redisCluster = this.getConnection();
String[] columnArr = (query.get(COLUMN) + "").replace("\n", "").replace(" ", "").split(",");
String keyTo = String.valueOf(query.get("keyTo"));
String valueSplit = String.valueOf(query.get("valueSplit"));
if (StringUtils.isEmpty(valueSplit)) {
// 默认分隔符
valueSplit = ",";
}
// Redis key过期时间
Object redisExpireObj = query.get("redisExpire");
SetParams setParams;
if (StringUtils.isNotEmpty(redisExpireObj)) {
setParams = SetParams.setParams().ex(Integer.parseInt(redisExpireObj + ""));
} else {
// 永不过期,待优化
setParams = SetParams.setParams();
}
for (Map<String, Object> item : datalist) {
StringBuilder sb = new StringBuilder();
for (String s : columnArr) {
// 以指定的分隔符拼接String形式的Redis value
sb.append(item.get(s)).append(valueSplit);
}
// 从
String objectKey = String.valueOf(item.get(keyTo));
// 去掉最后一个分隔符
redisCluster.set(objectKey, sb.substring(0, sb.toString().length() - 1), setParams);
}
}
此方法接收两个参数:
datalist
是从Impala中查询得到的数据,数据有多条,故而用List包装。每一条数据对应数据表的一行记录,使用Map自是必然的,key对应表字段,value对应该字段具体的数据,数据有多种类型,故而统一使用Object。Map<String, Object>
类型的query里面则存储着数据推送到Redis时的一些信息,比如过期时间redisExpire
,如Redis集群的appId(使用开源组件CacheCloud来维护及管理Redis集群),this.getConnection()
方法就是通过appId连接到对应的集群,比如需要往什么Key写数据,比如value组合时使用什么分隔符。
附:
private JedisCluster getConnection(Map<String, Object>) {
long appId = Long.parseLong(query.get("appId"));
return ClientBuilder.redisCluster(appId)
.setJedisPoolConfig(getPoolConfig())
.setConnectionTimeout(2000)
.setSoTimeout(1000)
.build();
}
其结果来自于如下SQL语句:
select concat('fqz_appscore_list_yxd:', cast(appname AS string) ) as keyname, appscore from fqz.Yxd_AppScore_List;
在Impala 查询平台执行上述SQL,获取得到的数据,无论是key,还是value都是正常的。value没有带多余的nul
。
说明Impala数据源是正常的。
问题出现在推送到Redis的逻辑代码处,即上面的Java代码。
而key是没有问题,只是value有问题,最终落值的value为: sb.substring(0, sb.toString().length() - 1
。
中间赋值的地方为:sb.append(item.get(s)).append(valueSplit);
说明,问题在于这个valueSplit
。再看下数据库原始数据,即Map query
这个map。
{
"redisExpire": "172800",
"column": "appscore",
"keyTo": "keyname"
}
并没有valueSplit
这个字段,query.get("valueSplit")
的结果为null
,好家伙!!
再看下String.valueOf()
源码:
/**
* Returns the string representation of the Object argument.
*/
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
问题定位到。
如何解决呢?
String valueSplit = String.valueOf(query.get("valueSplit"));
if (StringUtils.isEmpty(valueSplit) || "null".equalsIgnoreCase(valueSplit)) {
// 默认分隔符
valueSplit = ",";
}
参考
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/142146.html