一、 生產者消息如何分區
kafka的消息組織結構是: topic(主題)--partition(分區)--record(消息),topic下的每條record只會保存在某一個partition中。
分區的主要作用,就是提供負載均衡的能力,分區是部署在不同節點的機器上,通過加節點來提升系統的吞吐量。
在考慮系統的分區策略時,一般有,將消息數據均勻地分配到各個分區上,或者,按具體業務規則實現某種順序分佈在分區上。
如何設定分區策略:
配置producer端的參數:partitioner.class
比如:kafkaProps.put("partitioner.class", "com.yjp.producer.MyPartitioner");
MyPartitioner實現org.apache.kafka.clients.producer.Partitioner 接口的 int partition(params...)方法,partition入參可以參考javadoc
具體分區策略如下:
輪詢策略:即順序分配,也是生產者api默認提供的分區策略, 如果未指定 partitioner.class參數,或者設定org.apache.kafka.clients.producer.internals.DefaultPartitioner即指定該策略。
返回分區位置的代碼:
List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);
return Utils.toPositive(Utils.murmur2(keyBytes)) % partitions.size();
隨機策略:即隨意放在任意一個分區上。
代碼:
List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);
return ThreadLocalRandom.current().nextInt(partitions.size());
按key分區策略:kafka允許爲每條消息定義key,key是有着實際業務含義的字符串,該策略可以保證擁有同一種key的所有消息可以進入到相同的分區裏。
代碼:
List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);
return Math.abs(key.hashCode()) % partitions.size();
其他分區策略,比如按ip地址
代碼:
List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);
return partitions.stream().filter(p -> your filter).map(PartitionInfo::partition).findFirst().get();
另外,創建topic時可以指定partition放在哪些broker上,可以解決異地kafka集羣的問題。
二、消息壓縮算法
消息壓縮,優勢是節省帶寬資源和broker磁盤存儲的空間,缺點是犧牲了cpu資源
理論上的做法是 producer壓縮,broker保持,consumer解壓縮(kafka會把具體的壓縮算法封裝到消息集合中)
但是現在的kafka版本在broker端會解壓縮,主要是對消息執行CRC校驗。未來可能會把校驗放到producer端,然後把校驗值傳到broker端。
如何壓縮?
Properties props = new Properties();
props.put("compression.type", "gzip"); //開啓GZIP壓縮
Producer<String, String> producer = new KafkaProducer<Integer, String>(props);
除GZIP以外,還有幾種壓縮算法,Snappy、LZ4和zstd, 他們分別在cpu消耗,壓縮比,壓縮和解壓縮時間方面各有千秋,比如zstd有很好的壓縮比,但是在壓縮和解壓縮時間上就中規中矩。所以具體要根據實際生產需求決定選用哪一種。