Skip to content
Snippets Groups Projects
Commit 0113f4ca authored by czy's avatar czy
Browse files

删除实验报告.md

parent d40108fc
No related branches found
No related tags found
No related merge requests found
# 云原生大作业实验报告
## 小组成员
| 学号 | 姓名 | 分工 |
|-----------|-----|--------|
| | | |
| 211250179 | 杨胜寒 | 应用监控配置 |
| 211250108 | 谷雨阳 | 限流测试grafana |
## 实验环境
- JDK 1.8
- spring boot 2.3.1.RELEASE
## 实验内容
### 1. 实现一个 REST 接口,接口提供限流功能
```java
@RestController
public class RESTController {
//计数器限流100次/s
private static final RateLimiter limiter = RateLimiter.create(100.0);
@Autowired
private QPSMetrics QPSMetrics;
@GetMapping("/")
public ResponseEntity index() {
//尝试获取令牌,
if (limiter.tryAcquire()) {
QPSMetrics.increment();
return new ResponseEntity("Hello");
}
throw new TooManyRequestException("Too Many Request");
}
}
```
其中`TooMantRequestException`为自定义异常,用于返回429状态码
```java
@ResponseStatus(value = HttpStatus.TOO_MANY_REQUESTS, reason = "Too Many Request")
public class TooManyRequestException extends RuntimeException {
public TooMantRequestException(String message) {
super(message);
}
}
```
`ResponseEntity`为自定义返回类,为一个json串
```java
@Data
@ResponseBody
public class ResponseEntity {
private String message;
public ResponseEntity(String message) {
this.message = message;
}
}
```
限流测试:
![1-current-limiting](images%2F1-current-limiting.png)
### 2. 为该项目准备 Dockerfile,用于构建镜像
```dockerfile
FROM eclipse-temurin:8u372-b07-jre-centos7
ADD ./target/application-0.0.1.jar /app/application-0.0.1.jar
ADD runboot.sh /app/
WORKDIR /app
RUN chmod a+x runboot.sh
CMD sh -c /app/runboot.sh
EXPOSE 8080
```
将应用打包为 application.jar 后执行命令
```shell
docker build -t application:v1 .
docker run -d -p 80:8080 --name application application:v1
```
访问 127.0.0.1:80,返回`{"message":"Hello"}`
### 3. 为该项目准备 Kubernetes 部署文件
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: application
namespace: nju21
labels:
app: application
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
selector:
matchLabels:
app: application
template:
metadata:
labels:
app: application
annotations:
prometheus.io/path: /actuator/prometheus
prometheus.io/port: "8080"
prometheus.io/scheme: http
prometheus.io/scrape: "true"
spec:
hostname: application
containers:
- name: application
image: harbor.edu.cn/nju21/application:{VERSION}
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
resources:
requests:
cpu: 1
memory: 512Mi
limits:
cpu: 1
memory: 512Mi
imagePullSecrets:
- name: regcred
---
apiVersion: v1
kind: Service
metadata:
name: application
namespace: nju21
labels:
app: application
spec:
type: NodePort
ports:
- name: tcp
nodePort: 32531
protocol: TCP
port: 8080
targetPort: 8080
selector:
app: application
```
其中`regcred`是类型为`kubernetes.io/dockerconfigjson`的 Secret,用来存储 Docker 私有镜像仓库的登录凭据,由以下命令创建
```shell
[nju21@host-172-29-4-18 ~]$ kubectl create secret docker-registry regcred --docker-server=harbor.edu.cn --docker-username=nju21 --docker-password=nju212023 -n nju21
secret/reacred created
```
### 4. 编写 jenkins 的 pipeline 文件
```groovy
pipeline {
agent none
stages {
stage('Clone Code') {
agent {
label 'master'
}
steps {
echo "1.Git Clone Code"
sh 'curl "http://p2.nju.edu.cn/portal_io/login?username=211250108&password=GYY914qqbd"'
git branch: "master", url: "https://gitee.com/misakabryant/EngageCloud.git"
}
}
stage('Maven Test and Build') {
agent {
docker {
image 'maven:latest'
args '-v /root/.m2:/root/.m2'
}
}
steps {
echo "2.Maven Build Stage"
sh 'mvn -B clean package -Dmaven.test.skip=false'
}
//将JUnit步骤放在post always中 当测试环境不通过时 依然可以收集到测试报告
post {
always {
script {
junit "**/target/surefire-reports/*.xml"
}
}
}
}
stage('Image Build') {
agent {
label 'master'
}
steps {
echo "3.Image Build Stage"
sh 'docker build -f Dockerfile --build-arg jar_name=target/application-0.0.1.jar -t application:${BUILD_ID} . '
sh 'docker tag application:${BUILD_ID} harbor.edu.cn/nju21/application:${BUILD_ID}'
}
}
stage('Push') {
agent {
label 'master'
}
steps {
echo "4.Push Docker Image Stage"
sh "docker login --username=nju21 harbor.edu.cn -p nju212023"
sh "docker push harbor.edu.cn/nju21/application:${BUILD_ID}"
}
}
}
}
node('slave') {
container('jnlp-kubectl') {
stage('Clone YAML') {
echo "5. Git Clone YAML To Slave"
sh 'curl "http://p2.nju.edu.cn/portal_io/login?username=211250108&password=GYY914qqbd"'
git branch: "master", url: "https://gitee.com/misakabryant/EngageCloud.git"
}
stage('YAML') {
echo "6. Change YAML File Stage"
sh 'sed -i "s#{VERSION}#${BUILD_ID}#g" application.yaml'
}
stage('Deploy') {
echo "7. Deploy To K8s Stage"
sh 'kubectl apply -f application.yaml'
sh 'kubectl apply -f application-serviceMonitor.yaml'
}
}
}
```
后续验证流水线成功:
![4-pipeline.png](images%2F4-pipeline.png)
### 5. 提供 Prometheus metrics 接口
在 application.properties 中,添加 Spring Boot Actuator 相关配置
```properties
management.endpoints.web.exposure.include=prometheus,health,info,metrics
management.server.port=8080
```
暴露`prometheus``health``info``metrics`四个端点 ,并指定管理端口为 8080
在 application.yaml 中,添加 Prometheus 相关注解
```yaml
annotations:
prometheus.io/path: /actuator/prometheus
prometheus.io/port: "8080"
prometheus.io/scheme: http
prometheus.io/scrape: "true"
```
指定应用程序暴露指标的路径,运行的端口,使用的协议,抓取应用程序的指标
在 application-serviceMonitor.yaml 中,配置 Prometheus
```yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
labels:
k8s-app: application
name: application
namespace: nju21
spec:
endpoints:
- interval: 30s
port: tcp
path: /actuator/prometheus
scheme: 'http'
selector:
matchLabels:
app: application
namespaceSelector:
matchNames:
- nju21
```
指定监控的服务,命名空间,抓取间隔,路径等
实现接口访问指标(QPS),并暴露给 Prometheus
```java
@Component
public class QPSMetrics {
private final Gauge qps;
private long count = 0;
public QPSMetrics(CollectorRegistry collectorRegistry) {
qps = Gauge.build()
.name("my_qps")
.help("The average number of requests per second over the previous minute")
.register(collectorRegistry);
}
// 由 Controller 调用
public synchronized void increment() {
count++;
}
// 每秒报告 QPS
@Scheduled(fixedRate = 1000)
public void report() {
qps.set(count / 60.0);
}
// 每分钟重置访问次数
@Scheduled(fixedRate = 60000)
public void reset() {
count = 0;
}
}
```
访问 172.29.4.18:32531/actuator/prometheus,部分返回内容如下
(因内容过多,此处只展示 JVM 相关指标部分,具体内容可自行访问查看)
```text
# HELP jvm_classes_loaded_classes The number of classes that are currently loaded in the Java virtual machine
# TYPE jvm_classes_loaded_classes gauge
jvm_classes_loaded_classes 6879.0
# HELP system_load_average_1m The sum of the number of runnable entities queued to available processors and the number of runnable entities running on the available processors averaged over a period of time
# TYPE system_load_average_1m gauge
system_load_average_1m 3.07
# HELP jvm_memory_used_bytes The amount of used memory
# TYPE jvm_memory_used_bytes gauge
jvm_memory_used_bytes{area="heap",id="Tenured Gen",} 1.4676168E7
jvm_memory_used_bytes{area="heap",id="Eden Space",} 4629312.0
jvm_memory_used_bytes{area="nonheap",id="Metaspace",} 3.7628816E7
jvm_memory_used_bytes{area="nonheap",id="Code Cache",} 1.8448256E7
jvm_memory_used_bytes{area="heap",id="Survivor Space",} 30424.0
jvm_memory_used_bytes{area="nonheap",id="Compressed Class Space",} 4649712.0
```
其中可见自定义 QPS 指标部分
```text
# HELP my_qps The average number of requests per second over the previous minute
# TYPE my_qps gauge
my_qps 0.0
```
访问一次 172.29.4.18:32531/ 后,QPS 指标变为
```text
# HELP my_qps The average number of requests per second over the previous minute
# TYPE my_qps gauge
my_qps 0.016666666666666666
```
这里自定义的 QPS 指标统计的是一分钟内的每秒平均访问次数,即 1/60
Prometheus targets 中同样可见
![prometheus-targets.png](images%2Fprometheus-targets.png)
(此处名为 application-5c46dcf865-jdjcf 的 pod 为后续手工扩容后所得)
### 6. 在 Grafana 中定制应用的监控大屏
Grafana监控大屏:
![6-grafana.png](images%2F6-grafana.png)
### 7. 使用压测工具进行压测,并监控
使用 Jmeter 进行压测,配置如下:
设置 Loop Count 为 25,进行简单测试:
![1-jmeter-thread.png](images%2F1-jmeter-thread.png)
配置 HTTP 请求:
![1-jmeter-http.png](images%2F1-jmeter-http.png)
测试前:
![1-before.png](images%2F1-before.png)
开始测试:
![1-after.png](images%2F1-after.png)
可观察到 CPU 占用率略微上升,QPS 曲线明显上升,此处 QPS 显示结果为 0.333,即 20/60
Jmeter 结果树中观察到返回内容:
![1-jmeter-result.png](images%2F1-jmeter-result.png)
设置线程数为2,Loop Count 为 200,进行压力测试:
![3-jmeter-thread.png](images%2F3-jmeter-thread.png)
测试前:
![3-before.png](images%2F3-before.png)
开始测试:
![3-after.png](images%2F3-after.png)
可观察到 CPU 占用率明显上升,QPS 曲线大幅上升
### 8. 手工扩容,并监控
新建一个 Jenkins pipeline job,执行扩容命令
```groovy
node('slave') {
container('jnlp-kubectl') {
sh 'kubectl scale deployment application --replicas=4 -n nju21'
}
}
```
扩容前
![scale-before.png](images%2Fscale-before.png)
扩容成功
![scale-result.png](images%2Fscale-result.png)
![scale-after.png](images%2Fscale-after.png)
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment