请考虑以下设置
prop.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, ThriftSerializer.class.getName());
public class ThriftSerializer implements Serializer<TBase> {
private final ThreadLocal<TSerializer> serializer = new ThreadLocalTSerializer();
@Override
public void configure(Map map, boolean b) {
}
@Override
public byte[] serialize(String s, TBase event) {
try {
return serializer.get().serialize(event);
} catch (TException e) {
return new byte[0];
}
}
@Override
public void close() {
}
}
以上代码导致内存泄漏
但是我不明白为什么会发生。卡夫卡生产者会创建很多不会死的线程吗?
如果上面的代码替换为
@Override
public byte[] serialize(String s, TBase event) {
TSerializer serializer = new TSerializer();
try {
return serializer.serialize(event);
} catch (TException e) {
return new byte[0];
}
}
然后内存泄漏消失了,这很有意义,但是对于每个事件,它创建的新对象都需要进行垃圾收集,如果吞吐量很高,则可能导致gc压力
有人可以为我指出理解这种行为的方向吗?
答案 0 :(得分:0)
据我所知,KafkaProducer是线程安全的,跨线程共享单个生产者实例通常比拥有多个实例要快。
但是send方法是异步的(除非不建议对send方法返回的Future对象调用.get(),建议不要这样做,否则您将等待每个发送并以同步方式对其进行处理)。
由于文档的缘故,生产者由一个缓冲空间池和一个I / O后台线程组成,该缓冲池保存尚未传输到服务器的记录,该I / O线程负责将这些记录转换为请求。并将其传输到集群。使用后如果无法关闭生产者,则会泄漏这些资源。
似乎send方法实际上使用了后台线程来转换您的记录并将其发送到集群。
您实际上是在最后关闭生产者吗?
producer.flush();
producer.close();
要关闭Kafka会话时,将调用序列化程序的close方法。 我的猜测是,您可以尝试使用序列化器的close方法进行一些其他清理,或将其标记为符合垃圾收集条件。