Kafka Schema Registry | 学习Avro Schema
1.目标
在这个Kafka Schema Registry教程中,我们将了解Schema Registry是什么以及为什么我们应该将它与Apache Kafka一起使用。此外,我们将看到Avro架构演变的概念,并使用Kafka Avro Serializers设置和使用Schema Registry。此外,我们将学习使用Schema Registry的REST接口管理Avro Schemas。
那么,让我们讨论一下Apache Kafka Schema Registry。

Apache Kafka架构注册表
2.什么是Kafka Schema Registry?
基本上,对于Kafka Producers和Kafka Consumer,Kafka的 Schema Registry都存储Avro Schemas。
- 它提供了一个用于管理Avro架构的RESTful界面。
- 它允许存储版本化模式的历史记录。
- 此外,它还支持检查Kafka的架构兼容性。
- 使用Avro Schema,我们可以配置兼容性设置以支持Kafka模式的发展。
基本上,Kafka Avro序列化项目提供了序列化程序。在Avro和Kafka Schema Registry的帮助下,使用Kafka Avro序列化的Kafka Producers和Kafka Consumer都处理模式管理以及记录的序列化。

Kafka Schema Registry简介
此外,生产者在使用Kafka中的Confluent Schema Registry时不必发送模式,只需要唯一的模式ID。因此,为了从Confluent模式注册表中查找完整模式(如果尚未缓存),使用者使用模式ID。这意味着不必使用每组记录发送模式,这样也可以节省时间。
但是,Kafka制作人也创建了一条记录/消息,即Avro记录。该记录包含模式ID和数据。此外,如果需要,还会注册架构,然后使用Kafka Avro Serializer序列化数据和架构ID。
我们来讨论Apache Kafka架构及其基本概念
3.为什么在Kafka中使用Schema Registry?
消费者的架构可能与生产者的架构不同。在定义消费者模式时,消费者期望记录/消息符合要求。执行检查时,如果两个模式不匹配但兼容,则通过Avma Schema Evolution和Schema Registry进行有效负载转换。此外,Kafka记录可以有一个键和一个值,两者都可以有一个模式。
4. Kafka Schema注册局运营
但是,对于Kafka记录的键和值,Schema Registry可以存储模式。此外,它按主题列出模式。此外,它可以列出主题(模式)的所有版本。此外,它可以按版本或ID检索架构。并且可以获得最新版本的模式。
Apache Kafka架构注册表的一些兼容级别是向后,向前,完整,无。此外,我们可以通过REST API使用Schema注册表管理模式。
修改Apache Kafka操作和命令。
5. Kafka Schema兼容性设置
让我们了解所有兼容性级别。基本上,向后兼容性是指使用较旧模式编写的数据,可以使用较新的模式进行读取。此外,向前兼容性是指使用旧模式可读取使用较新模式编写的数据。此外,完全兼容性是指新版本的模式是向后兼容的。并且,“无”状态,意味着它禁用模式验证,不建议这样做。因此,Schema Registry只存储模式,如果我们将级别设置为“none”,它将不会验证兼容性。
一个。架构注册表配置
无论是全球还是每个主题。
兼容性值为:
A。无
表示不检查架构兼容性。
B.转发
说,检查以确保最后一个模式版本与新模式向前兼容。
C.向后(默认)
这意味着确保新模式向后兼容最新模式。
D. Full
“Full”表示确保新模式从最新到最新以及从最新到最新都是向前和向后兼容的。
阅读Storm Kafka与配置和代码的集成
6.架构演变
虽然,如果使用该架构的旧版本,在将数据写入存储后会更改Avro架构,那么当我们尝试读取该数据时,Avro可能会进行架构演变。
但是,从Kafka的角度来看,模式演变只发生在消费者的反序列化(阅读)中。并且,如果可能,则在反序列化期间自动修改值或键,以便在消费者的模式与生产者的模式不同时符合消费者的读取模式。
简而言之,它是消费者模式版本与生产者放入Kafka日志的模式之间的Avro模式的自动转换。但是,当消费者模式与用于序列化Kafka记录的生产者模式不同时,将对Kafka记录的键或值执行数据转换。虽然,如果模式匹配,则无需进行转换。
一个。模式演变过程中允许的修改
可以将具有默认值的字段添加到架构。我们可以删除具有默认值的字段。此外,我们可以更改字段的订单属性。此外,我们可以将字段的默认值更改为其他值,或者将默认值添加到没有字段的字段中。
但是,可以删除或添加字段别名,但这可能会导致某些依赖别名的使用者中断。此外,我们可以将类型更改为包含原始类型的联合。上述更改将导致我们的架构在使用旧架构读取时可以使用Avro的架构演变。
湾 修改架构的道路规则
如果我们想让我们的架构可以进化,我们必须遵循这些准则。首先,我们需要为模式中的字段提供默认值,因为这允许我们稍后删除该字段。请记住,永远不要更改字段的数据类型。此外,在向架构添加新字段时,我们必须为字段提供默认值。并且,请确保不要重命名现有字段(而是使用别名)。
我们来讨论Apache Kafka Streams | 流处理拓扑
例如:
- 员工示例Avro架构:
{"namespace": "com.dataflair.phonebook",
"type": "record",
"name": "Employee",
"doc" : "Represents an Employee at a company",
"fields": [
{"name": "firstName", "type": "string", "doc": "The persons given name"},
{"name": "nickName", "type": ["null", "string"], "default" : null},
{"name": "lastName", "type": "string"},
{"name": "age", "type": "int", "default": -},
{"name": "emails", "default":[], "type":{"type": "array", "items": "string"}},
{"name": "phoneNumber", "type":
[ "null",
{ "type": "record", "name": "PhoneNumber",
"fields": [
{"name": "areaCode", "type": "string"},
{"name": "countryCode", "type": "string", "default" : ""},
{"name": "prefix", "type": "string"},
{"name": "number", "type": "string"}
]
}
]
},
{"name":"status", "default" :"SALARY", "type": { "type": "enum", "name": "Status",
"symbols" : ["RETIRED", "SALARY", "HOURLY", "PART_TIME"]}
}
]
}
7. Avro Schema Evolution场景
假设在模式的版本1中,我们的员工记录没有年龄因素。但现在我们要添加一个默认值为-1的年龄字段。所以,假设我们有一个消费者使用版本1没有年龄,生产者使用模式的版本2与年龄
现在,通过使用Employee模式的版本2生产者,创建一个com.dataflair.Employee记录设置年龄字段到42,然后将其发送给Kafka主题new-Employees。之后,使用版本1,使用者将使用Employee架构的新员工记录。因此,在反序列化期间删除age字段只是因为使用者正在使用模式的版本1。
您是否知道Kafka和RabbitMQ之间的区别
此外,同一个消费者修改了一些记录,然后将记录写入NoSQL商店。因此,它写入NoSQL存储的记录中缺少age字段。现在,使用模式的第2版,另一个具有年龄的客户端从NoSQL存储中读取记录。因此,由于Consumer使用版本1编写它,因此记录中缺少age字段,因此客户端读取记录并将age设置为默认值-1。
因此,Schema Registry可以拒绝该模式,并且生产者永远不会将其添加到Kafka日志中,如果我们添加了年龄并且它不是可选的,即age字段没有默认值。
8.使用Schema Registry REST API
此外,通过使用以下操作,Kafka中的Schema Registry允许我们管理模式:
- 存储Kafka记录的键和值的模式
- 按主题列出模式
- 列出主题的所有版本(架构)
- 按版本检索架构
- 按ID检索架构
- 检索最新版本的架构
- 执行兼容性检查
- 全局设置兼容级别
您是否知道Apache Kafka职业范围及其薪资趋势
然而,所有这些都可通过REST API与Kafka中的Schema Registry一起获得。
我们可以执行以下操作,以便发布新架构:
一个。发布新架构
curl -X POST -H "Content-Type:
application/vnd.schemaregistry.v1+json" \
--data '{"schema": "{\"type\": …}’ \
http://localhost:8081/subjects/Employee/versions
湾 列出所有模式
curl -X GET http:// localhost:8081 / subject
我们基本上可以通过Schema Registry的REST接口执行上述所有操作,只有你有一个好的HTTP客户端。例如,Schema Registry使用Square中的OkHttp客户端(com.squareup.okhttp3:okhttp:3.7.0+)稍微好一点,如下所示:
使用REST端点尝试所有Schema Registry选项:
package com.dataflair.kafka.schema;
import okhttp3.*;
import java.io.IOException;
public class SchemaMain {
private final static MediaType SCHEMA_CONTENT =
MediaType.parse("application/vnd.schemaregistry.v1+json");
private final static String Employee_SCHEMA = "{\n" +
" \"schema\": \"" +
" {" +
" \\\"namespace\\\": \\\"com.dataflair.phonebook\\\"," +
" \\\"type\\\": \\\"record\\\"," +
" \\\"name\\\": \\\"Employee\\\"," +
" \\\"fields\\\": [" +
" {\\\"name\\\": \\\"fName\\\", \\\"type\\\": \\\"string\\\"}," +
" {\\\"name\\\": \\\"lName\\\", \\\"type\\\": \\\"string\\\"}," +
" {\\\"name\\\": \\\"age\\\", \\\"type\\\": \\\"int\\\"}," +
" {\\\"name\\\": \\\"phoneNumber\\\", \\\"type\\\": \\\"string\\\"}" +
" ]" +
" }\"" +
"}";
public static void main(String... args) throws IOException {
System.out.println(Employee_SCHEMA);
final OkHttpClient client = new OkHttpClient();
//POST A NEW SCHEMA
Request request = new Request.Builder()
.post(RequestBody.create(SCHEMA_CONTENT, Employee_SCHEMA))
.url("http://localhost:8081/subjects/Employee/versions")
.build();
String output = client.newCall(request).execute().body().string();
System.out.println(output);
//LIST ALL SCHEMAS
request = new Request.Builder()
.url("http://localhost:8081/subjects")
.build();
output = client.newCall(request).execute().body().string();
System.out.println(output);
//SHOW ALL VERSIONS OF Employee
request = new Request.Builder()
.url("http://localhost:8081/subjects/Employee/versions/")
.build();
output = client.newCall(request).execute().body().string();
System.out.println(output);
//SHOW VERSION 2 OF Employee
request = new Request.Builder()
.url("http://localhost:8081/subjects/Employee/versions/2")
.build();
output = client.newCall(request).execute().body().string();
System.out.println(output);
//SHOW THE SCHEMA WITH ID 3
request = new Request.Builder()
.url("http://localhost:8081/schemas/ids/3")
.build();
output = client.newCall(request).execute().body().string();
System.out.println(output);
//SHOW THE LATEST VERSION OF Employee 2
request = new Request.Builder()
.url("http://localhost:8081/subjects/Employee/versions/latest")
.build();
output = client.newCall(request).execute().body().string();
System.out.println(output);
//CHECK IF SCHEMA IS REGISTERED
request = new Request.Builder()
.post(RequestBody.create(SCHEMA_CONTENT, Employee_SCHEMA))
.url("http://localhost:8081/subjects/Employee")
.build();
output = client.newCall(request).execute().body().string();
System.out.println(output);
//TEST COMPATIBILITY
request = new Request.Builder()
.post(RequestBody.create(SCHEMA_CONTENT, Employee_SCHEMA))
.url("http://localhost:8081/compatibility/subjects/Employee/versions/latest")
.build();
output = client.newCall(request).execute().body().string();
System.out.println(output);
// TOP LEVEL CONFIG
request = new Request.Builder()
.url("http://localhost:8081/config")
.build();
output = client.newCall(request).execute().body().string();
System.out.println(output);
// SET TOP LEVEL CONFIG
// VALUES are none, backward, forward and full
request = new Request.Builder()
.put(RequestBody.create(SCHEMA_CONTENT, "{\"compatibility\": \"none\"}"))
.url("http://localhost:8081/config")
.build();
output = client.newCall(request).execute().body().string();
System.out.println(output);
// SET CONFIG FOR Employee
// VALUES are none, backward, forward and full
request = new Request.Builder()
.put(RequestBody.create(SCHEMA_CONTENT, "{\"compatibility\": \"backward\"}"))
.url("http://localhost:8081/config/Employee")
.build();
output = client.newCall(request).execute().body().string();
System.out.println(output);
}
}
我们建议运行该示例以尝试强制不兼容的架构到架构注册表,并且还要注意各种兼容性设置的行为。
C。运行Kafka架构注册表:
$ cat~ / tools / confluent-3.2.1 / etc / schema-registry / schema-registry.properties
listeners = http://0.0.0.0:8081
kafkastore.connection.url = localhost:2181
kafkastore.topic = _schemas
debug = false
~ / tools / confluent-3.2.1 / bin / schema-registry-start~ / tools / confluent-3.2.1 / etc / schema-registry / schema-registry.properties
9.撰写消费者和生产者
在这里,我们将要求启动指向ZooKeeper集群的Schema Registry服务器。此外,我们可能需要将Kafka Avro Serializer和Avro JAR导入我们的Gradle项目。之后,我们将要求配置生产者使用Schema Registry和KafkaAvroSerializer。此外,我们将要求将其配置为使用Schema Registry并使用KafkaAvroDeserializer来编写使用者。
因此,此构建文件显示了我们需要的Avro JAR文件。
阅读Apache Kafka Security | Kafka的需求和组成部分
- Kafka Avro Serializer示例的Gradle构建文件:
plugins {
id "com.commercehub.gradle.plugin.avro" version "0.9.0"
}
group 'dataflair'
version '1.0-SNAPSHOT'
apply plugin: 'java'
sourceCompatibility = 1.8
dependencies {
compile "org.apache.avro:avro:1.8.1"
compile 'com.squareup.okhttp3:okhttp:3.7.0'
testCompile 'junit:junit:4.11'
compile 'org.apache.kafka:kafka-clients:0.10.2.0'
compile 'io.confluent:kafka-avro-serializer:3.2.1'
}
repositories {
jcenter()
mavenCentral()
maven {
url "http://packages.confluent.io/maven/"
}
}
avro {
createSetters = false
fieldVisibility = "PRIVATE"
}
请记住包括Kafka Avro Serializer lib(io.confluent:kafka-avro-serializer:3.2.1)和Avro lib(org.apache.avro:avro:1.8.1)。
一个。写一个制片人
让我们按如下方式编写制作人。
- 使用Kafka Avro Serialization和Kafka Registry的制作人:
package com.dataflair.kafka.schema;
import com.dataflair.phonebook.Employee;
import com.dataflair.phonebook.PhoneNumber;
import io.confluent.kafka.serializers.KafkaAvroSerializerConfig;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.serialization.LongSerializer;
import io.confluent.kafka.serializers.KafkaAvroSerializer;
import java.util.Properties;
import java.util.stream.IntStream;
public class AvroProducer {
private static Producer<Long, Employee> createProducer() {
Properties props = new Properties();
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ProducerConfig.CLIENT_ID_CONFIG, "AvroProducer");
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,
LongSerializer.class.getName());
// Configure the KafkaAvroSerializer.
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,
KafkaAvroSerializer.class.getName());
// Schema Registry location.
props.put(KafkaAvroSerializerConfig.SCHEMA_REGISTRY_URL_CONFIG,
"http://localhost:8081");
return new KafkaProducer<>(props);
}
private final static String TOPIC = "new-Employees";
public static void main(String... args) {
Producer<Long, Employee> producer = createProducer();
Employee bob = Employee.newBuilder().setAge()
.setFirstName("Bob")
.setLastName("Jones")
.setPhoneNumber(
PhoneNumber.newBuilder()
.setAreaCode("")
.setCountryCode("")
.setPrefix("")
.setNumber("")
.build())
.build();
IntStream.range(, ).forEach(index->{
producer.send(new ProducerRecord<>(TOPIC, 1L * index, bob));
});
producer.flush();
producer.close();
}
}
另外,请确保我们将Schema Registry和KafkaAvroSerializer配置为生成器设置的一部分。
// Configure the KafkaAvroSerializer.
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,
KafkaAvroSerializer.class.getName());
// Schema Registry location. props.put(KafkaAvroSerializerConfig.SCHEMA_REGISTRY_URL_CONFIG,
"http://localhost:8081");
此外,我们按预期使用生产者
B 写一个消费者
之后,我们将写信给消费者。
- 使用Kafka Avro序列化和架构注册表的Kafka Consumer:
package com.dataflair.kafka.schema;
import com.dataflair.phonebook.Employee;
import io.confluent.kafka.serializers.KafkaAvroDeserializer;
import io.confluent.kafka.serializers.KafkaAvroDeserializerConfig;
import org.apache.kafka.clients.consumer.Consumer;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.common.serialization.LongDeserializer;
import java.util.Collections;
import java.util.Properties;
import java.util.stream.IntStream;
public class AvroConsumer {
private final static String BOOTSTRAP_SERVERS = "localhost:9092";
private final static String TOPIC = "new-Employee";
private static Consumer<Long, Employee> createConsumer() {
Properties props = new Properties();
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, BOOTSTRAP_SERVERS);
props.put(ConsumerConfig.GROUP_ID_CONFIG, "KafkaExampleAvroConsumer");
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,
LongDeserializer.class.getName());
//Use Kafka Avro Deserializer.
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,
KafkaAvroDeserializer.class.getName()); //<----------------------
//Use Specific Record or else you get Avro GenericRecord.
props.put(KafkaAvroDeserializerConfig.SPECIFIC_AVRO_READER_CONFIG, "true");
//Schema registry location.
props.put(KafkaAvroDeserializerConfig.SCHEMA_REGISTRY_URL_CONFIG,
"http://localhost:8081"); //<----- Run Schema Registry on 8081
return new KafkaConsumer<>(props);
}
public static void main(String... args) {
final Consumer<Long, Employee> consumer = createConsumer();
consumer.subscribe(Collections.singletonList(TOPIC));
IntStream.range(, ).forEach(index -> {
final ConsumerRecords<Long, Employee> records =
consumer.poll();
if (records.count() == ) {
System.out.println("None found");
} else records.forEach(record -> {
Employee EmployeeRecord = record.value();
System.out.printf("%s %d %d %s \n", record.topic(),
record.partition(), record.offset(), EmployeeRecord);
});
});
}
}
确保,我们必须告诉消费者在哪里找到注册表,与生产者一样,我们必须配置Kafka Avro反序列化器。
- 为消费者配置架构注册表:
//Use Kafka Avro Deserializer.
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,
KafkaAvroDeserializer.class.getName());
//Use Specific Record or else you get Avro GenericRecord.
props.put(KafkaAvroDeserializerConfig.SPECIFIC_AVRO_READER_CONFIG, "true");
//Schema registry location. props.put(KafkaAvroDeserializerConfig.SCHEMA_REGISTRY_URL_CONFIG,
"http://localhost:8081"); //<----- Run Schema Registry on 8081
此外,使用生成的Employee对象版本。因为,如果我们没有,而不是我们生成的Employee对象,那么它将使用Avro GenericRecord,这是一个SpecificRecord。
而且,我们需要启动Kafka和ZooKeeper,运行上面的例子:
- 运行ZooKeeper和Kafka:
kafka/bin/zookeeper-server-start.sh kafka/config/zookeeper.properties &
kafka/bin/kafka-server-start.sh kafka/config/server.properties
所以,这完全是关于Kafka Schema Registry的。希望你喜欢我们的解释。
体验最好的Apache Kafka Quiz Part-1 | 准备迎接挑战
10.结论
因此,我们看到Kafka Schema Registry为Kafka消费者和Kafka生产商管理Avro Schemas。此外,Avro还提供模式迁移,这对于流式传输和大数据架构非常重要。因此,我们已经向Kafka Schema Registry学习了整个概念。在这里,我们讨论了Kafka中Schema注册表的需求。
此外,我们还学习了模式注册表操作和兼容性设置。最后,我们看到了Kafka Avro Schema并使用了Schema Registry Rest API。最后,我们转向使用Schema注册表和Avro Serialization编写Kafka使用者和生产者
Kafka Schema Registry | 学习Avro Schema的更多相关文章
- Apache Avro & Avro Schema简介
为什么需要schema registry? 首先我们知道: Kafka将字节作为输入并发布 没有数据验证 但是: 如果Producer发送了bad data怎么办? 如果字段被重命名怎么办? 如果数据 ...
- Apache Kafka - Schema Registry
关于我们为什么需要Schema Registry? 参考, https://www.confluent.io/blog/how-i-learned-to-stop-worrying-and-love- ...
- Kafka:ZK+Kafka+Spark Streaming集群环境搭建(十四)定义一个avro schema使用comsumer发送avro字符流,producer接受avro字符流并解析
参考<在Kafka中使用Avro编码消息:Consumer篇>.<在Kafka中使用Avro编码消息:Producter篇> 在了解如何avro发送到kafka,再从kafka ...
- Spark(四十五):Schema Registry
很多时候在流数据处理时,我们会将avro格式的数据写入到kafka的topic,但是avro写入到kafka的时候,数据有可能会与版本升级,也就是schema发生变化,此时如果消费端,不知道哪些数据的 ...
- hadoop深入研究:(十八)——Avro schema兼容
转载请写明来源地址:http://blog.csdn.net/lastsweetop/article/details/9900129 所有源码在github上,https://github.com/l ...
- PostgreSQL学习----模式schema
PostgreSQL学习---模式schema 小序 接触PostgreSQL也有好长时间了,知识不总结梳理,似乎总不是自己的,继续努力吧少年!以此记录我的软件工艺之路! 模式(Schema) 一个 ...
- XSD(XML Schema Definition)学习笔记
今天学习了XSD相关的知识,为了以后查找的方便,写一些笔记. 一.什么是XSD? 1.XSD全称:XML Schema Definition.XML Schema 的作用是定义 XML 文档的合法构建 ...
- 数据库中间件DBLE学习(二) 学习配置schema.xml
前言 一边有一个经常引诱我让我"娱乐至死"的视频,还有一个不停"鞭策"我让我快点学习的大BOSS.正是有这两种极端的爱才让我常常在自信中明白自己努力的方向.嗯, ...
- rest-assured之Schema validation(包括JSON Schema validation及Xml Schema validation)
rest-assured从2.1.0版本开始支持 Schema 验证,包括JSON Schema validation及Xml Schema validation.我们之前断言响应体都是一个一个字段 ...
随机推荐
- 小a的学期 (组合数取模模板)
题目描述 小a是一个健忘的人,由于他经常忘记做作业,因此老师对他很恼火. 小a马上就要开学了,他学期一共2n 天,对于第i天,他有可能写了作业,也可能没写作业,不过他自己心里还有点B数,因此他会写恰好 ...
- LightOJ - 1333 - Grid Coloring
链接: https://vjudge.net/problem/LightOJ-1333 题意: You have to color an M x N two dimensional grid. You ...
- ztree异步加载---------补发周日内容
上周六老师要求和大三的进行JAVA知识交流,总体来说就是给大三学长做的东西打分,然后大三学长再教我们如果构建ztree.毕竟第一次接触ztree,所以有很多不了解,但通过周六日努力,还是做出来了.现在 ...
- python 生成文件到- execl
查了一些资料发现是英文版本的 很尴尬,经过看源码,和几个错误 ,现记录下来 一:下载包 pip install xlwt 二:定义样式 def set_style(name, height, bold ...
- 阿里云部署自己的web服务器
阿里云部署自己的web服务器 [外链图片转存失败(img-GIKNTPPx-1564287221547)(https://upload-images.jianshu.io/upload_images/ ...
- C博客作业01--分支丶顺序结构
1.本章学习总结 1.1学习内容总结 分支结构 if else-if语句与switch语句都具有选择判断的功能,但是在使用时又有所区别,按题目的不同要求与题意选择不同语句. if else-if语句表 ...
- GitHub 远程仓库 de 第一次配置
GitHub远程仓库, Git是分布式版本控制系统,同一个Git仓库,可以分布到不同的机器上.首先找一台电脑充当服务器的角色, 每天24小时开机,其他每个人都从这个“服务器”仓库克隆一份到自己的电脑上 ...
- 重新学习MySQL数据库12:从实践sql语句优化开始
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/a724888/article/details/79394168 本文不堆叠网上海量的sql优化技巧或 ...
- 第06组 Beta冲刺(4/4)
队名:福大帮 组长博客链接:https://www.cnblogs.com/mhq-mhq/p/11990575.html 作业博客 : https://edu.cnblogs.com/campus/ ...
- zookeeper安装运行(docker)
拉取镜像docker pull zookeeper:latest 获取镜像基本信息docker inspect zookeeper mkdir /opt/zookeeper -p vim /opt/z ...