一、配置Kubernetes借助于Prometheus-Adapter收集自定义指标,并由HPA v2基于自定义指标完成应用的自动扩缩容
# 部署prometheus以及相关监控组件
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 1.monitoring-namespace.yaml
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 2.daemonset-deploy-cadvisor.yaml
daemonset.apps/cadvisor created
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 3.daemonset-deploy-node-exporter.yaml
daemonset.apps/node-exporter created
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 4.metrics-server-v0.5.2.yaml
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 5.1.prometheus-cfg.yaml
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl create serviceaccount monitor -n monitoring
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl create clusterrolebinding monitor-clusterrolebinding -n monitoring --clusterrole=cluster-admin --serviceaccount=monitoring:monitor
[root@k8s-deployer ~]# mkdir -p /data/k8sdata/prometheus-data
[root@k8s-deployer prometheus-data]# chown -R 65534.65534 /data/k8sdata/prometheus-data
[root@k8s-deployer ~]# vim /etc/exports
/data/k8sdata/prometheus-data *(rw,no_root_squash)
[root@k8s-deployer prometheus-data]# systemctl restart nfs-server
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 5.2.prometheus-deployment.yaml
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 5.3.prometheus-svc.yaml
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 6.1.myserver-namespace.yaml
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 6.2.sample-httpserver.yaml
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 6.3.sample-httpserver-svc.yaml
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 6.4.tomcat/1.tomcat-yaml/tomcat-deploy.yaml
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 6.4.tomcat/1.tomcat-yaml/tomcat-svc.yaml
# 部署Prometheus-Adapter
[root@k8s-master1 adapter]# git clone -b release-0.10 https://github.com/kubernetes-sigs/prometheus-adapter.git
[root@k8s-master1 adapter]# cd prometheus-adapter/deploy
[root@k8s-master1 deploy]# ls
manifests README.md
[root@k8s-master1 deploy]# export PURPOSE=serving
[root@k8s-master1 deploy]# openssl req -x509 -sha256 -new -nodes -days 365 -newkey rsa:2048 -keyout ${PURPOSE}.key -out ${PURPOSE}.crt -subj "/CN=ca"
Generating a 2048 bit RSA private key
........................................................................................................................................+++
..........................+++
writing new private key to 'serving.key'
-----
[root@k8s-master1 deploy]# echo '{"signing":{"default":{"expiry":"43800h","usages":["signing","key encipherment","'${PURPOSE}'"]}}}' > "${PURPOSE}-ca-config.json"
[root@k8s-master1 deploy]# kubectl -n monitoring create secret generic cm-adapter-serving-certs --from-file=./serving.crt --from-file=./serving.key
secret/cm-adapter-serving-certs created
[root@k8s-master1 deploy]# sed -i 's/namespace: custom-metrics/namespace: monitoring/g' manifests/*.yaml
[root@k8s-master1 deploy]# vim manifests/custom-metrics-apiserver-deployment.yaml
[root@k8s-master1 deploy]# vim manifests/custom-metrics-config-map.yaml
[root@k8s-master1 deploy]# kubectl apply -f manifests/
#验证custom-metrics-apiserver pod状态为running状
[root@k8s-master1 deploy]# kubectl get pod -n monitoring
NAME READY STATUS RESTARTS AGE
cadvisor-9qbql 1/1 Running 4 (18m ago) 12d
cadvisor-hzpb7 1/1 Running 4 (18m ago) 12d
custom-metrics-apiserver-6d8b8f8769-stg9m 1/1 Running 0 40s
node-exporter-9stt4 1/1 Running 3 (18m ago) 8d
node-exporter-kt7h8 1/1 Running 3 (18m ago) 8d
prometheus-server-d7fcd9dd5-2l27z 1/1 Running 1 (18m ago) 28h
# HPA弹性伸缩测试,创建HPA控制器
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl apply -f 7.1.tomcat-hpa.yaml
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# kubectl get pod -n myserver
NAME READY STATUS RESTARTS AGE
sample-httpserver-85f78fff6d-ms2mr 1/1 Running 0 25m
tomcat-deployment-5f664dd496-5mz85 1/1 Running 0 2m22s # 新扩容的
tomcat-deployment-5f664dd496-jpt56 1/1 Running 0 7m10s
# 当带宽消耗达到阈值的时候就会触发自动扩容
[root@k8s-master1 prometheus-adapter-hpa-files-N79]# while true;do curl 172.18.10.102:31080/myapp/index.jsp;sleep 1 ;done
<h1>tomcat app1</h1>
<h1>tomcat app1</h1>
<h1>tomcat app1</h1>
<h1>tomcat app1</h1>
...
# 取消测试命令后验证
二、Prometheus基于VictoriaMetrics Cluster实现数据持久化
# 单机版部署
root@redis-1:/usr/local/src# tar -xvf victoria-metrics-amd64-v1.71.0.tar.gz
root@redis-1:/usr/local/src# mv victoria-metrics-prod /usr/local/bin/
root@redis-1:/usr/local/src# vim /etc/systemd/system/victoria-metrics-prod.service
[Unit]
Description=For Victoria-metrics-prod Service
After=network.target
[Service]
ExecStart=/usr/local/bin/victoria-metrics-prod -httpListenAddr=0.0.0.0:8428 -storageDataPath=/data/victoria -retentionPeriod=3
[Install]
WantedBy=multi-user.target
root@redis-1:/usr/local/src# systemctl daemon-reload && systemctl restart victoria-metrics-prod.service
# prometheus
root@redis-1:/usr/local/src# vim /apps/prometheus/prometheus/prometheus.yml
remote_write:
- url: http://172.18.10.141:8428/api/v1/write
root@redis-1:/usr/local/src# systemctl restart prometheus
grafana设置,添加数据源,类型为 prometheus,地址及端口为 VictoriaMetrics:
# 官方 docker-compsoe
root@redis-1:/usr/local/src# git clone https://github.com/VictoriaMetrics/VictoriaMetrics.git
root@redis-1:/usr/local/src# cd VictoriaMetrics/deployment/docker/
# 验证
# 集群版部署
# 环境 172.18.10.142、172.18.10.143、172.18.10.144
# 分别在各个 VictoriaMetrics 服务器进行安装配置
root@node2:~# tar xf victoria-metrics-linux-amd64-v1.94.0-cluster.tar.gz
root@node2:~# mv vminsert-prod vmselect-prod vmstorage-prod /usr/local/bin/
# 部署 vmstorage-prod 组件:负责数据的持久化,监听端口:API 8482 ,数据写入端口:8400,数据读取端口:8401
root@redis-3:~# vim /etc/systemd/system/vmstorage.service
[Unit]
Description=Vmstorage Server
After=network.target
[Service]
Restart=on-failure
WorkingDirectory=/tmp
ExecStart=/usr/local/bin/vmstorage-prod -loggerTimezone Asia/Shanghai -storageDataPath /data/vmstorage-data -httpListenAddr :8482 -vminsertAddr :8400 -vmselectAddr :8401
[Install]
WantedBy=multi-user.target
root@redis-3:~# systemctl daemon-reload && systemctl restart vmstorage.service && systemctl enable vmstorage.service
root@redis-3:~# scp /etc/systemd/system/vmstorage.service root@172.18.10.142:/etc/systemd/system/vmstorage.service
root@redis-3:~# scp /etc/systemd/system/vmstorage.service root@172.18.10.144:/etc/systemd/system/vmstorage.service
# 142和144执行
root@node2:~# systemctl daemon-reload && systemctl restart vmstorage.service && systemctl enable vmstorage.service
root@ubuntu-virtual-machine:~# systemctl daemon-reload && systemctl restart vmstorage.service && systemctl enable vmstorage.service
# 部署 vminsert-prod 组件 接收外部的写请求,默认端口 8480。
root@node2:~# vim /etc/systemd/system/vminsert.service
[Unit]
Description=Vminsert Server
After=network.target
[Service]
Restart=on-failure
WorkingDirectory=/tmp
ExecStart=/usr/local/bin/vminsert-prod -httpListenAddr :8480 -storageNode=172.18.10.142:8400,172.18.10.143:8400,172.18.10.144:8400
[Install]
WantedBy=multi-user.target
root@node2:~# systemctl daemon-reload && systemctl restart vminsert && systemctl enable vminsert
root@node2:~# scp /etc/systemd/system/vminsert.service root@172.18.10.143:/etc/systemd/system/vminsert.service
root@node2:~# scp /etc/systemd/system/vminsert.service root@172.18.10.143:/etc/systemd/system/vminsert.service
# 143和144执行
root@redis-3:~# systemctl daemon-reload && systemctl restart vminsert && systemctl enable vminsert
root@ubuntu-virtual-machine:~# systemctl daemon-reload && systemctl restart vminsert && systemctl enable vminsert
# 部署 vmselect-prod 组件:
root@node2:~# vim /etc/systemd/system/vmselect.service
[Unit]
Description=Vminsert Server
After=network.target
[Service]
Restart=on-failure
WorkingDirectory=/tmp
ExecStart=/usr/local/bin/vmselect-prod -httpListenAddr :8481 -storageNode=172.18.10.142:8401,172.18.10.143:8401,172.18.10.144:8401
[Install]
WantedBy=multi-user.target
root@node2:~# systemctl daemon-reload && systemctl restart vmselect && systemctl enable vmselect
root@node2:~# scp /etc/systemd/system/vmselect.service root@172.18.10.143:/etc/systemd/system/vmselect.service
root@node2:~# scp /etc/systemd/system/vmselect.service root@172.18.10.144:/etc/systemd/system/vmselect.service
# prometheus配置
remote_write:
- url: http://172.18.10.142:8480/insert/0/prometheus
- url: http://172.18.10.143:8480/insert/0/prometheus
- url: http://172.18.10.144:8480/insert/0/prometheus
root@redis-1:~# systemctl restart prometheus
三、总结单体应用与微服务优缺点
单体应用的优点:
1)单体应用通常使用一个 jar/war 文件部署(如Jenkins),结构简单、部署也简单。
2)与微服务架构相比,单体应用程序的设计、开发与测试更加容易和简单。
3)与微服务设计相比,使用单体应用程序时网络延迟和安全问题相对较小(因为都是本机调用)。
单体应用的缺点:
1)随着时间的推移,单体应用程序会变得过于庞大并且变得难以管理。
2)即使是单独的更新也需要重新部署整个应用程序。
3)随着应用程序规模的增大,管理和部署的时间也会增加(200兆的Java单体服务启动要花费好几分钟)。
4)影响团队协作、新开发人员很难理解大型整体应用程序的逻辑。
5)某一个功能的扩展,需要部署整个程序。
6)稳定性不可控、一个功能出现异常,会影响当前APP的所有功能甚至崩溃。
7)横向扩展效率慢。
微服务应用的缺点:
1)微服务通常是一个分布式服务,架构设计较难。
2)网络通信延迟比单体应用高。
3)跨主机通信的安全性问题。
4)故障排查、日志收集和监控相对复杂。
微服务应用的优点:
1)单个服务体积小,部署效率快、启动速度快、几乎秒级启动。
2)方便后期快速横向扩容。
3)如果要更新一个功能,那么只更新对应的APP即可。
4)不同的功能可以使用不同的数据库,方便分库分表。
5)只要提前定义好接口调用方式、每个应用可以使用不同的开发语言。
6)单个服务的宕机对整体业务影响较低。
7)开发者只需要维护自身的应用代码,甚至对其他服务可以完全不用关注。
8)去中心化,不依赖于任何一个中心服务。
四、总结服务的注册机发现机制、实现微服务的几个要素
服务的注册机发现机制:
容器化服务启动后,把信息注册到注册中心,消费服务会订阅注册中心,从中拿到地址信息,之后进行调用,监控组件做微服务的监控个管理。
实现微服务的要素:
1)微服务如何落地(容器化、容器编排工具)
2)微服务之间如何发现对方(注册中心、服务发现)
3)微服务之间如何访问对方(服务访问-> resetfulAPI)
4)微服务如何快速扩容(服务治理)
5)微服务如何监控(服务监控)
6)微服务如何升级与回滚(CI/CD)
7)微服务访问日志如何查看(ELK)
五、总结消息分发系统发展历史及对比、消息分发机制;
发展历史:
Message Queue的需求由来已久,最初的Message queuing软件叫做(the information
bus(TIB),后来IBM公司开发了MQSeries,微软也开发了MSMQ,但是价格昂贵,2004年摩根大通和iMatrix开始着手Advanced Message Queuing Protocol (AMQP)开放标准的开发,2006年,AMQP规范发布,2007年,
Rabbit技术公司基于AMQP标准开发的RabbitMQ 1.0 发布。
Java Message Service (JMS)规范首次发布于1998年,是一个Java平台中关于面向消息中间件(MOM,message oriented middleware)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信,Java消息服务应用程序结构支持两种模型:点对点或队列模型、发布/订阅模型。
MQ(Message queuing):消息队列的目的是为了实现各个APP之间的通讯,APP基于MQ实现消息的发送和接收实现应用程序之间的通讯,这样多个应用程序可以运行在不同的主机上,通过MQ就可以实现夸网络通信,因此MQ实现了业务的解耦和异步机制。
消息系统对比:
特性 | ActiveMQ | RabbitMQ | RocketMQ | Kafka |
---|---|---|---|---|
单机吞吐量 | 万级,比 RocketMQ、Kafka 低一个数量级 | 万级,比 RocketMQ、Kafka低一个数量级 | 10 万级,支撑高吞吐 | 10 万级,高吞吐,一般配合大数据类的系统来进行实时数据计算、日志采集等场景 |
topic 数量对吞吐量的影响 | topic 可以达到几百/几千的级别,吞吐量会有较小幅度的下降,这是 RocketMQ 的一大优势,在同等机器下,可以支撑大量的 topic | topic 从几十到几百个时候,吞吐量会大幅度下降,在同等机器下,Kafka 尽量保证 topic 数量不要过多,如果要支撑大规模的 topic,需要增加更多的机器资源 | ||
时效性 | ms 级 | 微秒级,这是RabbitMQ 的一大特点,延迟最低 | ms 级 | 延迟在 ms 级以内 |
可用性 | 高,基于主从架构实现高可用 | 高,基于主从架构实现高可用 | 非常高,分布式架构 | 非常高,分布式,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用 |
消息可靠性 | 有较低的概率丢失数据 | 主从环境保证消息高可用 | 经过参数优化配置,可以做到 0丢失 | 经过参数优化配置,可以做到 0 丢失 |
功能支持 | MQ 领域的功能非常完成 | MQ 领域的功能非常完成 | MQ 功能较为完善 | 功能较为简单,主要支持简单的 MQ功能,在大数据领域的实时计算以及日志采集被大规模使用 |
消息分发机制:JMS模型
点对点或队列模型,也叫生产者消费者模型,生产者向消息队列发送消息,但是只有一个消费者可以消费,基于异步机制发型消息,同时消息有确认机制,确保消息可以成功发送及消费。
发布/订阅模型:发布者发送消息到消息队列中,订阅改队列的多个消费者都可以消费,在发布者和订阅者之间存在时间依赖性,既已经发送的过的消息,后续新启动的消费者将无法消费。
六、总结Kafka简介及优缺点、Kafka逻辑架构详解
消息队列特点:
1)削峰填谷(主要解决瞬时写压力大于应用服务能力导致消息丢失、系统奔溃等问题)
2)系统解耦(解决不同重要程度、不同能力级别系统之间依赖导致一死全死)
3)提升性能(当存在一对多调用时,可以发一条消息给消息系统,让消息系统通知相关系统)
4)蓄流压测(线上有些链路不好压测,可以通过堆积一定量消息再放开来压测
5)FIFO机制:基于FIFO(first in first out,先进先出)机制保证业务消息的顺序处理
kafka简介:
kafka被称为下一代的分布式消息系统,是apache基金会开源软件。具有高吞吐量,即使是普通硬件也可以支持每秒上百万的消息。kafka通过O(1)的磁盘结构提供消息的持久化,这种结构对于TB级别的消息存储也能够保持长时间的稳定性能。kafka支持分区消息,再Hadoop等大数据环境被广泛使用。
kafka逻辑架构详解:
Producer:生产者,负责发布消息到Kafka broker。
Consumer:消费者,消费消息,每个consumer属于一个特定的consuer group(可为每个consumer指定group name,若不指定group name则属于默认的group),使用consumer high level API时,同一topic的一条消息只能被同一个consumer group内的一个consumer消费,但多个consumer group可同时消费这一消息。
Broker:Kafka集群包含一个或多个服务器,这种服务器被称为broker。
Topic :每条发布到Kafka集群的消息都有一个类别,这个类别被称为topic,(物理上不同topic的消息分开存储在不同的文件夹,逻辑上一个topic的消息虽然保存于一个或多个broker上但用户只需指定消息的topic即可生产或消费数据而不必关心数据存于何处),topic在逻辑上对record(记录、日志)进行分组保存,消费者需要订阅相应的topic才能消费topic中的消息。
Partition :是物理上的概念,每个topic包含一个或多个partition,创建topic时可指定parition数量,每个partition对应于一个文件夹,该文件夹下存储该partition的数据和索引文件,为了实现实现数据的高可用,比如将分区0的数据分散到不同的kafka节点,每一个分区都有一个broker作为leader和一个broker作为Follower。
kafka选举简介:
kafka有两种集群管理方式(不能同时使用):
1)基于zookeeper进行集群角色管理
2)基于Raft算法改进的kfaft进行集群角色管理,使用Raft的还有Consul、InfluxDB、etcd等。
Raft节点角色:集群中每个节点只能处于 Leader、Follower 和 Candidate 三种状态的一种
Leader:主节点,类似于redis的master
Follower:追随者,类似于redis cluster中的slave节点
Candidate:候选节点,只存在于选举过程中。
节点启动后基于termID(任期ID)进行相互投票,termID是一个整数默认值为0,在Raft算法中,一个term代表leader的一段任期周期,每当一个节点成为leader时,就会进入一个新的term, 然后每个节点都会在自己的term ID上加1,以便与上一轮选举区分开来。
配置详解:
Process.Roles:
如果Process.Roles = Broker, 服务器在KRaft模式中充当 Broker角色。
如果Process.Roles = Controller, 服务器在KRaft模式下充当 Controller角色
如果Process.Roles = Broker,Controller,服务器在KRaft模式中同时充当 Broker 角色和Controller角色。
如果process.roles 没有设置,那么集群就假定是运行在ZooKeeper模式下。
Kafka 分区与 Leader 选举规则:
分区中的所有副本的累计列表统称为AR(Assigned Repllicas)
Topic: myserver8 Partition: 0 Leader: 102 Replicas: 102,103,101 Isr: 102,103,101
Topic: myserver8 Partition: 1 Leader: 103 Replicas: 103,101,102 Isr: 103,101,102
Topic: myserver8 Partition: 2 Leader: 101 Replicas: 101,102,103 Isr: 101,102,103
所有与leader保持同步的副本(包括Leader)组成一组ISR(In-Sync Replicas),ISR集合是AR集合中的一个子集。
与leader同步延迟过多的副本(不包括leader),组成了OSR(Out-Sync Relipcas),由此可见:AR=ISR+OSR,但是在在正常情况下,所有的follower副本都应该与leader副本保持尽可能的同步,即正常情况下AR=ISR, 而OSR集合通常没有(即使宕机、只要还有主机资源很快就会自动修复)
在 ISR 中存活的副本为前提, 按照 AR 中排在前面的优先 。 例如 AR[ 101,102,103], ISR [ 101,102,103], 那么 Leader 就会按照 101,102,103 的顺序轮询。
zk与kraft模式对比:
场景 | ZK模式 | 问题 | kraft模式 |
---|---|---|---|
Controller故障转移 | 控制器赢得选举后,它会获取所有主题和分区,并将LeaderAndISR和UpdateMetaData发送给所有broker节点 | 假设有一个包含大量分区的大型kafka集群,此过程可能需要很长时间,并且在此期间集群将不可用 | 使用 KRaft 模式,一旦控制器赢得选举,它就会开始从代理获取请求,因此无需等待时间即可再次加载所有主题等 |
节点重启 | 滚动节点启动时期内当前节点没有元数,只有在重启完成并重新获取所有元数据后才可用 | 当集群中有很多可用分区时,获取元数据可能会花费更长的时间,这将导致节点在一段时间内不可用 | 使用 KRaft 模式,滚动更新过程中节点只需要获取本地缓存中没有的元数据,它使用元数据偏移量来做到实现元数据的更新 |
Zookeeper 依赖 | 需同时部署Kafka 和 ZooKeeper 是两种不同的服务,因此为了管理 Kafka 集群,我们还需要额外运行并管理zookeeper集群 | 需要关注zookeeper的状态,比如为了保证zk集群的安全,还必须为Zookeeper 设置安全、监控等 | 通过KRaft模式,Kafka已经标准化不再依赖Zookeeper来存储元数据,因此不需要部署和管理zookeeper集群 |
可扩展架性 | 在 ZooKeeper 模式下,Kafka 必须将其元数据存储在 zNode 中,每次集群启动或控制器选举发生时,Kafka控制器都必须从Zookeeper服务读取所有元数据,效率比较低 | 获取所有元数据期间kafka集群不可用,无法支持大规模的topic信息(超过一定分片后集群会变慢) | 动态横向扩展,kafka node只需要更新本地没有的元数据,支持的分片更多 |
易用性 | 需要时部署和维护zookeeper及kafka | 需要额外学习zookeeper相关知识 | 只需要维护kafka集群即可 |
七、基于kafka实现生产者与消费者的消息发送与接收(上课演示的python脚本)
[root@k8s-harbor 1.prometheus-case-files]# git clone https://gitee.com/jiege-gitee/kafka.git
[root@k8s-harbor kafka]# docker-compose up -d
root@redis-1:~/pydir# cat myserver-KafkaConsumer.py
#/usr/bin/env python3
#coding=utf-8
#pip3 install --index-url https://mirrors.aliyun.com/pypi/simple/ kafka-python
from kafka import KafkaConsumer
conn = KafkaConsumer('myserver',bootstrap_servers=['172.18.10.130:9092','172.18.10.130:9092','172.18.10.130:9092'])
for message in conn:
print ("%s:%d:%d: key=%s value=%s" % (message.topic, message.partition,
message.offset, message.key,message.value))
conn.close()root@redis-1:~/pydir# cat myserver-KafkaProducer.py
#/usr/bin/env python3
#coding=utf-8
#pip3 install --index-url https://mirrors.aliyun.com/pypi/simple/ kafka-python
from kafka import KafkaProducer
conn = KafkaProducer(bootstrap_servers=['172.18.10.130:9092','172.18.10.130:9092','172.18.10.130:9092'],compression_type='gzip')
conn.send('foobar', key=b'foo', value=b'bar')
for i in range(3):
msg = "msg%d" % i
#conn.send('myserver', msg)
conn.send('myserver',key=b'myserver-key', value=b'msg%d' % i)
print('topic-->myserver: msg%d发送成功!' % i)
root@redis-1:~/pydir# apt install python3-pip
root@redis-1:~/pydir# pip3 install --index-url https://mirrors.aliyun.com/pypi/simple/ kafka-python
root@redis-1:~/pydir# python3 myserver-KafkaConsumer.py # 消费者
root@redis-1:~/pydir# python3 myserver-KafkaProducer.py # 生产者