ZooKeeper教程

Zookeeper简介

ZooKeeper 是 Apache 软件基金会的一个软件项目,它为大型分布式计算提供开源的分布式配置服务、同步服务和命名注册。

ZooKeeper 的架构通过冗余服务实现高可用性。

简单来说zookeeper=文件系统的数据模型结构+监听通知机制(Watch)

Zookeeper的数据模型结构很像数据结构当中的树,也很像文件系统中的目录。

树是由所有节点组成,Zookeeper的数据存储也同样是基于节点,这种节点叫做Znode

但是,不同于树的节点,Znode的引用方式是路径引用,类似于文件系统,通过路径进行访问数据,而redis是根据key值来访问数据

Zookeeper的安装

官网地址-> Zookeeper

安装、启动命令:

1
2
3
4
5
6
tar xvf apache-zookeeper-3.7.0-bin.tar.gz
cd apache-zookeeper-3.7.0-bin
cd conf
cp zoo_sample.cfg zoo.cfg
cd ../bin
sh zkServer.sh start

执行后,服务启动成功

查看服务状态

配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/tmp/zookeeper
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60

默认端口号是2181

zookeeper 数据结构

zookkeeper 提供的名称空间非常类似于标准文件系统,整体结构类似于 linux 文件系统的模式以树形结构存储。其中根路径以 / 开头。所有存储的数据是由 znode 组成的,节点也称为 znode,并以 key/value 形式存储数据。
zookeeper 名称空间中的每个节点都是由一个路径标识.

进入 zookeeper 安装的 bin 目录,通过sh zkCli.sh打开命令行终端,执行 “ls /“ 命令显示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
./zkCli.sh
# 查看节点
[zk: localhost:2181(CONNECTED) 0] ls /
[zookeeper]

# 创建节点/yiny并赋值 123,创建节点时,必须要带上全路径
[zk: localhost:2181(CONNECTED) 1] create -e /yiny 123
Created /yiny

# 再次查看节点,确认除了zookeeper节点以外新增了yiny节点
[zk: localhost:2181(CONNECTED) 2] ls /
[yiny, zookeeper]

# 查看/zookeeper节点的内容
[zk: localhost:2181(CONNECTED) 4] ls /zookeeper
[config, quota]

# 使用get命令获取节点存储的数据
[zk: localhost:2181(CONNECTED) 5] get /yiny
123

# 使用set命令修改节点存储的数据
[zk: localhost:2181(CONNECTED) 6] set /yiny abc
[zk: localhost:2181(CONNECTED) 7] get /yiny
abc

# 使用delete命令删除节点
[zk: localhost:2181(CONNECTED) 8] delete /yiny
[zk: localhost:2181(CONNECTED) 9] ls /yiny
Node does not exist: /yiny

ZooKeeper的基本操作

命令 功能
create 创建节点
delete 删除节点
exists 判断节点是否存在
getData 获得一个节点的数据
setData 设置一个节点的数据
getChildren 获取节点下的所有节点

Dubbo教程

Dubbo-admin简介

Dubbo-admin是Dubbo RPC框架的“管理端”,可以对注册的服务(provider)和服务调用方(comsumer)进行服务治理,包括路由、监控、配置等功能;

Dubbo一般都是使用zookeeper来进行管理服务注册,而dubbo-admin查看哪些注册了哪些服务,也是需要从zk上查询的,所以Dubbo-admin需要依赖于zookeeper;

另外,Dubbo-admin是一个web项目(spring-boot),提供了管理端页面,页面是使用vue框架,所以需要安装node环境;

对于zookeeper和node的相关安装配置,这里就不在阐述。

Dubbo-admin项目

github地址:https://github.com/apache/dubbo-admin

在项目目录下打包dubbo-admin

1
mvn clean package -Dmaven.test.skip=true

这是一个SpringBoot项目,也可以导入到IDEA中,双击Maven面板中的package按钮来进行构建。
构建之后的结果文件生成在:project-dir/dubbo-admin-distribution/target/dubbo-admin-0.3.0-SNAPSHOT.jar

运行

运行Dubbo-Admin前需要先启动ZooKeeper:

1
2
# 启动ZooKeeper
/Users/yiny/soft/apache-zookeeper-3.7.0-bin/bin/zkServer.sh start

这里需要注意的是,需要修改ZooKeeper使用的默认端口,否则在启动Dubbo-admin的时候会出现端口被占用的情况。修改方法为修改zoo.cfg,在最后添加:

1
admin.serverPort=38080

然后再次使用lsof -i tcp:38080来查看端口占用情况。

1
2
3
# 启动Dubbo-Admin
# java -jar dubbo-admin-0.0.1-SNAPSHOT.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/bin/java -jar /Users/yiny/Sites/dubbo-admin/dubbo-admin-distribution/target/dubbo-admin-0.3.0-SNAPSHOT.jar

然后使用浏览器访问:http://localhost:8080
用户名密码都是root/root
即可看到Dubbo-Admin界面了。

使用Docker搭建Dubbo-Admin环境

1
docker pull apache/dubbo-admin:latest

微服务两种架构方案的比较

  • Spring Boot + Spring Cloud 组件多,功能完备, Http通讯,俗称SpringCloud全家桶 ->微服务架构解决方案一

  • Spring Boot+Dubbo+Zookeeper 组件少,功能非完备 Alibaba Dubbo ->RPC通讯框架 ->微服务架构解决方案二

微服务架构是一种思想,实现方案是分布式系统,分布式系统最大的问题 -> 网络是不可靠的。

什么是分布式锁

Zookeeper 分布式协调服务: 解决分布式系统当中多个进程之间的同步控制,让他们有序的访问某种临界资源,防止造成脏数据的后果。

为了防止分布式系统中的多个进程之间相互干扰,用分布式协调技术对这种进程进行调度,而分布式协调技术的核心就是分布式锁

分布式锁: 在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行。

Dubbo-Admin + ZooKeeper 服务注册与发现配置

  1. 新建dubbo-zk-api的Maven项目
1
2
3
4
5
6
7
8
9
@Component
public interface TicketService {
String getTicket();
}

@Component
public interface UserService {
String sayHi();
}
  1. 新建provider的SpringBoot服务项目,并导入依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<!-- 导入依赖 Dubbo + ZooKeeper -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.3</version>
</dependency>

<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>

<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>

<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.12.0</version>
</dependency>

<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.14</version>

<!-- 排除这个slf4j-log4j12 -->
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cn.geekhall</groupId>
<artifactId>dubbo-zk-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

properties配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 端口
server.port=8001

# 服务应用名字
dubbo.application.name=dubbo-zk-provider

# 注册中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181

# 哪些服务要被注册
dubbo.scan.base-packages=cn.geekhall.service

dubbo.application.protocol=dubbo

新建服务接口实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package cn.geekhall.service;

import org.apache.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component;

@Service //这里的Service注解是Dubbo的,可以被扫描到,在项目一启动就自动注册到注册中心
@Component
public class TicketServiceImpl implements TicketService {
@Override
public String getTicket() {
return "极客堂";
}
}

@Service
@Component
public class UserServiceImpl implements UserService {
@Override
public String sayHi() {
return "Hi geek!";
}
}

启动服务后,在Dubbo-admin后台即可看到服务:

  1. 新建Consumer的SpringBoot服务项目,并导入依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<!-- 导入依赖 Dubbo + ZooKeeper -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.3</version>
</dependency>

<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>

<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>

<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.12.0</version>
</dependency>

<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.14</version>

<!-- 排除这个slf4j-log4j12 -->
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cn.geekhall</groupId>
<artifactId>dubbo-zk-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

application.properties配置:

1
2
3
4
5
6
7
8
# 服务端口
server.port=8002

# 消费者去哪里拿服务需要暴露自己的名字
dubbo.application.name=dubbo-zk-consumer

# 注册中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181

Customer代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package cn.geekhall.service;

import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;

@Service // 这里的Service是Spring的,放到容器中即可
public class UserService {

// 想拿到provider提供的票,要去注册中心拿到服务
@Reference(timeout = 30000) // 引用 , Pom坐标,可以定义路径相同的接口名
TicketService ticketService;

public void buyTicket(){
String ticket = ticketService.getTicket();
System.out.println("在注册中心拿到 ====> " + ticket);
}
}

运行Consumer,得到运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
2021-08-08 14:22:05.029  INFO 54035 --- [           main] c.g.DubboZkConsumerApplicationTests      : Starting DubboZkConsumerApplicationTests using Java 1.8.0_251 on MacBook-Pro with PID 54035 (started by yiny in /Users/yiny/Sites/java_demo/dubbo-zk-consumer)
2021-08-08 14:22:05.052 INFO 54035 --- [ main] c.g.DubboZkConsumerApplicationTests : No active profile set, falling back to default profiles: default
2021-08-08 14:22:05.440 INFO 54035 --- [ main] .a.d.c.s.c.a.DubboConfigBindingRegistrar : The dubbo config bean definition [name : org.apache.dubbo.config.ApplicationConfig#0, class : org.apache.dubbo.config.ApplicationConfig] has been registered.
2021-08-08 14:22:05.441 INFO 54035 --- [ main] .a.d.c.s.c.a.DubboConfigBindingRegistrar : The BeanPostProcessor bean definition [org.apache.dubbo.config.spring.beans.factory.annotation.DubboConfigBindingBeanPostProcessor] for dubbo config bean [name : org.apache.dubbo.config.ApplicationConfig#0] has been registered.
2021-08-08 14:22:05.441 INFO 54035 --- [ main] .a.d.c.s.c.a.DubboConfigBindingRegistrar : The dubbo config bean definition [name : org.apache.dubbo.config.RegistryConfig#0, class : org.apache.dubbo.config.RegistryConfig] has been registered.
2021-08-08 14:22:05.441 INFO 54035 --- [ main] .a.d.c.s.c.a.DubboConfigBindingRegistrar : The BeanPostProcessor bean definition [org.apache.dubbo.config.spring.beans.factory.annotation.DubboConfigBindingBeanPostProcessor] for dubbo config bean [name : org.apache.dubbo.config.RegistryConfig#0] has been registered.
2021-08-08 14:22:05.622 INFO 54035 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration' of type [org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration$$EnhancerBySpringCGLIB$$8b980fda] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2021-08-08 14:22:05.727 INFO 54035 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.apache.dubbo.spring.boot.autoconfigure.DubboRelaxedBinding2AutoConfiguration' of type [org.apache.dubbo.spring.boot.autoconfigure.DubboRelaxedBinding2AutoConfiguration$$EnhancerBySpringCGLIB$$1c5234aa] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2021-08-08 14:22:05.748 INFO 54035 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'relaxedDubboConfigBinder' of type [org.apache.dubbo.spring.boot.autoconfigure.BinderDubboConfigBinder] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2021-08-08 14:22:05.763 INFO 54035 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'relaxedDubboConfigBinder' of type [org.apache.dubbo.spring.boot.autoconfigure.BinderDubboConfigBinder] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2021-08-08 14:22:06.026 INFO 54035 --- [ main] .f.a.DubboConfigBindingBeanPostProcessor : The properties of bean [name : org.apache.dubbo.config.ApplicationConfig#0] have been binding by prefix of configuration properties : dubbo.application
2021-08-08 14:22:06.034 INFO 54035 --- [ main] .f.a.DubboConfigBindingBeanPostProcessor : The properties of bean [name : org.apache.dubbo.config.RegistryConfig#0] have been binding by prefix of configuration properties : dubbo.registry
2021-08-08 14:22:06.035 INFO 54035 --- [ main] o.a.d.c.s.b.f.a.ReferenceBeanBuilder : The configBean[type:ReferenceBean] has been built.
2021-08-08 14:22:06.137 INFO 54035 --- [ main] o.a.c.f.imps.CuratorFrameworkImpl : Starting
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:zookeeper.version=3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf, built on 03/06/2019 16:18 GMT
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:host.name=macbook-pro
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:java.version=1.8.0_251
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:java.vendor=Oracle Corporation
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:java.home=/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:java.class.path=/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar:/Applications/IntelliJ IDEA.app/Contents/plugins/junit/lib/junit-rt.jar:/Applications/IntelliJ IDEA.app/Contents/plugins/junit/lib/junit5-rt.jar:/Users/yiny/.m2/repository/org/junit/platform/junit-platform-launcher/1.7.2/junit-platform-launcher-1.7.2.jar:/Users/yiny/.m2/repository/org/apiguardian/apiguardian-api/1.1.0/apiguardian-api-1.1.0.jar:/Users/yiny/.m2/repository/org/junit/platform/junit-platform-engine/1.7.2/junit-platform-engine-1.7.2.jar:/Users/yiny/.m2/repository/org/opentest4j/opentest4j/1.2.0/opentest4j-1.2.0.jar:/Users/yiny/.m2/repository/org/junit/platform/junit-platform-commons/1.7.2/junit-platform-commons-1.7.2.jar:/Users/yiny/.m2/repository/org/junit/vintage/junit-vintage-engine/5.7.2/junit-vintage-engine-5.7.2.jar:/Users/yiny/.m2/repository/junit/junit/4.13/junit-4.13.jar:/Users/yiny/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/lib/tools.jar:/Users/yiny/Sites/java_demo/dubbo-zk-consumer/target/test-classes:/Users/yiny/Sites/java_demo/dubbo-zk-consumer/target/classes:/Users/yiny/.m2/repository/org/springframework/boot/spring-boot-starter-web/2.5.3/spring-boot-starter-web-2.5.3.jar:/Users/yiny/.m2/repository/org/springframework/boot/spring-boot-starter/2.5.3/spring-boot-starter-2.5.3.jar:/Users/yiny/.m2/repository/org/springframework/boot/spring-boot/2.5.3/spring-boot-2.5.3.jar:/Users/yiny/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.5.3/spring-boot-autoconfigure-2.5.3.jar:/Users/yiny/.m2/repository/org/springframework/boot/spring-boot-starter-logging/2.5.3/spring-boot-starter-logging-2.5.3.jar:/Users/yiny/.m2/repository/ch/qos/logback/logback-classic/1.2.4/logback-classic-1.2.4.jar:/Users/yiny/.m2/repository/ch/qos/logback/logback-core/1.2.4/logback-core-1.2.4.jar:/Users/yiny/.m2/repository/org/apache/logging/log4j/log4j-to-slf4j/2.14.1/log4j-to-slf4j-2.14.1.jar:/Users/yiny/.m2/repository/org/apache/logging/log4j/log4j-api/2.14.1/log4j-api-2.14.1.jar:/Users/yiny/.m2/repository/org/slf4j/jul-to-slf4j/1.7.32/jul-to-slf4j-1.7.32.jar:/Users/yiny/.m2/repository/jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5.jar:/Users/yiny/.m2/repository/org/yaml/snakeyaml/1.28/snakeyaml-1.28.jar:/Users/yiny/.m2/repository/org/springframework/boot/spring-boot-starter-json/2.5.3/spring-boot-starter-json-2.5.3.jar:/Users/yiny/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.12.4/jackson-databind-2.12.4.jar:/Users/yiny/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.12.4/jackson-annotations-2.12.4.jar:/Users/yiny/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.12.4/jackson-core-2.12.4.jar:/Users/yiny/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.12.4/jackson-datatype-jdk8-2.12.4.jar:/Users/yiny/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.12.4/jackson-datatype-jsr310-2.12.4.jar:/Users/yiny/.m2/repository/com/fasterxml/jackson/module/jackson-module-parameter-names/2.12.4/jackson-module-parameter-names-2.12.4.jar:/Users/yiny/.m2/repository/org/springframework/boot/spring-boot-starter-tomcat/2.5.3/spring-boot-starter-tomcat-2.5.3.jar:/Users/yiny/.m2/repository/org/apache/tomcat/embed/tomcat-embed-core/9.0.50/tomcat-embed-core-9.0.50.jar:/Users/yiny/.m2/repository/org/apache/tomcat/embed/tomcat-embed-el/9.0.50/tomcat-embed-el-9.0.50.jar:/Users/yiny/.m2/repository/org/apache/tomcat/embed/tomcat-embed-websocket/9.0.50/tomcat-embed-websocket-9.0.50.jar:/Users/yiny/.m2/repository/org/springframework/spring-web/5.3.9/spring-web-5.3.9.jar:/Users/yiny/.m2/repository/org/springframework/spring-beans/5.3.9/spring-beans-5.3.9.jar:/Users/yiny/.m2/repository/org/springframework/spring-webmvc/5.3.9/spring-webmvc-5.3.9.jar:/Users/yiny/.m2/repository/org/springframework/spring-aop/5.3.9/spring-aop-5.3.9.jar:/Users/yiny/.m2/repository/org/springframework/spring-context/5.3.9/spring-context-5.3.9.jar:/Users/yiny/.m2/repository/org/springframework/spring-expression/5.3.9/spring-expression-5.3.9.jar:/Users/yiny/.m2/repository/org/springframework/boot/spring-boot-starter-test/2.5.3/spring-boot-starter-test-2.5.3.jar:/Users/yiny/.m2/repository/org/springframework/boot/spring-boot-test/2.5.3/spring-boot-test-2.5.3.jar:/Users/yiny/.m2/repository/org/springframework/boot/spring-boot-test-autoconfigure/2.5.3/spring-boot-test-autoconfigure-2.5.3.jar:/Users/yiny/.m2/repository/com/jayway/jsonpath/json-path/2.5.0/json-path-2.5.0.jar:/Users/yiny/.m2/repository/net/minidev/json-smart/2.4.7/json-smart-2.4.7.jar:/Users/yiny/.m2/repository/net/minidev/accessors-smart/2.4.7/accessors-smart-2.4.7.jar:/Users/yiny/.m2/repository/org/ow2/asm/asm/9.1/asm-9.1.jar:/Users/yiny/.m2/repository/jakarta/xml/bind/jakarta.xml.bind-api/2.3.3/jakarta.xml.bind-api-2.3.3.jar:/Users/yiny/.m2/repository/jakarta/activation/jakarta.activation-api/1.2.2/jakarta.activation-api-1.2.2.jar:/Users/yiny/.m2/repository/org/assertj/assertj-core/3.19.0/assertj-core-3.19.0.jar:/Users/yiny/.m2/repository/org/hamcrest/hamcrest/2.2/hamcrest-2.2.jar:/Users/yiny/.m2/repository/org/junit/jupiter/junit-jupiter/5.7.2/junit-jupiter-5.7.2.jar:/Users/yiny/.m2/repository/org/junit/jupiter/junit-jupiter-api/5.7.2/junit-jupiter-api-5.7.2.jar:/Users/yiny/.m2/repository/org/junit/jupiter/junit-jupiter-params/5.7.2/junit-jupiter-params-5.7.2.jar:/Users/yiny/.m2/repository/org/junit/jupiter/junit-jupiter-engine/5.7.2/junit-jupiter-engine-5.7.2.jar:/Users/yiny/.m2/repository/org/mockito/mockito-core/3.9.0/mockito-core-3.9.0.jar:/Users/yiny/.m2/repository/net/bytebuddy/byte-buddy/1.10.22/byte-buddy-1.10.22.jar:/Users/yiny/.m2/repository/net/bytebuddy/byte-buddy-agent/1.10.22/byte-buddy-agent-1.10.22.jar:/Users/yiny/.m2/repository/org/objenesis/objenesis/3.2/objenesis-3.2.jar:/Users/yiny/.m2/repository/org/mockito/mockito-junit-jupiter/3.9.0/mockito-junit-jupiter-3.9.0.jar:/Users/yiny/.m2/repository/org/skyscreamer/jsonassert/1.5.0/jsonassert-1.5.0.jar:/Users/yiny/.m2/repository/com/vaadin/external/google/android-json/0.0.20131108.vaadin1/android-json-0.0.20131108.vaadin1.jar:/Users/yiny/.m2/repository/org/springframework/spring-core/5.3.9/spring-core-5.3.9.jar:/Users/yiny/.m2/repository/org/springframework/spring-jcl/5.3.9/spring-jcl-5.3.9.jar:/Users/yiny/.m2/repository/org/springframework/spring-test/5.3.9/spring-test-5.3.9.jar:/Users/yiny/.m2/repository/org/xmlunit/xmlunit-core/2.8.2/xmlunit-core-2.8.2.jar:/Users/yiny/.m2/repository/org/apache/dubbo/dubbo-spring-boot-starter/2.7.3/dubbo-spring-boot-starter-2.7.3.jar:/Users/yiny/.m2/repository/org/apache/dubbo/dubbo-spring-boot-autoconfigure/2.7.3/dubbo-spring-boot-autoconfigure-2.7.3.jar:/Users/yiny/.m2/repository/org/apache/dubbo/dubbo-spring-boot-autoconfigure-compatible/2.7.3/dubbo-spring-boot-autoconfigure-compatible-2.7.3.jar:/Users/yiny/.m2/repository/org/apache/dubbo/dubbo/2.7.3/dubbo-2.7.3.jar:/Users/yiny/.m2/repository/org/javassist/javassist/3.20.0-GA/javassist-3.20.0-GA.jar:/Users/yiny/.m2/repository/io/netty/netty-all/4.1.66.Final/netty-all-4.1.66.Final.jar:/Users/yiny/.m2/repository/com/google/code/gson/gson/2.8.7/gson-2.8.7.jar:/Users/yiny/.m2/repository/com/github/sgroschupf/zkclient/0.1/zkclient-0.1.jar:/Users/yiny/.m2/repository/log4j/log4j/1.2.14/log4j-1.2.14.jar:/Users/yiny/.m2/repository/org/apache/curator/curator-framework/2.12.0/curator-framework-2.12.0.jar:/Users/yiny/.m2/repository/org/apache/curator/curator-client/2.12.0/curator-client-2.12.0.jar:/Users/yiny/.m2/repository/com/google/guava/guava/16.0.1/guava-16.0.1.jar:/Users/yiny/.m2/repository/org/apache/curator/curator-recipes/2.12.0/curator-recipes-2.12.0.jar:/Users/yiny/.m2/repository/org/apache/zookeeper/zookeeper/3.4.14/zookeeper-3.4.14.jar:/Users/yiny/.m2/repository/org/slf4j/slf4j-api/1.7.32/slf4j-api-1.7.32.jar:/Users/yiny/.m2/repository/com/github/spotbugs/spotbugs-annotations/3.1.9/spotbugs-annotations-3.1.9.jar:/Users/yiny/.m2/repository/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar:/Users/yiny/.m2/repository/jline/jline/0.9.94/jline-0.9.94.jar:/Users/yiny/.m2/repository/org/apache/yetus/audience-annotations/0.5.0/audience-annotations-0.5.0.jar:/Users/yiny/.m2/repository/io/netty/netty/3.10.6.Final/netty-3.10.6.Final.jar:/Users/yiny/Sites/java_demo/dubbo-zk-api/target/classes:/Users/yiny/.m2/repository/junit/junit/4.13.2/junit-4.13.2.jar:/Users/yiny/.m2/repository/org/hamcrest/hamcrest-core/2.2/hamcrest-core-2.2.jar:/Users/yiny/.m2/repository/javax/servlet/javax.servlet-api/4.0.1/javax.servlet-api-4.0.1.jar:/Users/yiny/.m2/repository/javax/servlet/jsp/javax.servlet.jsp-api/2.3.3/javax.servlet.jsp-api-2.3.3.jar:/Users/yiny/.m2/repository/jstl/jstl/1.2/jstl-1.2.jar:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:java.library.path=/Users/yiny/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:java.io.tmpdir=/var/folders/7p/r7xrt8r50l1cd6dh0dtz2n940000gp/T/
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:java.compiler=<NA>
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:os.name=Mac OS X
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:os.arch=x86_64
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:os.version=10.16
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:user.name=yiny
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:user.home=/Users/yiny
2021-08-08 14:22:06.156 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Client environment:user.dir=/Users/yiny/Sites/java_demo/dubbo-zk-consumer
2021-08-08 14:22:06.157 INFO 54035 --- [ main] org.apache.zookeeper.ZooKeeper : Initiating client connection, connectString=127.0.0.1:2181 sessionTimeout=60000 watcher=org.apache.curator.ConnectionState@252f626c
2021-08-08 14:22:06.175 INFO 54035 --- [localhost:2181)] org.apache.zookeeper.ClientCnxn : Opening socket connection to server localhost/127.0.0.1:2181. Will not attempt to authenticate using SASL (unknown error)
2021-08-08 14:22:06.192 INFO 54035 --- [localhost:2181)] org.apache.zookeeper.ClientCnxn : Socket connection established to localhost/127.0.0.1:2181, initiating session
2021-08-08 14:22:06.217 INFO 54035 --- [localhost:2181)] org.apache.zookeeper.ClientCnxn : Session establishment complete on server localhost/127.0.0.1:2181, sessionid = 0x1000146c20c0007, negotiated timeout = 40000
2021-08-08 14:22:06.221 INFO 54035 --- [ain-EventThread] o.a.c.f.state.ConnectionStateManager : State change: CONNECTED
2021-08-08 14:22:07.663 INFO 54035 --- [ main] c.g.DubboZkConsumerApplicationTests : Started DubboZkConsumerApplicationTests in 2.957 seconds (JVM running for 3.913)
在注册中心拿到 ====> 极客堂-941311334
2021-08-08 14:22:08.094 INFO 54035 --- [extShutdownHook] .b.c.e.AwaitingNonWebApplicationListener : [Dubbo] Current Spring Boot Application is about to shutdown...
2021-08-08 14:22:08.129 INFO 54035 --- [tor-Framework-0] o.a.c.f.imps.CuratorFrameworkImpl : backgroundOperationsLoop exiting
2021-08-08 14:22:08.151 INFO 54035 --- [ain-EventThread] org.apache.zookeeper.ClientCnxn : EventThread shut down for session: 0x1000146c20c0007
2021-08-08 14:22:08.151 INFO 54035 --- [extShutdownHook] org.apache.zookeeper.ZooKeeper : Session: 0x1000146c20c0007 closed
2021-08-08 14:22:08.159 INFO 54035 --- [extShutdownHook] f.a.ReferenceAnnotationBeanPostProcessor : org.apache.dubbo.common.bytecode.proxy0@a69919e was destroying!
2021-08-08 14:22:08.159 INFO 54035 --- [extShutdownHook] f.a.ReferenceAnnotationBeanPostProcessor : class org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor was destroying!

Process finished with exit code 0

微服务笔记

框架

微服务条目 落地技术
服务开发 Spring、SpringMVC、SpringBoot
服务配置与管理 Netflix的Archaius、阿里的Diamond等
服务注册与发现 Eureka、Consul、Zookeeper
服务调用 Rest、RPC、gRPC
服务熔断器 Hystrix、Envoy等
负载均衡 Ribbon、Nginx等
服务接口调用 Feign等
消息队列 Kafka、RabbitMQ、ActiveMQ等
服务配置中心管理 SpringCloudConfig、Chef等
服务路由(API网关) Zuul等
服务监控 Zabbix、Nagios、Metrics、Specatator等
全链路追踪 Zipkin、Brave、Dapper等
服务部署 Docker、OpenStack、Kubernetes等
数据流操作开发包 SpringCloudStream(封装与Redis、Rabbit、Kafka等发送接收消息
消息事件总线 SpringCloud Bus

SpringMVC

SpringMVC执行过程

Maven教程

maven的安装

maven下载地址:maven官网

下载后解压到一个固定位置,比如我这里直接解压到:/Users/yiny/soft/apache-maven-3.8.1

然后更改.bash_profile (如果使用zsh的话需要修改.zshrc),将maven的环境变量添加进去:

1
2
export M2_HOME="/Users/yiny/soft/apache-maven-3.8.1"
export PATH="$M2_HOME/bin:$PATH"

然后在命令行执行mvn -v,如果命令成功返回显示了maven的版本号,就说明maven已经安装成功了。
如果不成功,比如提示找不到mvn命令等,一般是JDK或者maven安装的有问题。

修改maven的默认配置

修改本地仓库地址

安装成功后,需要到maven的安装目录下的conf/setting.xml文件中修改一下默认的repository存储位置和下载镜像。

1
2
3
4
5
6
7
<!-- localRepository
| The path to the local repository maven will use to store artifacts.
|
| Default: ${user.home}/.m2/repository
<localRepository>/path/to/local/repo</localRepository>
-->
<localRepository>/Users/yiny/soft/apache-maven-3.8.1/repo</localRepository>

修改localRepository节点的值,配置本地仓库存储地址。

修改镜像地址

还需要配置下载源为阿里源,提高下载速度,在mirrors节点下添加如下mirror配置:

1
2
3
4
5
6
7
8
9
10
<mirrors>
...
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
</mirrors>

创建maven工程

这里以java的jar格式工程说明mvn的工程目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
➜  mvntest1 tree
.
├── pom.xml # maven 配置文件
├── src # 源码文件根目录
│   ├── main # 源码
│   │   ├── java
│   │   │   └── cn
│   │   │   └── geekhall
│   │   │   └── main
│   │   │   └── Main.java
│   │   └── resourses
│   └── test # 测试代码
│   └── java
└── target # 生成的目标文件根目录
├── classes
│   └── cn
│   └── geekhall
│   └── main
│   └── Main.class
└── maven-status
└── maven-compiler-plugin
└── compile
└── default-compile
├── createdFiles.lst
└── inputFiles.lst

然后在pom.xml文件中添加如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>cn.geekhall</groupId>
<artifactId>maventest1</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<junit.version>4.11</junit.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

</project>

按照上面的目录格式常见好目录结构和源码文件后,在工程的根目录执行mvn compile 就会对工程进行编译,生成的文件存放在target目录下。第一次会下载全量依赖包,时间会比较长,第二次以后再次运行的时候就会比较快了。

然后执行: mvn -e exec:java -Dexec.mainClass="cn.geekhall.main.Main" 即可运行工程看到执行结果。

pom.xml文件格式

maven是使用pom.xml文件来找到各种依赖包、插件的地址,解决依赖问题的。
具体的pom.xml文件格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<!--在这里配置本工程的mvn地址信息。 -->
<groupId>cn.geekhall</groupId>
<artifactId>maventest02</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

<name>maventest02 Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>https://www.geekhall.cn</url>

<!-- 这里可以配置参数信息、比如编码格式、版本号信息等 -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<junit.version>4.11</junit.version>
<servlet-version>4.0.1</servlet-version>
<jsp-version>2.3.3</jsp-version>
<jstl-version>1.2</jstl-version>
<spring-version>5.1.11.RELEASE</spring-version>
<aspectjweaver-version>1.9.4</aspectjweaver-version>
<mybatis-version>3.5.2</mybatis-version>
<mybatis-spring-version>2.0.2</mybatis-spring-version>
<log4j-version>1.2.17</log4j-version>
<mysql-connector-java-version>5.1.48</mysql-connector-java-version>
<jackson-version>2.9.9</jackson-version>
<commons-fileupload-version>1.3.1</commons-fileupload-version>
</properties>

<!-- 这里配置各种依赖信息 -->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet-version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>${jsp-version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>${jstl-version}</version>
</dependency>
</dependencies>

<!-- 执行profile环境 -->
<profiles>
<profile>
<id>dev</id>
<properties>
<env>dev</env>
</properties>
<acctivation>
<activeByDefault>true</activeByDefault>
</acctivation>
</profile>
</profile>

<build>
<finalName>maventest02</finalName>
<!-- plugins配置各种插件 -->
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>6060</port>
<path>/my</path>
</configuration>
</plugin>
</plugins>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

maven常用命令

maven命令格式为:mvn [plugin-name]:[goal-name],表示执行plugin-name插件的goal-name目标,

常用命令有:

  • mvn -version / mvn -v : 显示版本信息。
  • mvn clean : 清理项目产生的临时文件,一般是模块下的target目录。
  • mvn compile : 编译源代码,一般编译模块下的src/main/java目录。
  • mvn package : 项目打包工具,会在模块下的target目录生成jar或者war等文件。
  • mvn test : 测试命令,会执行src/test/java目录下的测试用例。
  • mvn install : 将打包的jar或者war文件复制到你的本地仓库中,供其他模块使用。
  • mvn deploy : 将打包的jar或者war文件发布到远程仓库,提供其他人员进行下载依赖。
  • mvn site : 生成项目相关信息的网站。
  • mvn eclipse:eclipse : 将项目转化为Eclipse项目。
  • mvn dependency:tree : 打印出项目的整个依赖树。
  • mvn archetype:generate : 创建maven的普通java项目。
  • mvn tomcat7:run : 在tomcat容器中运行web应用。
  • mvn jetty:run: 调用jetty的run目标在Jetty Servlet容器中启动web应用。

需要注意的是:运行maven命令的时候,首先需要定位在maven项目所在的目录,也就是项目pom.xml文件所在的目录。否则需要使用参数执行项目的目录。

还可以使用-D指定属性参数,例如:mvn package -Dmaven.test.skip=true 可以指定打包的时候跳过单元测试。

IDEA集成maven环境

在工具的 preferences -> Build,Extension,Deployment -> Build Tools ->Maven 目录下配置maven。

在Maven home directory:目录下配置当前使用的maven,这里使用了IDEA自带的maven。

创建java项目

创建普通java项目

web项目要选择maven-archetype-webapp

编辑运行配置

compile

package

maven仓库

对于maven来说,仓库分为两类:本地仓库和远程仓库。maven根据坐标去寻找构件的时候,它会首先查看本地仓库,若存在则直接使用,不存在再去远程仓库下载。
远程仓库分为三种:中央仓库(国外,访问量大,速度慢),私服(一般公司内部搭建),其他公共库(阿里等)。

mavenrepository.com

maven的配置可以从
https://mvnrepository.com/上找到。

C语言笔记

C语言简介

C 语言是一种通用的、面向过程式的计算机程序设计语言。1972 年,为了移植与开发 UNIX 操作系统,丹尼斯·里奇在贝尔电话实验室设计开发了 C 语言。

C 语言是一种广泛使用的计算机语言,它与 Java 编程语言一样普及,二者在现代软件程序员之间都得到广泛使用。

当前最新的 C 语言标准为 C18 ,在它之前的 C 语言标准有 C17、C11…C99 等。

第一个C程序

1
2
3
4
5
6
#include <stdio.h>
int main()
{
printf("Hello, World! \n");
return 0;
}

开发环境

Unix/Linux/Mac环境

如果是使用Unix/Linux/Mac环境,可以使用gcc -v命令检查本地是否安装了gcc环境。

Windows环境

需要先安装Cygwin

使用VSCode和Code Runner插件

使用VSCode的Code Runner插件可以方便地编译和运行C程序

基础语法

  • 分号:在 C 程序中,分号是语句结束符。也就是说,每个语句必须以分号结束。它表明一个逻辑实体的结束。

  • 注释

    • 单行注释
    • 多行注释
  • 标识符:
    标识符是用来标识变量、函数,或任何其他用户自定义项目的名称。一个标识符以字母 A-Z 或 a-z 或下划线 _ 开始,后跟零个或多个字母、下划线和数字(0-9)。

    C 标识符内不允许出现标点字符,比如 @、$ 和 %。C 是区分大小写的编程语言。因此,在 C 中,Manpower 和 manpower 是两个不同的标识符。

  • 关键字

  • 空格:只包含空格的行,被称为空白行,可能带有注释,C 编译器会完全忽略它。在 C 中,空格用于描述空白符、制表符、换行符和注释。

数据类型

变量

常量

存储类

  • auto
  • register
  • static
  • extern

运算符

判断

循环

函数

作用域规则

数组

枚举

指针

函数指针与回调函数

字符串

结构体

共用体

位域

typedef

输入&输出

文件读写

预处理

头文件

强制类型转换

错误处理

递归

可变参数

内存管理

命令行参数

常用数据结构和算法

gdb和程序调试

gdb常用命令

  • attach
  • break/b
  • continue/c
  • info
  • set print pretty

makefile和工程

堆和栈

程序的结构-ELF文件

程序的结构-中间文件、可执行程序、静态库、动态库

栈溢出

程序漏洞、pwn

如何使你的网站支持https

HTTPS一般指HTTP over TLS或者HTTP over SSL或者HTTP Secure,是一种通过计算机网略进行安全通信的传输协议,HTTPS经由HTTP进行通信,但是使用SSL/TLS来加密数据包,HTTPS的主要目的是提供对网站服务器的身份认证,保护交换资料的隐私与完整性。
这里使用腾讯云提供的一年免费SSL证书为例,讲解如何使你的网站支持HTTPS。

1 申请证书

首先登录腾讯云的管理控制台,找到SSL证书->证书申请页面,并按照要求填写域名、邮箱等申请资料:

下一步,选择验证方式:

这里推荐使用DNS验证,基本上一分钟之内就可以生效了。

到控制台DNS解析,找到需要添加证书的域名,按照上面要求的内容添加一条解析记录:

然后等待一分钟左右就可以下载到证书了。里面是一个压缩文件,解压后可以看到里面是适用于Apache、Nginx、Tomcat、IIS等各种服务器的私钥配置文件和pem文件

2 配置Nginx

到Nginx的配置目录,默认为/etc/nginx,新建一个cert的文件夹,将下载的证书文件上传到这里。

编辑该域名对应的配置文件,我这里由于配置了虚拟主机所以在/etc/nginx/vhosts/domain.conf,:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 配置http重定向至https
server {
listen 80;
server_name geekhall.cn www.geekhall.cn;
return 301 https://$server_name$request_uri;
}
# 配置https
server {
listen 443 ssl;
server_name geekhall.cn www.geekhall.cn;

# ssl证书地址
ssl_certificate cert/geekhall.cn.pem;
ssl_certificate_key cert/geekhall.cn.key;

# ssl验证配置
ssl_session_timeout 5m; # 缓存有效期
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; #加密算法
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #安全链接可选的加密协议
ssl_prefer_server_ciphers on; # 使用服务器端的首选算法

}

重启Nginx服务后使用https访问域名确认生效。

git教程

Git 读音为/git/ ,是一个开源的分布式版本管理系统,是Linux Torvalds为了帮助管理Linux内核开发而开发的一个版本控制软件。

git 和svn的区别:

1 工作原理

1.1 git的四个工作区域

image-20210409050441248

  • 远程仓库:Github、Gitee、GitLab,存储在远程服务器上的仓库。
  • 本地仓库:git clone或者git init之后存储在本地的仓库,HEAD指向最新放入仓库的版本。
  • 暂存区:也叫待提交更新区,存放临时变动,本质上是文件,保存即将提交的文件列表。
  • 工作区:也叫工作目录,本地工作目录

1.2 git的文件状态

  • 未跟踪(Untracked):文件在本地,未添加到git仓库,不参与版本控制,执行git add 后 状态变为 Staged

  • 未修改(Unmodified):文件已入库,未修改,即版本库中的快照内容与本地文件一致。修改后转为Modified,执行git rm后移出版本库,变为Untracked

  • 已修改(Modified):文件已入库,已修改,即版本库中的快照内容与本地文件不一致。使用git checkout则丢弃修改,返回Unmodified状态,git add后进入暂存Staged状态。

  • 暂存(Staged):暂存状态,执行git commit则修改同步到本地库中,文件变为Unmodified状态,执行git reset HEAD filename 取消暂存,文件变为Modified状态

    可以使用git status [filename]来查看指定文件的状态。

image-20210409050404549

image-20210409042142708

image-20210409042214715

image-20210409042230437

1.3 本地工作流

你的本地仓库由 git 维护的三棵“树”组成。第一个是你的 工作目录,它持有实际文件;第二个是 缓存区(Index),它像个缓存区域,临时保存你的改动;最后是 HEAD,指向你最近一次提交后的结果。

image-20210409043232427

1.4 分支

分支是用来将特性开发绝缘开来的。在你创建仓库的时候,master 是“默认的”。master分支应该非常稳定,用来发布新版本,一般情况下不允许在上面工作,一般会新建dev分支进行开发,dev分支代码稳定后再将它们合并到master分支上。

image-20210409043607480

1.5 需要记住的命令

image-20210409044451952

2 常用操作

全局配置:

1
2
3
git config --global user.name "username"
git config --global user.email "xxxx@gmail.com"

新建仓库:

1
2
3
4
5
6
7
8
9
10
mkdir vuecli_sample
cd vuecli_sample
git init
touch README.md
git add README.md
git commit -m "first commit"
git remote add github git@github.com:geekhall/vue2cli.git
git remote add gitee git@gitee.com:sjdt/vue2cli.git
git push -u github master
git push -u gitee master

已有仓库

1
2
3
4
cd existing_git_repo
git remote add github git@gitee.com:sjdt/vuecli_sample.git
git branch -M main
git push -u github main

2.1 配置

1
2
3
4
5
6
# 设置
git config --global user.name yiny
git config --global user.email yinyang007@gmail.com

# 查看
git config -l / git config --list

2.2 创建仓库

两种方式:

1
2
3
4
5
# 创建一个新的仓库
git init

# 创建一个远端仓库的本地克隆版本
git clone username@host:/path/to/repository

2.3 本地提交

1
2
3
4
5
6
7
# 添加到Stage
git add <filename>
git add .
git add *

# 提交到本地仓库
git commit -m "提交信息" # 现在,你的改动已经提交到了 HEAD,但是还没到你的远端仓库!

2.4 推送改动

1
2
3
4
5
6
# 将本地改动提交到远端仓库,origin和master分别为默认的仓库名和分支名称
git push origin master

# 如果你还没有克隆现有仓库,并欲将你的仓库连接到某个远程服务器,你可以使用如下命令添加:
git remote add origin <server>

2.5 分支操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 列出所有本地分支
git branch

# 列出所有远程分支
git branch -r

# 创建分支,但依然停留在当前分支
git branch [branch-name]

# 创建一个分支,并切换过去:
git checkout -b [branch-name]

# 合并指定分支到当前分支:
git merge [branch-name]

# 切换回主分支:
git checkout master

# 删除分支:
git branch -d [branch-name]

# 除非你将分支推送到远端仓库,不然该分支就是 不为他人所见的:
git push origin <branch>

# 删除远程分支
git push origin --delete [branch-name]
git branch -dr [remote/branch]

2.6 更新与合并

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 要更新你的本地仓库至最新改动,执行:
git pull # 在你的工作目录中 获取(fetch) 并 合并(merge) 远端的改动。

# 要合并其他分支到你的当前分支(例如 master),执行:
git merge <branch>

# 两种情况下,git 都会尝试去自动合并改动。不幸的是,自动合并并非次次都能成功,并可能导致 冲突(conflicts)。
# 这时候就需要你修改这些文件来人肉合并这些 冲突(conflicts) 。改完之后,你需要执行如下命令以将它们标记为合并成功并重新提交:
git add <filename>
git commit

# 在合并改动之前,也可以使用如下命令查看:
git diff <source_branch> <target_branch>

2.7 标签

1
2
3
# 在软件发布时创建标签,是被推荐的。这是个旧有概念,在 SVN 中也有。可以执行如下命令以创建一个叫做 1.0.0 的标签:
git tag 1.0.0 1b2e1d63ff # 1b2e1d63ff 是你想要标记的提交 ID 的前 10 位字符。

2.8 日志

1
git log

2.9 diff

1
git diff ver1..ver2 [filename]

2.10 替换本地改动(慎用,未提交的本地修改内容可能丢失)

1
2
3
4
5
6
# 假如你做错事,你可以使用如下命令替换掉本地改动:
git checkout -- <filename> # 此命令会使用 HEAD 中的最新内容替换掉你的工作目录中的文件。已添加到缓存区的改动,以及新文件,都不受影响。

# 假如你想要丢弃你所有的本地改动与提交,可以到服务器上获取最新的版本并将你本地主分支指向到它:
git fetch origin
git reset --hard origin/master

2.11 git reset

git reset 的三种模式soft,mixed,hard

image-20210409042413736

image-20210409042427204

image-20210409042439298

2.12 gitignore

在.gitignore文件中配置不需要提交到版本库进行管理的文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Class file
*.class

# Log file
*.log

# BlueJ file
*.ctxt

# Mac file
.DS_Store

# package file
*.jar
*.war
*.nar
*.ear
*.zip
*.tar
*.tar.gz
*.rar

# config file
.idea/

删除远程仓库文件

如果要删除的文件已经被git跟踪,那么即使添加到.gitignore也是没有用的,
具体操作步骤:

  1. 预览将要删除的文件
    加上 -n 表示只是展示,不会删除任何文件
1
git rm -r -n --cached filename
  1. 确定无误后删除文件:
1
git rm -r --cached filename
  1. 提交到本地并推送到远程服务器
1
2
git commit -m "提交说明"
git push origin master
  1. 修改本地.gitignore文件并提交

同时提交Github和Gitee

同时提交github和gitee

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 1 查看仓库信息
git remote -v

# 2 删除原有远程仓库,然后添加两个远程仓库
git remote rm origin
git remote add github git@github.com:geekhall/geekhall.cn.git
git remote add gitee git@gitee.com:sjdt/geekhall.cn.git

# 2 拉代码,合并两个仓库的历史记录
git pull gitee main --allow-unrelated-histories
git pull github main --allow-unrelated-histories

# 3 设置上游分支
git push --set-upstream github main
git push --set-upstream gitee main

# 3 push 代码
git push gitee main
git push github main


提交脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
usage()
{
echo "使用方法:"
echo "commit.sh"
echo " or"
echo "commit.sh 提交注释"
exit 2
}

if [ $# -eq 1 ]; then
comment=$1
else
comment=`date +'%Y%m%d-%H%M%S'`
fi

git add .
git commit -m "$comment"
git push github
git push gitee

远端自动部署脚本

1
2
3
4
5
6
7
8
9
10
11
cd /usr/share/nginx/html/geekhall.cn
git pull
workon mwd
rm -rf static_dist
python manage.py collectstatic
deactivate
./stopsvr.sh
./startuwsgi.sh
nginx -s stop
nginx

gulp常见问题及解决方法

执行gulp的时候报错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
➜  front git:(main) ✗ gulp
Error: Node Sass does not yet support your current environment: OS X 64-bit with Unsupported runtime (88)
For more information on which environments are supported please see:
https://github.com/sass/node-sass/releases/tag/v4.14.1
at module.exports (/Users/yiny/Sites/geekhall.cn/front/node_modules/node-sass/lib/binding.js:13:13)
at Object.<anonymous> (/Users/yiny/Sites/geekhall.cn/front/node_modules/node-sass/lib/index.js:14:35)
at Module._compile (node:internal/modules/cjs/loader:1108:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1137:10)
at Module.load (node:internal/modules/cjs/loader:973:32)
at Function.Module._load (node:internal/modules/cjs/loader:813:14)
at Module.require (node:internal/modules/cjs/loader:997:19)
at require (node:internal/modules/cjs/helpers:92:18)
at Object.<anonymous> (/Users/yiny/Sites/geekhall.cn/front/node_modules/gulp-sass/index.js:166:21)
at Module._compile (node:internal/modules/cjs/loader:1108:14)

下面的命令可以修复:

1
npm rebuild node-sass

Nginx虚拟主机的多域名配置

本文的目的是使用Nginx的虚拟主机功能在同一台服务器上配置多个域名,多域名之间可以使用不同架构,比如同时使用php的thinkphp或者Laravel和python的Django。
主要架构思想为使用Nginx作为反向代理,配合php-fpm和fastcgi作为上游服务端提供服务。

1. 目录说明

序号 目录 用途
1 /etc/nginx/nginx.conf Nginx主配置文件
2 /etc/nginx/vhosts/ Nginx虚拟主机配置文件存放目录
3 /etc/nginx/vhosts/aaa.com.conf 网站aaa.com的虚拟主机配置文件存放目录
4 /etc/nginx/vhosts/bbb.com.conf 网站bbb.com的虚拟主机配置文件存放目录
5 /usr/share/nginx/html/aaa.com/ 网站aaa.com的文件存放目录
6 /usr/share/nginx/html/bbb.com/ 网站bbb.com的文件存放目录
7 /etc/php-fpm.d/www.conf php-fpm配置文件

2. Nginx配置

2.1 修改Nginx主配置文件

修改 /etc/nginx/nginx.conf

1
2
3
4
5
6
7
8
9
10
11
http {
include /etc/nginx/conf.d/*.conf;
# 将所有虚拟主机的配置文件都放在vhosts文件夹中
include /etc/nginx/vhosts/*.conf;

# 注释掉Nginx默认的server部分的服务器配置
#server{
# listen 80 default_server;
# ...
#}
}

2.2 修改php版的虚拟主机配置

/etc/nginx/vhosts/aaa.com.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
server {
listen 80;
server_name aaa.com www.aaa.com;
#charset utf-8;
access_log /usr/share/nginx/html/aaa.com/log/host.access.log;
error_log /usr/share/nginx/html/aaa.com/log/error.log;
# gzip off;
root /usr/share/nginx/html/aaa.com/public;
index index.php index.html index.htm;
location / {
if (!-e $request_filename) {
rewrite ^/(.*)$ /index.php/$1 last;
break;
}
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
expires 100d;
}
location ~ .*\.(js|css)?$ {
expires 30d;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php(/|$) {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include /etc/nginx/fastcgi.conf;
set $fastcgi_script_name2 $fastcgi_script_name;
if ($fastcgi_script_name ~ "^(.+\.php)(/.+)$") {
set $fastcgi_script_name2 $1;
set $path_info $2;
}
fastcgi_param PATH_INFO $path_info;
fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html/aaa.com/public/$fastcgi_script_name2;
fastcgi_param SCRIPT_NAME $fastcgi_script_name2;
}
}

2.3 配置python虚拟环境

使用virtualenv和virtualenvwrapper来新建和管理虚拟环境,相关命令如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 安装
pip3 install virtualenvwrapper
# 安装好后需要将下面内容添加至~/.bashrc中
export WORKON_HOME=~/Env
source /usr/local/bin/virtualenvwrapper.sh
export LD_LIBRARY_PATH="/usr/local/lib"
export PATH=$PATH:/usr/local/python3/bin/

# 新建虚拟环境
mkvirtualenv my_env

# 切换至虚拟环境
workon my_env

# 退出虚拟环境
deactivate

# 删除虚拟环境
rmvirtualenv my_env

# 列出虚拟环境
lsvirtualenv

2.4 修改Django版的虚拟主机配置

/etc/nginx/vhosts/bbb.com.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
upstream hello{
server unix:///usr/share/nginx/html/hello/hello.sock;
}

server {
listen 80;
server_name bbb.com www.bbb.com;
charset utf-8;
# 发送所有非静态请求至Django服务器
location / {
uwsgi_pass hello;
include /etc/nginx/uwsgi_params;
# root html/moonwhite.design;
# index index.html index.htm index.php;
}
}

3 php-fpm配置

修改/etc/php-fpm.d/www.conf 文件

1
2
listen = 127.0.0.1:9000
listen.allowed_clients = 127.0.0.1
  • php-fpm启动命令:php-fpm
  • php-fpm停止命令:ps -ef|grep php-fpm|grep master|awk '{print $2}'|xargs kill -QUIT

4 配置使用uwsgi

命令行方式:uwsgi --http :4000 --module hello.wsgi --virtualenv=/root/Env/mwd

配置文件方式:/usr/share/nginx/html/hello/hello.ini

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[uwsgi]

# Django 相关配置
# 必须为绝对路径
# 项目的路径
chdir = /usr/share/nginx/html/hello
# Django 的wsgi文件
module = hello.wsgi
# python 虚拟环境的路径
home = /root/Env/mwd

# 通讯方式:http
#http = :4000

# 进程相关设置
# 主进程
master = true
# 最大数量的工作进程
processes = 10
# 通讯方式:socket
# socket 文件路径
socket = /usr/share/nginx/html/hello/hello.sock
# socket 权限
chomd-socket = 666
# 退出的时候是否清理环境
vacuum = true

配置好之后就可以使用uwsgi --ini hello.ini来启动了。

停止命令:wsgi| grep -v grep |awk '{print $2}'|xargs kill -9

这里需要注意的是uwsgi不要安装在虚拟环境,要安装在系统python环境中。
而Django和相关项目依赖要安装在python虚拟环境中。

5. 配置VCS

1
2
3
4
5
6
# git初始化
git init
# 查看指定远程仓库地址
git remote get-url origin
# 设置远程仓库地址
git remote set-url origin 你新的远程仓库地址