一、SkyWalking三大架构模式
①、AOP架构模式
②、插件式架构模式
③、微内核架构模式
一个组件具有高扩展架构的话,需要具有微内核架构/插件式架构/无入侵
架构,例如:
二、skywalking介绍:应用监控和链路跟踪
随着互联网行业的飞速发展,业务规模增长迅速,复杂与过去相比大大提升。与此同时,微服务等技术的蓬勃发展,同样给开发带来不小的运维压力,导致我们经常需要面临这些问题:
①、链路较长:在微服务场景下,整个链路会变得很长,服务出问题时,往往不能第一时间排查出问题。
②、缺少监控:缺少对于服务器,应用组件的实时运行信息,做到心中有数。
③、预警不及时,粒度较大:经常在服务器响应延迟甚至宕机后,才能发现问题,同时粒度较大,无法在接口层面进行预警。
在这种背景下,SkyWalking作为应用监控和链路跟踪的利器,便脱颖而出
基于Agent技术,SkyWalking提供了例如吞吐量,QPS,JVM信息等丰富的指标供参考,做到有效同时地告警,利用其丰富的插件,能帮助我们跟踪Dubbo,ElasticSearch,Redis等这些组件的调用链路。
在这几年,SkyWalking同时也作为Apachc顶级项目,走上了世界的舞台,可以说SkyWalking就是目前APM体系中最受关注的一款软件。通过SkyWalking做了链路跟踪,系统监控,异常告警的落地,解决了开发过程中问题定位慢的痛点。
三、javaAgent探针技术, 使用场景
①、无入侵 链路跟踪
②、无入侵 动态线程池
③、无入侵 TransmitThreadLocal
④、无入侵的 命令行交互模式JVM诊断Arthas
四、分布式系统链路跟踪背景
随着微服务架构的流行,服务按照不同的维度进行拆分,一次请求往往需要涉及到多个服务,互联网应用构建在不同的软件模块集上,这些软件模块,有可能是由不同的团队开发,可能使用不同的编程语言来实现,有可能部署在了几千台服务器,横跨多个不同的数据中心,因此,就需要一些可以帮助理解系统的行为,用于分析性能问题的工具,以便发生故障的时候,能够快速定位和解决问题。
全链路监控组件就在这样的问题背景下产生了,最出名的是谷歌公开的论文提到的Google Dapper。想要在这个上下文中理解分布式系统的行为,就 需要监控那些横跨了不同的应用,不同的服务器之间的关联动作。
‘所以,在复杂的微服务架构系统中,几乎每一个前端请求都会形成一个复杂的分布式服务调用链路,一个请求完整的调用链路可能如下图所示:
一个请求完整的调用链路:
那么在业务规模不断增大,服务不断增多以及频繁变更的情况下,面对复杂的调用链路就带来一系列问题:
①、如何快速发现问题?
②、如何判断故障影响范围?
③、如何梳理服务依赖以及依赖的合理性?
④、如何分析链路性能以及实时容量规划?
⑤、吞吐量,根据拓扑可计算相应组件,平台,物理设备的实时吞吐量
⑥、响应时间,包括整体调用的响应时间和各个服务的响应时间等。
⑦、错误记录,根据服务返回统计单位时间异常次数。
全链路性能监控从整体维度到局部维度展示各个指标,将跨应用的所有调用链路性能信息集中展现,可方便度量整体和局部性能,并且方便找到故障产生的源头,生产上可极大缩短故障排查时间。
有了全链路监控工具,我们能够达到:
①、请求链路跟踪,故障快速定位:可以通过调用链路结合业务日志快速定位错误信息。
②、可视化:各个阶段耗时,进行性能分析
③、依赖优化:各个调用环节的可用性,梳理服务依赖关系以及优化
④、数据分析,优化链路:可以得到用户的行为路径,汇总分析应用在很多业务场景。
五、常见的监控工具对比:
六、SkyWalking的特点
①、性能好:针对单实例5000tps的应用,在全量采集的情况下,只增加10%的CPU开销
②、支持多语言探针
③、无入侵,支持自动以及手动探针
自动探针:java支持的中间件,框架与类库列表
手动探针:OpenTrackingApi,@Trace注解,traceId集成到日志中
七、完成SkyWaking平台的部署
用容器启动的,准备好docker-compose文件
version: "3.5"#容器列表services: elasticsearch: image: elasticsearch:7.9.0 container_name: elasticsearch restart: always ports: - 9200:9200 volumes: - ./elasticsearch7/logs:/usr/share/elasticsearch/logs - ./elasticsearch7/data:/usr/share/elasticsearch/data environment: - "discovery.type=single-node" #es单机模式 - "ES_JAVA_OPTS=-Xms512m -Xmx512m" - "TZ=Asia/Shanghai" - "TAKE_FILE_OWNERSHIP=true" #volumes 挂载权限 如果不想要挂载es文件改配置可以删除 ulimits: memlock: soft: -1 hard: -1 networks: monitor-network: aliases: - elasticsearch #数据的接入和聚合。 skywalking-oap: image: apache/skywalking-oap-server:8.0.1-es7 container_name: skywalking-oap depends_on: - elasticsearch links: - elasticsearch restart: always ports:#SkyWalking搭建的IP和端口 - 11800:11800 - 12800:12800 environment: - "SW_STORAGE=elasticsearch7" # 指定ES版本会把数据持久化到es - "SW_STORAGE_ES_CLUSTER_NODES=elasticsearch:9200" - "TZ=Asia/Shanghai" #时区设置 - "TAKE_FILE_OWNERSHIP=true" #解决 volumes 挂载权限问题 networks: monitor-network: aliases: - skywalking-oap # dashboard skywalking-ui: image: apache/skywalking-ui:8.0.1 container_name: ui depends_on: - skywalking-oap links: - skywalking-oap restart: always ports: - 13800:8080 environment: # 拿数据用的12800端口,通过后台服务aop拿数据 - "SW_OAP_ADDRESS=skywalking-oap:12800" - "TZ=Asia/Shanghai" networks: monitor-network: aliases: - skywalking-ui # docker network create monitor-networknetworks: monitor-network: external: name: "monitor-network"
然后部署,docker-compose up -d
docker ps:可以看到容器的启动:
然后访问:
七、一键完成带skywalkingAgent的SpringBoot应用的部署
(1)、如何进行SpringBoot,java应用的链路数据接入
因为skywalking采用无侵入的探针模式,那什么是探针呢?探针就是jvm提供了一套专门的接口给开发者使用,JVMTI这套接口是双向接口,对应用程序理解为客户端,也叫做探针,对JVM来说是目标的vm。链路收集的数据放入到探针里面,提供springboot应用使用进行链路采集,然后发送到skywalking的后台oap:观测分析平台。
JVMTI Client也叫agent代理或者探针,基于event事件机制,它接受事件,并执行JVM的控制,也能对事件进行回应。它有一个重要的特性:回调函数机制:JVM可以产生各种事件,面对各种事件,它提供了一个Callback数组,每个事件执行时,都会调用Callback函数,所以编写JVM TI Client的核心就是放置Callback函数。
正是有了这个机制能让我们向JVM发送指令,加载新的类定义
八、skywalingAgent的部署实操
skywalking的探针其实是一个jar包:skywalking-agent.jar
①、准备好两个应用:
demo-application和uaa-application
通过uaa进行远程的rpc调用demo
下面是demo-application的应用,work目录是映射到容器里面去的
在agent目录下skywalking的探针agent,skywalking-agnet.jar就是skywalking给我们提供的jar包:用来采集数据的
skywalking本身还是挺复杂的,它需要提供各种组件的链路收集,它以插件的形式支持不同组件数据的收集,还有配置数据,启动时的插件,日志数据。
②、如何使用探针的jar包呢?
如果我们在普通的环境下,我们使用如下命令:
使用如下命令,需要折成一行java-javaagent:D:\dev\apm\sky-walking\skywalking-agent\skywalking-agent.jar#应用的名字-Dskywalking.agent.service_name=apm-demo#aop的服务ip和端口-Dskywalking.collector.backend_service=cdh1:11800#项目的jar-jar xxxx.jar
如果我们在容器启动的话:看下编排文件:作用是制作镜像,然后把容器启动
version: '3.5'services: demo-provider: build: context: . dockerfile: Dockerfile image: w/demo-provider:1.0-SNAPSHOT container_name: demo-provider restart: always networks: base-env-network: aliases: - demo-provider extra_hosts: - "cdh1:192.168.56.121" - "cdh2:192.168.56.122" - "cdh3:192.168.56.123" volumes: #这个work目录是映射到容器里面去的 - ./work:/work ports: - "7700:7700" environment: - TAKE_FILE_OWNERSHIP=true #解决 volumes 挂载权限问题 - NACOS_SERVER=cdh1:8848 - LOG_PATH=/work/logs - JVM_CONF=-server -Xms64m -Xmx256m - filebeat_enable=false #把变量的值放到环境变量里面方便我们在shell脚本使用 - SKYWALKING_JAR_PATH=/work/agent/skywalking-agent.jar # 所搭建的aop服务的ip和端口 - SKYWALKING_RPC_ADDRESS=cdh1:11800 - SCAFFOLD_DB_HOST=cdh1 - SCAFFOLD_DB_USER=root - SCAFFOLD_DB_PSW=123456 - SCAFFOLD_REDIS_HOST=cdh1 - SCAFFOLD_REDIS_PSW=123456 - SCAFFOLD_EUREKA_ZONE_HOSTS=http://cdh1:7777/eureka/ - RABBITMQ_HOST=cdh1 - SCAFFOLD_ZOOKEEPER_HOSTS=cdh1:2181 # docker network create base-env-network networks: base-env-network: external: name: "base-env-network"
看下shell脚本,这个shell脚本是在DockerFile文件里面做处理的,DockFile文件是制作镜像的。首先看下shell脚本。
#!/bin/bash #服务参数 定制化SERVER_PORT=7700MAIN_CLASS="com.yang.springcloud.demo.start.DemoCloudApplication" PRO_NAME="demo-provider" #服务保持不变 JAR_NAME="/app/JarApplication.jar" WORK_PATH="/work" # export NACOS_SERVER=cdh2:8848# 向hosts文件追加内容# echo "192.168.56.121 cdh1" >> /etc/hosts# echo "192.168.56.122 cdh2" >> /etc/hosts# echo "192.168.56.123 cdh3" >> /etc/hosts #BOOT_STRAP_YML= "-Dspring.config.location=bootstrap.yaml" PROFILES_ACTIVE="-Dspring.profiles.active=sit"APPLICATION_CONFIG="-Dserver.port=${SERVER_PORT} ${PROFILES_ACTIVE} -Duser.timezone=GMT+08"REMOTE_CONFIG="-Xdebug -Xrunjdwp:transport=dt_socket,address=5005,server=y,suspend=n" SKYWALKING_CONFIG="-javaagent:${SKYWALKING_JAR_PATH} -Dskywalking.agent.service_name=${PRO_NAME} -Dskywalking.collector.backend_service=${SKYWALKING_RPC_ADDRESS}" #START_CMD="nohup java ${JVM_CONF} ${SKYWALKING_CONFIG} ${APPLICATION_CONFIG} -jar ${JAR_NAME} ${MAIN_CLASS} &" #如果环境变量配置了这个SKYWALKING_JAR_PATH走这个分支启动探针# 否则走下面的分支if [ "$SKYWALKING_JAR_PATH" != "" ]; then START_CMD="java ${JVM_CONF} ${SKYWALKING_CONFIG} ${APPLICATION_CONFIG} -jar ${JAR_NAME} ${MAIN_CLASS}"else START_CMD="java ${JVM_CONF} ${APPLICATION_CONFIG} -jar ${JAR_NAME} ${MAIN_CLASS}"fi RETVAL="0" # See how we were called.function start() { if [ "$filebeat_enable" != "" ]; then echo " start filebeat .........." chmod 777 /usr/local/filebeat-7.14.0-linux-x86_64/filebeat chmod go-w /work/filebeat/filebeat.yml chmod go-w /work/filebeat/input.yml nohup /usr/local/filebeat-7.14.0-linux-x86_64/filebeat -e -c /work/filebeat/filebeat.yml >> /work/filebeat/out.log 2>&1 & fi echo " start ${PRO_NAME} .........." echo "PORT:$SERVER_PORT" echo "JVM_CONF:$JVM_CONF" echo "START_CMD:$START_CMD" echo "LOG_PATH: $LOG_PATH" echo "SKYWALKING_CONFIG: $SKYWALKING_CONFIG" # nohup java ${JVM} ${APPLICATION_CONFIG} -jar ${WORK_PATH}/lib/${JAR_NAME} ${MAIN_CLASS} >> ${LOG} 2>&1 & # nohup java ${JVM} ${SKYWALKING_CONFIG} ${APPLICATION_CONFIG} ${BOOT_STRAP_YML} -jar ${JAR_NAME} ${MAIN_CLASS} & ${START_CMD} status } function stop() { pid=$(ps -ef | grep -v 'grep' | egrep $JAR_NAME| awk '{printf $2 " "}') if [ "$pid" != "" ]; then echo -n $"Shutting down boot: " kill -9 "$pid" else echo "${JAR_NAME} is stopped" fi status} function debug() { echo " start remote debug mode .........." if [ ! -f ${LOG} ]; then touch ${LOG} fi nohup java ${JVM} ${APPLICATION_CONFIG} ${REMOTE_CONFIG} -jar ${WORK_PATH}/lib/${JAR_NAME} ${MAIN_CLASS} >> ${LOG} 2>&1 &} function status(){ pid=$(ps -ef | grep -v 'grep' | egrep $JAR_NAME| awk '{printf $2 " "}') #echo "$pid" if [ "$pid" != "" ]; then echo "${JAR_NAME} is running,pid is $pid" else echo "${JAR_NAME} is stopped" fi} function usage(){ echo "Usage: $0 {start|debug|stop|restart|status}" RETVAL="2"} # See how we were called.case "$1" in start) start ;; debug) debug ;; stop) stop ;; restart) stop start ;; status) status ;; *) usage ;;esac exit ${RETVAL}
DockerFile文件如下:
#FROM openjdk:8-jre-alpine3.9-bashFROM filebeat:7.14.0ADD demo-provider-1.0-SNAPSHOT.jar /app/JarApplication.jar#这个脚本是放到容器里面的/app目录下的并改名为run.shADD deploy-sit.sh /app/run.shRUN chmod +x /app/run.sh # WORKDIR /app/#然后这个脚本会启动ENTRYPOINT /bin/bash -c "/app/run.sh start"# ENTRYPOINT /bin/bash
项目的部署结果如下: