前面写了一个单实例模式的redis hset写入udf,使用pipeline提高写入性能,没用连接池,因为有使用限制,就是要按唯一键mod分成许多个组然后collect_list传入一个列表,所以创建的连接很少,保证每个组里面的这个list不会太大,就没啥问题。不然在pipeline上提交的时候应该也要计数一下,每多少条sync一下,偷懒了。。。。
后面正式使用的时候是将这些用户id写入了一个redis集群,那么那个udf就不好用了,得写过一个,因为集群模式没有pipeline啊我擦。。。。
开始没想那么多,在evaluate函数里面每次都会创建一个JedisCluster实例,类似下面这种:
@Override
public Object evaluate(DeferredObject[] arg0) throws HiveException {
//JedisCluster只能在方法内部创建作为局部变量使用,这个类里面会用到连接池,连接池是有状态的,无法序列化。
try (JedisCluster jedisCluster = new JedisCluster(hostAndPort)) {
for (int i = 0; i < paramsListInspector.getListLength(arg0[2].get()); i++) {
Object row = paramsListInspector.getListElement(arg0[2].get(), i);
Map<?, ?> map = paramsElementInspector.getMap(row);
if (map.containsKey(writableKeyField)) {
String did = map.get(writableKeyField).toString();
for (Map.Entry<?, ?> entry : map.entrySet()) {
if (!writableKeyField.equals(entry.getKey()) && entry.getValue() != null && !"".equals(entry.getValue().toString())) {
jedisCluster.hset(did, entry.getKey().toString(), entry.getValue().toString());
}
}
}
}
return new IntWritable(1);
} catch (Exception e) {
e.printStackTrace();
throw new HiveException(e);
}
}
性能简直差到爆啊,因为有300多万条数据,每条都创建一个JedisCluster,而且JedisCluster和Jedis不太一样,他内部本省就是使用了pool。。。想想都很恐怖,如果执行快的话其实都没太去管这么多,关键是执行的慢的不得了,就得优化了。
首先一个优化就是想同一个map container里面所有数据都共享一个jedisCluster实例,于是抽离到单独的类中去,延迟初始化,不能定义在当前udf类中通过initialize来初始化,会无法序列化:
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.joda.time.DateTime;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import java.util.concurrent.*;
public class JedisClusterUtil {
private static GenericObjectPoolConfig initPoolConfiguration() {
System.out.println(Thread