Librdkafka是c语言实现的apachekafka的高性能客户端,为生产和使用kafka提供高效可靠的客户端,并且提供了c++接口

性能:

Librdkafka 是一款专为现代硬件使用而设计的高性能库,它尝试将内存复制保持在最小,可以让用户决定是需要高吞吐量还是低延迟的服务,性能调优的两个最重要的配置是:

*batch.num.messages:在发送消息之前累积在本地队列中等待的消息的最小数量。

*queue.buffering.max.ms:等待batch.num.messages多长时间来填写到本地队列中。

使用:

源码中的rdkafka.h、CONFIGURATION.md有Librdkafka的API的说明

初始化:

应用程序需要实例化一个顶级对象rd_kafka_t作为基础容器,提供全局配置和共享状态,调用rd_kafka_new()创建。

还需要实例化一个或多个topics(`rd_kafka_topic_t`)来提供生产或消费,topic对象保存topic特定的配置,并在内部填充所有可用分区和leader brokers,通过调用`rd_kafka_topic_new()`创建。

`rd_kafka_t``rd_kafka_topic_t`自带一个可选的配置API,如果没有调用API,Librdkafka将会使用CONFIGURATION.md中的默认配置。

注意

1.应用程序可能会创建多个`rd_kafka_t`对象,并且它们不共享任何状态

2.一个`rd_kafka_topic_t`对象仅可以用于创建它的`rd_kafka_t`对象

配置

为了简化与Apache Kafka官方软件的集成,降低学习曲线,librdkafka实现了与Apache Kafka官方客户端相同的配置属性。

使用`rd_kafka_conf_set()` 和`rd_kafka_topic_conf_set()`在创建对象之前应用配置。

注意:

`rd_kafka.._conf_t`对象在传递给rd_kafka.._new()`之后不可重复使用,调用`rd_kafka.._new()`后,应用程序不需要free任何配置资源。

例子

  1. rd_kafka_conf_t*conf;

  2. char errstr[512];

  3. conf = rd_kafka_conf_new();

  4. rd_kafka_conf_set(conf, "compression.codec","snappy", errstr, sizeof(errstr));

  5. rd_kafka_conf_set(conf, "batch.num.messages", "100",errstr, sizeof(errstr));

  6. rd_kafka_new(RD_KAFKA_PRODUCER,conf);

线程和回调函数

librdkafka内部使用多个线程来充分利用硬件资源.

API是线程安全的,应用程序可以在任意时间调用其线程内的任意api函数.

poll-based的API用于向应用程序提供信号,应用程序定期调用` rd_kafka_poll() `,poll API将会调用如下的API:

*消息传递报告回调函数:消息传递成功或失败的信号,允许应用程序释放消息中使用的任何应用程序资源。

*错误回调函数:发出错误信号,这些错误通常具有信息性质,例如连接broker失败,应用程序通常不需要做任何处理,错误的类型通过` rd_kafka_resp_err_t `枚举值传递,包括远程的broke错误和本地错误。

可选回调不是通过poll触发的,可以通过任意线程调用:

*Logging callback :允许应用程序输出librdkafka生成的日志消息

*partitioner callback:应用提供的消息分区器,可在任意时刻、任意线程中调用,对于相同的键,可以调用多次

Brokers

Librdkafka需要至少一个brokers的初始化list,称作` bootstrap brokers `,通过"metadata.broker.list"配置属性或`rd_kafka_brokers_add()`来指定,用来连接所有bootstrapbrokers,并查询每个元数据的信息,其中包含brokers、topic、partitions和它们在kafka cluster中的leaders的完整列表,

Brokers的名字被指定为"host[:port]",端口可选(默认9092),host是主机名或ip地址,如果主机解析到多个地址,librdkafka将轮询每个尝试连接的地址,因此,可以使用包含所有brokers地址的DNS记录来提供可靠的bootstrap broker。

Producer API

使用`RD_KAFKA_PRODUCER`设置了`rd_kafka_t`对象,并设置了一个或多个`rd_kafka_topic_t`对象后,librdkafka已经准备好接收要发送给brokers的消息。

`rd_kafka_produce()`函数有如下参数:

*`rkt` - 需要produce的topic,之前通过`rd_kafka_topic_new()`函数创

*`partition` - 生产到的partition,如果设置为`RD_KAFKA_PARTITION_UA`(UnAssigned),那么配置的分区函数将会用来选择目标分区。

*`msgflags` - 0,或者是:

* `RD_KAFKA_MSG_F_COPY` - librdkafka会立刻生成payload的一份拷贝,当payload在非持久化内存中(例如堆)时使用。

* `RD_KAFKA_MSG_F_FREE` - librdkafka使用完payload后,会使用`free(3)`将其释放。

这两个指标是互斥的,如果既不需要copy也不需要free,那么这两个指标都不需要设置。

如果`RD_KAFKA_MSG_F_COPY`没有设置,将不会执行数据的复制,librdkafka将会hold住payload的指针直到消息成功传输或传输失败。

当librdkafka完成消息的传递,使应用程序重新获得payload内存的所有权后,传递报告回调函数将会被调用

如果设置了`RD_KAFKA_MSG_F_FREE`,传递报告回调函数不能对payload进行free

*`payload`,`len` - 消息的payload

*`key`,`keylen` - 可以用来进行消息分区的消息键

它将被传递到topic分区回调函数(如果存在的话),并在发送给broker的时候附加在消息上

*`msg_opaque` - 应用程序提供的一个可选的每条消息的不透明指针,在消息回调函数中提供,让应用程序引用一个特定的指针。

`rd_kafka_produce()`是一个非阻塞API,它会在内部队列中排列消息并立即返回。如果已排列的消息个数超过了"queue.buffering.max.messages"配置项,`rd_kafka_produce()`返回-1并将errno设置为`ENOBUFS`,从而提供了一种背压机制

Simple Consumer API

NOTE: 对于高级KafkaConsumer接口,查看rd_kafka_subscribe(rdkafka.h) 或者 KafkaConsumer (rdkafkacpp.h)。

使用`RD_KAFKA_CONSUMER`和`rd_kafka_topic_t`实例创建`rd_kafka_t`后,应用程序还必须通过调用`rd_kafka_consume_start()`来为给定的分区启动consumer。

`rd_kafka_consume_start()` 参数:

* `rkt` - 需要消费的topic,之前通过`rd_kafka_topic_new()`创建。

 *`partition` - 从哪个分区消费

  *`offset` - 开始消费的消息offset,这可能是绝对消息偏移或两个特殊偏移之一:

`RD_KAFKA_OFFSET_BEGINNING` :从partition队列的起始位置开始消费(最老的message)

         `RD_KAFKA_OFFSET_END`:在下一个要生产到该partition上的消息处开始消费

         `RD_KAFKA_OFFSET_STORED`:使用存储的offset

一个topic+partition的consumer启动后,librdkafka将会尝试通过反复从broker获取批次消息以保持本地队列中保存"queued.min.messages"条消息,然后这个本地消息队列将会通过三个不同的consume API传递给应用程序:

*`rd_kafka_consume()` - consume单条消息

*`rd_kafka_consume_batch()` - consume单条或多条消息

*`rd_kafka_consume_callback()` - consume本地队列中的所有消息,并给每条消息调用一个回调函数

这三个API按照性能升序排列,`rd_kafka_consume()`最慢,`rd_kafka_consume_callback()`最快。

使用`rd_kafka_message_t`类型标识一条已消费的消息,其成员为:

*`err` - 发回到应用程序的错误信号,如果不为0,那么`payload`成员将被认为是一条错误消息,`err`是错误码(`rd_kafka_resp_err_t`),如果为0,`payload`则包含消息数据。

*`rkt`,`partition` - 该消息的topic和partition

*`payload`,`len` - payload消息,或者是错误信息(err!=0)

*`key`,`key_len` - 生产者指定的可选消息key

*`offset` - Message offset

`payload`和`key`以及整个消息的内存,属于librdkafka,调用`rd_kafka_message_destroy()`后不可再次使用,librdkafka将为该消息集的所有消息payloads共享相同的消息集接收缓冲存储器,以避免过度复制,这意味着如果应用程序决定hang on单个rd_kafka_message_t,它将阻止从相同消息集中释放所有其他消息的备份内存。

当应用程序完成从topic+partition的消息消费后,需要调用`rd_kafka_consume_stop()`来停止这个consumer,这也将清除本地队列中的当前的消息。

Offset management

broker version >= 0.9.0结合使用高版本的KafkaConsumer接口,可实现基于Broker的offset管理(查看rdkafka.h或 rdkafkacpp.h)

还可以通过本地文件存储来实现Offset管理,通过如下的topic配置参数,offset被永久写在本地文件中:

  * `auto.commit.enable`

  * `auto.commit.interval.ms`

  * `offset.store.path`

  * `offset.store.sync.interval.ms`

目前还没有对ZooKeeper的偏移量管理的支持。

Consumer groups

当kafka broker 版本>= 0.9 ,librdkafka支持基于broker的consumer groups

Topics

Librdkafka支持自动创建topic,broker需要配置"auto.create.topics.enable=true"

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

一.编译librdkafka

环境:Fedora 20,32位

依赖:pthreads(必选),zlib(可选),libssl-dev(可选),libsasl2-dev(可选)

先查看自己的linux上是否安装了pthreads,指令如下:

# locate libpthread

因为我之前安过了,所以可以直接编译librdkafka,没有安的下个pthreads的源码——configure、make、make install。

开始编译librdkafka,指令如下:

  1. # ./configure

  2. # make

  3. # make install

lib库会被默认安装到/usr/local/lib目录

头文件被默认安装到/usr/local/include/librdkafka目录

二.生产者

新建Qt控制台工程KafkaProducer,Pro文件如下:

  1. #-------------------------------------------------

  2. #

  3. # Project created by QtCreator 2018-03-27T19:45:09

  4. #

  5. #-------------------------------------------------

  6. QT -= gui core

  7. TARGET = KafkaProducer

  8. CONFIG += console

  9. CONFIG -= app_bundle

  10. TEMPLATE = app

  11. SOURCES += main.cpp

  12. INCLUDEPATH += /usr/local/include/librdkafka

  13. LIBS += -L/usr/local/lib -lrdkafka

  14. LIBS += -L/usr/local/lib -lrdkafka++

main.cpp文件如下:

  1. #include <iostream>

  2. #include <string>

  3. #include <cstdlib>

  4. #include <cstdio>

  5. #include <csignal>

  6. #include <cstring>

  7. #include <getopt.h>

  8. #include "rdkafkacpp.h"

  9. static bool run = true;

  10. static void sigterm (int sig) {

  11. run = false;

  12. }

  13. class ExampleDeliveryReportCb : public RdKafka::DeliveryReportCb {

  14. public:

  15. void dr_cb (RdKafka::Message &message) {

  16. std::cout << "Message delivery for (" << message.len() << " bytes): " <<

  17. message.errstr() << std::endl;

  18. if (message.key())

  19. std::cout << "Key: " << *(message.key()) << ";" << std::endl;

  20. }

  21. };

  22. class ExampleEventCb : public RdKafka::EventCb {

  23. public:

  24. void event_cb (RdKafka::Event &event) {

  25. switch (event.type())

  26. {

  27. case RdKafka::Event::EVENT_ERROR:

  28. std::cerr << "ERROR (" << RdKafka::err2str(event.err()) << "): " <<

  29. event.str() << std::endl;

  30. if (event.err() == RdKafka::ERR__ALL_BROKERS_DOWN)

  31. run = false;

  32. break;

  33. case RdKafka::Event::EVENT_STATS:

  34. std::cerr << "\"STATS\": " << event.str() << std::endl;

  35. break;

  36. case RdKafka::Event::EVENT_LOG:

  37. fprintf(stderr, "LOG-%i-%s: %s\n",

  38. event.severity(), event.fac().c_str(), event.str().c_str());

  39. break;

  40. default:

  41. std::cerr << "EVENT " << event.type() <<

  42. " (" << RdKafka::err2str(event.err()) << "): " <<

  43. event.str() << std::endl;

  44. break;

  45. }

  46. }

  47. };

  48. int main ()

  49. {

  50. std::string brokers = "localhost";

  51. std::string errstr;

  52. std::string topic_str="test";

  53. int32_t partition = RdKafka::Topic::PARTITION_UA;

  54. RdKafka::Conf *conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL);

  55. RdKafka::Conf *tconf = RdKafka::Conf::create(RdKafka::Conf::CONF_TOPIC);

  56. conf->set("bootstrap.servers", brokers, errstr);

  57. ExampleEventCb ex_event_cb;

  58. conf->set("event_cb", &ex_event_cb, errstr);

  59. signal(SIGINT, sigterm);

  60. signal(SIGTERM, sigterm);

  61. ExampleDeliveryReportCb ex_dr_cb;

  62. conf->set("dr_cb", &ex_dr_cb, errstr);

  63. RdKafka::Producer *producer = RdKafka::Producer::create(conf, errstr);

  64. if (!producer) {

  65. std::cerr << "Failed to create producer: " << errstr << std::endl;

  66. exit(1);

  67. }

  68. std::cout << "% Created producer " << producer->name() << std::endl;

  69. RdKafka::Topic *topic = RdKafka::Topic::create(producer, topic_str,

  70. tconf, errstr);

  71. if (!topic) {

  72. std::cerr << "Failed to create topic: " << errstr << std::endl;

  73. exit(1);

  74. }

  75. for (std::string line; run && std::getline(std::cin, line);) {

  76. if (line.empty()) {

  77. producer->poll(0);

  78. continue;

  79. }

  80. RdKafka::ErrorCode resp =

  81. producer->produce(topic, partition,

  82. RdKafka::Producer::RK_MSG_COPY /* Copy payload */,

  83. const_cast<char *>(line.c_str()), line.size(),

  84. NULL, NULL);

  85. if (resp != RdKafka::ERR_NO_ERROR)

  86. std::cerr << "% Produce failed: " <<

  87. RdKafka::err2str(resp) << std::endl;

  88. else

  89. std::cerr << "% Produced message (" << line.size() << " bytes)" <<

  90. std::endl;

  91. producer->poll(0);

  92. }

  93. run = true;

  94. // 退出前处理完输出队列中的消息

  95. while (run && producer->outq_len() > 0) {

  96. std::cerr << "Waiting for " << producer->outq_len() << std::endl;

  97. producer->poll(1000);

  98. }

  99. delete conf;

  100. delete tconf;

  101. delete topic;

  102. delete producer;

  103. RdKafka::wait_destroyed(5000);

  104. return 0;

  105. }

三.消费者

新建Qt控制台工程KafkaConsumer,Pro文件如下:

  1. #-------------------------------------------------

  2. #

  3. # Project created by QtCreator 2018-03-28T16:27:54

  4. #

  5. #-------------------------------------------------

  6. QT -= gui core

  7. TARGET = KafkaConsumer

  8. CONFIG += console

  9. CONFIG -= app_bundle

  10. TEMPLATE = app

  11. SOURCES += main.cpp

  12. INCLUDEPATH += /usr/local/include/librdkafka

  13. LIBS += -L/usr/local/lib -lrdkafka

  14. LIBS += -L/usr/local/lib -lrdkafka++

main.cpp文件如下:

  1. #include <iostream>

  2. #include <string>

  3. #include <cstdlib>

  4. #include <cstdio>

  5. #include <csignal>

  6. #include <cstring>

  7. #include <sys/time.h>

  8. #include <getopt.h>

  9. #include <unistd.h>

  10. #include "rdkafkacpp.h"

  11. static bool run = true;

  12. static bool exit_eof = true;

  13. static int eof_cnt = 0;

  14. static int partition_cnt = 0;

  15. static int verbosity = 1;

  16. static long msg_cnt = 0;

  17. static int64_t msg_bytes = 0;

  18. static void sigterm (int sig) {

  19. run = false;

  20. }

  21. class ExampleEventCb : public RdKafka::EventCb {

  22. public:

  23. void event_cb (RdKafka::Event &event) {

  24. switch (event.type())

  25. {

  26. case RdKafka::Event::EVENT_ERROR:

  27. std::cerr << "ERROR (" << RdKafka::err2str(event.err()) << "): " <<

  28. event.str() << std::endl;

  29. if (event.err() == RdKafka::ERR__ALL_BROKERS_DOWN)

  30. run = false;

  31. break;

  32. case RdKafka::Event::EVENT_STATS:

  33. std::cerr << "\"STATS\": " << event.str() << std::endl;

  34. break;

  35. case RdKafka::Event::EVENT_LOG:

  36. fprintf(stderr, "LOG-%i-%s: %s\n",

  37. event.severity(), event.fac().c_str(), event.str().c_str());

  38. break;

  39. case RdKafka::Event::EVENT_THROTTLE:

  40. std::cerr << "THROTTLED: " << event.throttle_time() << "ms by " <<

  41. event.broker_name() << " id " << (int)event.broker_id() << std::endl;

  42. break;

  43. default:

  44. std::cerr << "EVENT " << event.type() <<

  45. " (" << RdKafka::err2str(event.err()) << "): " <<

  46. event.str() << std::endl;

  47. break;

  48. }

  49. }

  50. };

  51. void msg_consume(RdKafka::Message* message, void* opaque) {

  52. switch (message->err()) {

  53. case RdKafka::ERR__TIMED_OUT:

  54. //std::cerr << "RdKafka::ERR__TIMED_OUT"<<std::endl;

  55. break;

  56. case RdKafka::ERR_NO_ERROR:

  57. /* Real message */

  58. msg_cnt++;

  59. msg_bytes += message->len();

  60. if (verbosity >= 3)

  61. std::cerr << "Read msg at offset " << message->offset() << std::endl;

  62. RdKafka::MessageTimestamp ts;

  63. ts = message->timestamp();

  64. if (verbosity >= 2 &&

  65. ts.type != RdKafka::MessageTimestamp::MSG_TIMESTAMP_NOT_AVAILABLE) {

  66. std::string tsname = "?";

  67. if (ts.type == RdKafka::MessageTimestamp::MSG_TIMESTAMP_CREATE_TIME)

  68. tsname = "create time";

  69. else if (ts.type == RdKafka::MessageTimestamp::MSG_TIMESTAMP_LOG_APPEND_TIME)

  70. tsname = "log append time";

  71. std::cout << "Timestamp: " << tsname << " " << ts.timestamp << std::endl;

  72. }

  73. if (verbosity >= 2 && message->key()) {

  74. std::cout << "Key: " << *message->key() << std::endl;

  75. }

  76. if (verbosity >= 1) {

  77. printf("%.*s\n",

  78. static_cast<int>(message->len()),

  79. static_cast<const char *>(message->payload()));

  80. }

  81. break;

  82. case RdKafka::ERR__PARTITION_EOF:

  83. /* Last message */

  84. if (exit_eof && ++eof_cnt == partition_cnt) {

  85. std::cerr << "%% EOF reached for all " << partition_cnt <<

  86. " partition(s)" << std::endl;

  87. run = false;

  88. }

  89. break;

  90. case RdKafka::ERR__UNKNOWN_TOPIC:

  91. case RdKafka::ERR__UNKNOWN_PARTITION:

  92. std::cerr << "Consume failed: " << message->errstr() << std::endl;

  93. run = false;

  94. break;

  95. default:

  96. /* Errors */

  97. std::cerr << "Consume failed: " << message->errstr() << std::endl;

  98. run = false;

  99. }

  100. }

  101. class ExampleConsumeCb : public RdKafka::ConsumeCb {

  102. public:

  103. void consume_cb (RdKafka::Message &msg, void *opaque) {

  104. msg_consume(&msg, opaque);

  105. }

  106. };

  107. int main () {

  108. std::string brokers = "localhost";

  109. std::string errstr;

  110. std::string topic_str="test";

  111. std::vector<std::string> topics;

  112. std::string group_id="101";

  113. RdKafka::Conf *conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL);

  114. RdKafka::Conf *tconf = RdKafka::Conf::create(RdKafka::Conf::CONF_TOPIC);

  115. //group.id必须设置

  116. if (conf->set("group.id", group_id, errstr) != RdKafka::Conf::CONF_OK) {

  117. std::cerr << errstr << std::endl;

  118. exit(1);

  119. }

  120. topics.push_back(topic_str);

  121. //bootstrap.servers可以替换为metadata.broker.list

  122. conf->set("bootstrap.servers", brokers, errstr);

  123. ExampleConsumeCb ex_consume_cb;

  124. conf->set("consume_cb", &ex_consume_cb, errstr);

  125. ExampleEventCb ex_event_cb;

  126. conf->set("event_cb", &ex_event_cb, errstr);

  127. conf->set("default_topic_conf", tconf, errstr);

  128. signal(SIGINT, sigterm);

  129. signal(SIGTERM, sigterm);

  130. RdKafka::KafkaConsumer *consumer = RdKafka::KafkaConsumer::create(conf, errstr);

  131. if (!consumer) {

  132. std::cerr << "Failed to create consumer: " << errstr << std::endl;

  133. exit(1);

  134. }

  135. std::cout << "% Created consumer " << consumer->name() << std::endl;

  136. RdKafka::ErrorCode err = consumer->subscribe(topics);

  137. if (err) {

  138. std::cerr << "Failed to subscribe to " << topics.size() << " topics: "

  139. << RdKafka::err2str(err) << std::endl;

  140. exit(1);

  141. }

  142. while (run) {

  143. //5000毫秒未订阅到消息,触发RdKafka::ERR__TIMED_OUT

  144. RdKafka::Message *msg = consumer->consume(5000);

  145. msg_consume(msg, NULL);

  146. delete msg;

  147. }

  148. consumer->close();

  149. delete conf;

  150. delete tconf;

  151. delete consumer;

  152. std::cerr << "% Consumed " << msg_cnt << " messages ("

  153. << msg_bytes << " bytes)" << std::endl;

  154. //应用退出之前等待rdkafka清理资源

  155. RdKafka::wait_destroyed(5000);

  156. return 0;

  157. }

四.测试

先启动zookeeper服务和kafka服务,详见:kafka的编译和使用,然后再启动生产者和消费者。

生产者循环等待用户输入,输入后回车,消息就发布出去了,此时消费者显示订阅到的内容。

转载地址:

https://blog.csdn.net/lijinqi1987/article/details/76571757

https://blog.csdn.net/caoshangpa/article/details/79786100

kafka的c/c++高性能客户端librdkafka简介/使用librdkafka的C++接口实现简单的生产者和消费者相关推荐

  1. 使用librdkafka的C++接口实现简单的生产者和消费者

    https://blog.csdn.net/caoshangpa/article/details/79786100

  2. kafka的c/c++高性能客户端librdkafka简介

    Librdkafka是c语言实现的apachekafka的高性能客户端,为生产和使用kafka提供高效可靠的客户端,并且提供了c++接口 性能: Librdkafka 是一款专为现代硬件使用而设计的高 ...

  3. java最简单的kafka生产者和消费者,未结合spring

    目录 1 最简单的生产者和消费者 1.1 引入maven 1.2 基本的生产者和代码注释 1.3 最简单消费者 2 生产者发送消息的三种方式 2.1 直接send之后就不管了,会自动重试,可能丢失消息 ...

  4. Kafka : Kafka入门教程和JAVA客户端使用

    目录 目录 Kafka简介 环境介绍 术语介绍 消费模式 下载 集群安装配置 命令使用 JAVA实战 参考文献 Kafka简介 由Scala和Java编写,Kafka是一种高吞吐量的分布式发布订阅消息 ...

  5. Kafka是如何实现高性能的?

    序 在分布式消息中,消息队列中应用最广泛的是 Kafka 和 RocketMQ,故今天我们就一起来看一下,Kafka 是如何实现高性能的. Kafka 的高性能 不知道你有没有了解过自己电脑的配置? ...

  6. Kafka SSL服务配置及客户端使用(Linux+Pykafka)

    内容:1: Kafka及Zookeeper快速安装配置及测试2: Kafka SSL服务端配置3: Kafka 客户端3.1: Linux下配置及测试3.2: Pykafka配置及测试4: 脚本5: ...

  7. linux瘦终端系统,Thinstation 桌面云瘦客户端操作系统简介

    想要构建桌面云瘦客户端操作系统可以参考开源的Thinstation.git 库地址https://github.com/Thinstation/thinstation.git . Thinstatio ...

  8. Windows客户端开发简介(二)

    Windows客户端开发简介(二) 一个典型的Windows客户端程序要有哪几部分构成呢?下面我会以一个国内比较流行的互联网客户端程序的基本架构来跟大家逐步展开分析,由于涉及到知识产权的问题,请大家不 ...

  9. kafka学习总结(含java生产者、消费者、Topic操作代码)

    kafka(http://kafka.apache.org)是一款分布式消息发布和订阅的系统,具有高性能和高吞吐率.它的优点是能够直接使用磁盘进行存储.线性读写.速度快,避免了数据在JVM内存和系统内 ...

最新文章

  1. 信号与系统作业问题回复
  2. type=InnoDB ENGINE=InnoDB
  3. pyqt 弹出全屏窗口_pyqt5-QWidget-窗口状态(最大化最小化等)
  4. 精彩回顾 | Apache Flink x Iceberg Meetup · 上海站
  5. java线程池(ThreadPool)
  6. 学会“量体裁衣”去赚钱
  7. 获取棋盘格与标准模板在扫描仪上不同位置图片
  8. 淘宝优惠券去哪里领?
  9. H5调用安卓以及IOS前置摄像头
  10. php根据出生日期计算年龄函数
  11. 计算机系军训口号四句霸气,军训口号四句霸气中队
  12. 【源码之下无秘密】ArrayList:在内存只有10M的空间中申请一块5M的数组空间,会导致OOM吗?
  13. 玩转Openwrt(二) — 配合Android手机打造无线音乐播放器
  14. python多张图片生成ppt_天呐,还能这么玩!用 Python 生成动态 PPT
  15. C# 调用钉钉接口进行发送企业通知消息,适应于网页版
  16. Jquery的简单使用
  17. 解决EXCEL中选中单元格右键被屏蔽的问题
  18. APS计划排程系统有哪些优势?
  19. db2 10.1 数据库文件介绍
  20. 8点办~互联网公司加班该不该有加班费

热门文章

  1. 《Oracle数据库管理与维护实战》——1.2 Oracle各版本异同
  2. 【深度优先搜索】一个实例+两张动图彻底理解 DFS | DFS 与 BFS 的区别 | 用 DFS 自动控制我们的小游戏
  3. 不敢去争取,学不会珍惜,却难以忘记——dbGet(三)
  4. mysql 升级高可用_MySQL高可用方案升级规划
  5. FPGA实现VGA显示(三)——————单个字符显示
  6. 【VerySky原创】怎么查找系统中的锁对象
  7. [转]苦逼男和女神之间的经典对话,亲身经历过的有木有啊,必须转。。。
  8. [黑金原创教程][连载][iBoard 电子学堂][第〇卷 电子基础]第一篇 认识电子元器件...
  9. fcpx调整图层_【FCPX萌新系列】新手常遇到的4个基础调色问题
  10. 已解决:手动打包war包结果无法在Tomcat中部署