kafka 相信都有听说过,不管有没有用过,在江湖上可以说是大名鼎鼎,就像天龙八部里的乔峰。国际惯例,先介绍生平事迹
 
简介

Kafka 是由 Apache软件基金会 开发的一个开源流处理平台,由 Scala 和 Java 编写。Kafka是一种高吞吐量的 分布式 ,支持分区(partition),多副本(replica)的 发布订阅消息系统 。与其他MQ最大不同是Topic 具有分区(Partition)的概念,消息出队的速度也比其他MQ快。

特性及适用场景
  • 高吞吐量、低延迟
  • 可扩展性:集群支持热扩展
  • 持久性、可靠性
  • 容错性:允许集群中节点失败(若副本数量为n,则允许n-1个节点失败)
  • 高并发:支持数千个客户端同时读写
常用场景
  • 日志收集
  • 消息系统:生产者和消费者、缓存消息等。
  • 用户活动跟踪:流网页、搜索、点击等活动
  • 运营指标
  • 工作流处理
  • 对实时性要求不高的数据处理

Kafka基础概念
Topic

Kafka 中可将消息分类,每一类的消息称为一个 Topic(主题),消费者可以对不同的 Topic 进行不同的处理。Topic相当于传统消息系统MQ中的一个队列queue,producer端发送的message必须指定是发送到哪个topic,但是不需要指定topic下的哪个partition,因为kafka会把收到的message进行load balance,均匀的分布在这个topic下的不同的partition上

Broker

每个 Broker(代理) 即一个 Kafka 服务实例,多个 Broker 构成一个 Kafka 集群,生产者发布的消息将保存在 Broker 中,消费者将从 Broker 中拉取消息进行消费。

producer

生产者

consumer

消费者

Partition

分区,Kafka 中比较特色的部分,一个 Topic 可以分为多个 Partition,每个 Partition 是一个有序的队列,Partition 中的每条消息都存在一个有序的偏移量(Offest) ,同一个 Consumer Group 中,只有一个 Consumer 实例可消费某个 Partition 的消息。

持久化

Kafka会把消息持久化到本地文件系统中,每个 Topic 将消息分成多 Partition,每个 Partition 在存储层面是 append log 文件。任何发布到此 Partition 的消息都会被直接追加到 log 文件的尾部,每条消息在文件中的位置称为 Offest(偏移量),Partition 是以文件的形式存储在文件系统中,log 文件根据 Broker 中的配置保留一定时间后删除来释放磁盘空间。

由于message的写入持久化是顺序写入的,因此message在被消费的时候也是按顺序被消费的,保证partition的message是顺序消费的。

看到上面的一堆特性,巴拉巴拉,一顿吹,道理我都懂,怎么操作,还是没看到效果。

别急,接下来就上代码,这个是不能少的。保证你们拿去就能用

上代码,demo测试
先创建两个接口,写好基础类库,后面直接应用就行了,我这里就直接放一起了
 /// <summary>
/// 消费者
/// </summary>
public interface IKafkaConsumer : IDisposable
{
/// <summary>
/// 消费数据
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
T Consume<T>() where T : class;
} public interface IKafkaProducer : IDisposable
{
/// <summary>
/// 发布消息
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="data"></param>
/// <param name="operateType"></param>
/// <returns></returns>
bool Produce<T>(string key, T data, int operateType) where T : class;
}

  实现方法

using Confluent.Kafka;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text; namespace Kafka
{
public class KafkaConsumer : IKafkaConsumer
{
private bool disposeHasBeenCalled = false;
private readonly object disposeHasBeenCalledLockObj = new object(); private readonly IConsumer<string, string> _consumer; /// <summary>
/// 构造函数,初始化配置
/// </summary>
/// <param name="config">配置参数</param>
/// <param name="topic">主题名称</param>
public KafkaConsumer(ConsumerConfig config, string topic)
{
_consumer = new ConsumerBuilder<string, string>(config).Build(); _consumer.Subscribe(topic);
} /// <summary>
/// 消费
/// </summary>
/// <returns></returns>
public T Consume<T>() where T : class
{
try
{
var result = _consumer.Consume(TimeSpan.FromSeconds(1));
if (result != null)
{
if (typeof(T) == typeof(string))
return (T)Convert.ChangeType(result.Value, typeof(T)); return JsonConvert.DeserializeObject<T>(result.Value);
}
}
catch (ConsumeException e)
{
Console.WriteLine($"consume error: {e.Error.Reason}");
}
catch (Exception e)
{
Console.WriteLine($"consume error: {e.Message}");
} return default;
} /// <summary>
/// 释放
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
} /// <summary>
/// Dispose
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
{
lock (disposeHasBeenCalledLockObj)
{
if (disposeHasBeenCalled) { return; }
disposeHasBeenCalled = true;
} if (disposing)
{
_consumer?.Close();
}
}
} }

  

 public class KafkaProducer : IKafkaProducer
{
private bool disposeHasBeenCalled = false;
private readonly object disposeHasBeenCalledLockObj = new object(); private readonly IProducer<string, string> _producer;
private readonly string _topic; /// <summary>
/// 构造函数,初始化配置
/// </summary>
/// <param name="config">配置参数</param>
/// <param name="topic">主题名称</param>
public KafkaProducer(ProducerConfig config, string topic)
{
_producer = new ProducerBuilder<string, string>(config).Build();
_topic = topic;
} /// <summary>
/// 发布消息
/// </summary>
/// <typeparam name="T">数据实体</typeparam>
/// <param name="key">数据key,partition分区会根据key</param>
/// <param name="data">数据</param>
/// <param name="operateType">操作类型[增、删、改等不同类型]</param>
/// <returns></returns>
public bool Produce<T>(string key, T data, int operateType) where T : class
{
var obj = JsonConvert.SerializeObject(new
{
Type = operateType,
Data = data
}); try
{
var result = _producer.ProduceAsync(_topic, new Message<string, string>
{
Key = key,
Value = obj
}).ConfigureAwait(false).GetAwaiter().GetResult(); #if DEBUG Console.WriteLine($"Topic: {result.Topic} Partition: {result.Partition} Offset: {result.Offset}");
#endif
return true; }
catch (ProduceException<string, string> e)
{
Console.WriteLine($"Delivery failed: {e.Error.Reason}");
}
catch (Exception e)
{
Console.WriteLine($"Delivery failed: {e.Message}");
} return false;
} /// <summary>
/// 释放
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
} /// <summary>
/// Dispose
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
{
lock (disposeHasBeenCalledLockObj)
{
if (disposeHasBeenCalled) { return; }
disposeHasBeenCalled = true;
} if (disposing)
{
_producer?.Dispose();
}
}
}

  

再写两个测试方法,一个发送消息,一个接收消息,控制台就好
注意  kafka 通过 topic 来接收消息 new KafkaProducer(config, "topic-c"))  发送方和接收方的topic要一致
 static void Main(string[] args)
{
var config = new ProducerConfig
{
BootstrapServers = "localhost:9092",
Acks = Acks.All
};
//发送消息 using (var kafkaProducer = new KafkaProducer(config, "topic-d"))
{
var result = kafkaProducer.Produce<object>("a", new { name = "猪八戒3" }, 1); }
Console.WriteLine("消息发送成功");
} static void Main(string[] args)
{
var config = new ConsumerConfig
{
BootstrapServers = "localhost:9092",
GroupId = "test",
AutoOffsetReset = AutoOffsetReset.Earliest
}; string text;
Console.WriteLine("接受中......");
while ((text = Console.ReadLine()) != "q")
{
//接受消息
using (var kafkaProducer = new KafkaConsumer(config, "topic-d"))
{
var result = kafkaProducer.Consume<object>();
if (result != null)
{
Console.WriteLine(result.ToString());
} }
} }

 上结果、

可以看到,消息已经收到了。这个demo里,消费端要一直处于正常状态才行,才能消费生产者得信息


本文版权归作者和博客园共有,来源网址:欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。

.net core kafka 入门实例 一篇看懂的更多相关文章

  1. springboot + kafka 入门实例 入门demo

    springboot + kafka 入门实例 入门demo 版本说明 springboot版本:2.3.3.RELEASE kakfa服务端版本:kafka_2.12-2.6.0.tgz zooke ...

  2. pyhton pandas数据分析基础入门(一文看懂pandas)

    //2019.07.17 pyhton中pandas数据分析基础入门(一文看懂pandas), 教你迅速入门pandas数据分析模块(后面附有入门完整代码,可以直接拷贝运行,含有详细的代码注释,可以轻 ...

  3. 《OD大数据实战》Kafka入门实例

    官网: 参考文档: Kafka入门经典教程 Kafka工作原理详解 一.安装zookeeper 1. 下载zookeeper-3.4.5-cdh5.3.6.tar.gz 下载地址为: http://a ...

  4. ASP.NET Core 快速入门(环境篇)

    [申明]:本人.NET Core小白.Linux小白.MySql小白.nginx小白.而今天要说是让你精通Linux ... 的开机与关机.nginx安装与部署.Core的Hello World .. ...

  5. 【转】ASP.NET Core 快速入门(环境篇)

    原文链接:http://www.cnblogs.com/zhaopei/p/netcore.html [申明]:本人.NET Core小白.Linux小白.MySql小白.nginx小白.而今天要说是 ...

  6. ASP.NET Core 快速入门(实战篇)

    上篇讲了<asp.net core在linux上的环境部署>.今天我们将做几个小玩意实战一下.用到的技术和工具有mysql.websocket.AngleSharp(爬虫html解析).n ...

  7. java web 入门实例servlet篇(显示后台数据库列表,删除某一条记录并显示)

    编写过程中需要注意的问题: 1.建立eclipse动态web工程时,需要改写编译后class文件的位置,通常情况下是这个位置:/WebContent/WEB-INF/classes 2.配置的页面链接 ...

  8. 一篇看懂Docker

    松勤教育2020.4.20 我要分享     Docker 是什么? Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口.它是目前最流行的 Linux 容器解决方案. Dock ...

  9. 一篇看懂JVM底层详解,利用class反编译文件了解文件执行流程

    JVM之内存结构详解 JVM内存结构 java虚拟机在执行程序的过程中会将内存划分为不同的区域,具体如图1-1所示. 五个区域 JVM分为五个区域:堆.虚拟机栈.本地方法栈.方法区(元空间).程序计数 ...

随机推荐

  1. 计算某天的下一天:黑盒测试之等价类划分+JUnit参数化测试

    题目要求 测试以下程序:该程序有三个输入变量month.day.year(month.day和year均为整数值,并且满足:1≤month≤12.1≤day≤31和1900≤year≤2050),分别 ...

  2. Unity 游戏框架搭建 2019 (三十六~三十八) partial与public

    在上一篇,我们把菜单的顺序从头到尾整理了一遍.在整理菜单顺序的过程中,记录了一个要做的事情. 要做的事情: (完成) 备份:导出文件,并取一个合理的名字. 整理完菜单顺序后,学习新的知识,解决随着示例 ...

  3. 《剑指Offer》- 连续子数组的最大和或最小和

    前言 本文是<剑指Offer>系列(JavaScript版)的第一篇,题目是"连续子数组的最大和或最小和". 话不多说,开始"打怪"修炼... 一. ...

  4. vagrant + 宝塔 环境搭建遇到的一些问题

    1.js时间戳单位为毫秒,php时间戳为秒. 2.tp里的where()方法如果where("id=".$id)不能用的话就用数组形式的:where(array("id& ...

  5. Django新手十个开发指导

    下面是关于Django新手开发中的一些建议,大家可以参考一下~~ 1,不要将项目名称包含在引用代码里 比如你创建了一个名为"project"的项目,包含一个名为"app& ...

  6. 如何在Vue项目中优雅的使用swiper插件

    个人网站 https://iiter.cn 程序员导航站 开业啦,欢迎各位观众姥爷赏脸参观,如有意见或建议希望能够不吝赐教! 开始之前,请先确保有一个基于webpack模板的项目(vue-cli脚手架 ...

  7. Clickhouse 时区转换

    Clickhouse 时区转换 ClickHouse是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS). OLAP场景的关键特征 大多数是读请求 数据总是以相当大的批(> 1000 ...

  8. Vim Configuration

    安装原生态的Vim之后,界面是这样的: 行号,没有:自动缩进,没有:括号匹配,没有~ 为了我们使用的方便,进行一些基本的配置: sudo vim /etc/vim/vimrc 进入配置界面: 如下图进 ...

  9. 使用Redis构建文章投票网站

    涉及到的key: 1. article_time, 记录文章的发布时间,zset结构 2. article_score, 记录文章的得分, zset结构 得分 = 发布时间 + 投票用户数 X 432 ...

  10. 学习vue第六节,v-if和v-show

    vue 中的v-if和v-show <!DOCTYPE html> <html> <head> <meta charset="utf-8" ...