Impala推送数据到Redis及String.valueOf()生产问题踩坑

勤奋不是嘴上说说而已,而是实际的行动,在勤奋的苦度中持之以恒,永不退却。业精于勤,荒于嬉;行成于思,毁于随。在人生的仕途上,我们毫不迟疑地选择勤奋,她是几乎于世界上一切成就的催产婆。只要我们拥着勤奋去思考,拥着勤奋的手去耕耘,用抱勤奋的心去对待工作,浪迹红尘而坚韧不拔,那么,我们的生命就会绽放火花,让人生的时光更加的闪亮而精彩。

导读:本篇文章讲解 Impala推送数据到Redis及String.valueOf()生产问题踩坑,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

背景

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

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!