kafka 原理
1.topic下面分partition,每个partition的offset是这个在partition里面的偏移量
2.具体选择那个partition会根据算法来选择,基本上会平均分配
3.zookeeper和kafka的关系是zookeeper用来管理kafka内部的分区和选择leader
4.ISR是用来管理副本的,有一个HW的水位线,Leader和Follower都复制完成,水位线就到这个位置。
选择follwer现在是基于时间的值来判断的,延迟时间超过这个值就剔除ISR,没有选用relica.lag.max.message的原因是,如果设置数量为4,如果follower正常工作,leader接收到的producer发送过来的条数就是4,那么follower肯定小于4,那么就会被剔除ISR,但是事实是他follower能够正常工作,过一段时间有加回来,浪费资源。
5.topic是在Kafka broker里面,Producer消息的生产者是在向broker发送信息,Consumer是在从Broker里面读取信息。
不使用group的话,启动10个consumer消费一个topic,这10个consumer都能得到topic的所有数据,相当于这个topic中的任一条消息被消费10次。
KafkaTemplate
1.Kafka 生产者
@Slf4j
@Component
public class KafkaConsumer {
//@KafkaListener(topics = "#{'${kafka.consumer.topics}'.split(',')}")
@KafkaListener(//必须设置groupId,没有就设置默认的group.id
topics = "my_log",
groupId = "group.id",
//会在日志前面加上前缀
clientIdPrefix = "abc",
containerFactory = "kafkaListenerContainerFactory")
//containerFactory = "ackSingleContainerFactory")
//如果输入的部分要设置ack,那么必须要有手动获取ack偏移量节点
public void inputPersonfileNewCluster(List<ConsumerRecord> consumerRecords) {
log.info(String.valueOf(consumerRecords));
}
}
2.设置取数据的参数
@Configuration
public class ConfigKafka {
@Bean
public ConcurrentKafkaListenerContainerFactory<String,byte[]> kafkaListenerContainerFactory(ConsumerFactory<String,byte[]> consumerFactory){
ConcurrentKafkaListenerContainerFactory<String,byte[]> factory=new ConcurrentKafkaListenerContainerFactory<>();
//相当于同时多少个客户端在取数据,2说明有两个客户端同时取数据
factory.setConcurrency(2);
factory.setConsumerFactory(consumerFactory);
//设置为批量消费,每个批次数量在Kafka配置参数中设置ConsumerConfig.MAX_POLL_RECORDS_CONFIG,每次取MAX_POLL_RECORDS_CONFIG个数据
factory.setBatchListener(true);
return factory;
}
}
3.在配置文件里面加入批量消费的数据个数
4.kafka生产者
@Slf4j
@Component
public class KafkaProducer {
@Resource
private KafkaTemplate<String,String> kafkaTemplate;
public void send(String topic, String obj){
log.info("准备发送消息",obj);
ListenableFuture<SendResult<String,String>> future = kafkaTemplate.send(topic,obj);
future.addCallback(new ListenableFutureCallback<SendResult<String, String>>() {
@Override
public void onFailure(Throwable throwable) {
log.info(topic+"生产者消费失败"+throwable.getMessage());
}
@Override
public void onSuccess(SendResult<String, String> stringStringSendResult) {
log.info(topic+"生产者发送消息成功"+stringStringSendResult.toString());
}
});
}
}
5.调用KafkaProducer
@Component
public class KafkaProducerService {
@Resource
KafkaProducer kafkaProducer;
public void test(){
kafkaProducer.send("my_log","abc");
}
}
@RestController
public class ProducerController {
@Resource
KafkaProducerService kafkaProducerService;
@Resource
KafkaTransactionService kafkaTransactionService;
@PostMapping("/hby")
public void test(){
kafkaProducerService.test();
}
@PostMapping("/hby1")
public void test1(){
kafkaTransactionService.sendToKafka("error");
}
@PostMapping("/hby2")
public void test2(@RequestParam String input){
kafkaTransactionService.sendToTrans(input);
}
}
Kafka事务
Kafka处理事务的两种方法,加注解和用template.executeInTransaction,当中间有报错,数据都进行回滚,不进行传输。输入是error不发送数据。
@Component
public class KafkaTransactionService {
@Resource
private KafkaTemplate template;
public String sendToKafka(String input){
template.executeInTransaction(t->{
t.send("my_log",input);
if("error".equals(input)){
throw new RuntimeException("input is error");
}
t.send("my_log",input+"other");
return true;
});
return "Send success"+input;
}
@Transactional
public String sendToTrans(String input){
template.send("my_log",input);
if("error".equals(input)){
throw new RuntimeException("input is error");
}
template.send("my_log",input+"other");
return "Send success"+input;
}
}
kafka单元测试
这部分还需学习,虽然能够跑通过,但是没有对应到对应的方法中。
@SpringBootTest
@DirtiesContext
@ActiveProfiles("junit")
@RunWith(SpringRunner.class)
@EmbeddedKafka(controlledShutdown = true,topics = "my_log")
@Slf4j
public class KafkaConsumerTest {
@Resource
private EmbeddedKafkaBroker kafkaEmbeded;
@Before
public void setUp() {
Map<String,Object> senderProperties = KafkaTestUtils.producerProps(kafkaEmbeded.getBrokersAsString());
ProducerFactory<String,String> producerFactory=new DefaultKafkaProducerFactory<>(senderProperties);
KafkaTemplate<String,String> template=new KafkaTemplate<>(producerFactory);
String topic="my_log";
template.send(topic,"and sec");
}
@Test
public void onMessage() throws InterruptedException{
TimeUnit.SECONDS.sleep(5);
System.out.println("finish");
// log.info(String.valueOf(consumerRecords));
}
}
Linux grep 管道
Linux提供的管道符号,|左面命令的输出会作为右面命令的输入,第二个管道符号,做不命令的输出,同样作为右面命令的输入,以此类推。
ps -ef|grep java
501 1794 1018 0 9:34上午 ??
每个字段的含义
UID PID PPID C STIME TTY TIME CMD
zzw 14124 13991 0 00:38 pts/0 00:00:00 grep --color=auto dae
UID :程序被该 UID 所拥有
PID :就是这个程序的 ID
PPID :则是其上级父程序的ID
C :CPU使用的资源百分比
STIME :系统启动时间
TTY :登入者的终端机位置
TIME :使用掉的CPU时间
CMD :所下达的是什么指令
从当前目录开始查找所有扩展名为 .rtf 的文本文件,并找出包含 “Abc” 的行
crystaldeMacBook-Pro:javahby crystal$ find . -name "*.rtf" | xargs grep "Abc"
\f0\fs24 \cf0 Abc}
在一个类里面主函数调用方法
https://blog.csdn.net/qq_35389417/article/details/84024470