原文网址:SkyWalking--官网/配置/指南_IT利刃出鞘的博客-CSDN博客

简介

说明

Skywalking是由国内开源爱好者吴晟(原OneAPM工程师,目前在华为)开源并提交到Apache孵化器的产品,它同时吸收了Zipkin/Pinpoint/CAT的设计思路。特点是:支持多种插件,UI功能较强,支持非侵入式埋点。目前使用厂商最多,版本更新较快。

数据存储支持:Elasticsearch、MySQL、H2、TiDB。默认是H2,而且是存到内存。项目中一般将其存到ES。

SkyWalking的两个服务

SkyWalking启动之后,会启动两个Java服务:Skywalking-Collector、Skywalking-Webapp

  1. Skywalking-Collector

    1. 追踪信息收集器
    2. 通过 gRPC/Http 收集客户端的采集信息。默认是gRPC
    3. Http默认端口 12800,gRPC默认端口 11800。
  2. Skywalking-Webapp
    1. 管理平台页面
    2. 默认端口 8080。可以在webapp/webapp.yml里修改

拉取模式和推送模式

Agent(客户端)收集数据并将其推送到后端,再对数据进一步分析,我们称之为“推送”模式。SkyWalking即便使用了推送模式,同时也可进行数据拉取。在最近的8.x的发版本中,SkyWalking支持从已经集成Prometheus的服务中获取终端用户的数据。

官网

入口

主页:http://skywalking.apache.org/
下载:https://skywalking.apache.org/downloads/
github:https://github.com/apache/skywalking
文档:https://github.com/apache/skywalking/tree/master/docs
博客:博客 | Apache SkyWalking
配置:https://github.com/apache/skywalking/tree/master/docs/en/setup/backend

总配置

https://github.com/apache/skywalking/blob/master/docs/en/setup/backend/backend-setup.md

性能测试

https://github.com/SkyAPMTest/

数据存储

存储的总配置

https://github.com/apache/skywalking/blob/master/docs/en/setup/backend/backend-storage.md

数据保留时间

https://github.com/apache/skywalking/blob/master/docs/en/setup/backend/ttl.md

对应配置文件位置为:apache-skywalking-apm-bin-es7\config\application.yml

In SkyWalking, there are two types of observability data:

  1. Records include traces, logs, topN sampled statements and alarm. recordDataTTL applies to record data.
  2. Metrics include all metrics for service, instance, endpoint, and topology map. Metadata(lists of services, instances, or endpoints) also belongs to metrics. metricsDataTTL applies to Metrics data.

These are the settings for the different types:

# Set a timeout on metrics data. After the timeout has expired, the metrics data will automatically be deleted.
    recordDataTTL: ${SW_CORE_RECORD_DATA_TTL:3} # Unit is day
    metricsDataTTL: ${SW_CORE_METRICS_DATA_TTL:7} # Unit is day

自动删除

SkyWalking有个自动删除的任务,默认会5分钟执行一次,删除超期的数据。

配置文件为:apache-skywalking-apm-bin-es7\config\application.yml

core:selector: ${SW_CORE:default}default:# Set a timeout on metrics data. After the timeout has expired, the metrics data will automatically be deleted.enableDataKeeperExecutor: ${SW_CORE_ENABLE_DATA_KEEPER_EXECUTOR:true} # Turn it off then automatically metrics data delete will be close.dataKeeperExecutePeriod: ${SW_CORE_DATA_KEEPER_EXECUTE_PERIOD:5} # How often the data keeper executor runs periodically, unit is minute

修改ES的配置(增加写入性能)

SkyWalking是批量往ES写数据的,SkyWalking的默认的批量处理的数量很小,会导致SkyWalking往ES写数据失败;这样会导致只能在SkyWalking页面查到最近几分钟的数据(在内存里暂时缓存的少量数据),无法查到更早的数据。

解决方案是提高ES的批量处理的性能,做法是修改ES的配置(elasticsearch.yml):

thread_pool.write.queue_size: 1000

详见下方官网的讲解。

官网:skywalking/ES-Server-FAQ.md at v6.3.0 · apache/skywalking · GitHub

启动skywalking后,添加的服务达到一定数量时,发现skywalking的ui界面查不到数据。原因可能是:

  1. 报了429错误 (SkyWalking往ES写数据失败)
  2. ES性能不够。

429错误的日志:

Suppressed: org.elasticsearch.client.ResponseException: method [POST], host [http://127.0.0.1:9200], URI [/service_instance_inventory/type/6_tcc-app-gateway-77b98ff6ff-crblx.cards_0_0/_update?refresh=true&timeout=1m], status line [HTTP/1.1 429 Too Many Requests]
{"error":{"root_cause":[{"type":"remote_transport_exception","reason":"[elasticsearch-0][10.16.9.130:9300][indices:data/write/update[s]]"}],"type":"es_rejected_execution_exception","reason":"rejected execution of org.elasticsearch.transport.TransportService$7@19a5cf02 on EsThreadPoolExecutor[name = elasticsearch-0/write, queue capacity = 200, org.elasticsearch.common.util.concurrent.EsThreadPoolExecutor@389297ad[Running, pool size = 2, active threads = 2, queued tasks = 200, completed tasks = 147611]]"},"status":429}at org.elasticsearch.client.RestClient$SyncResponseListener.get(RestClient.java:705) ~[elasticsearch-rest-client-6.3.2.jar:6.3.2]at org.elasticsearch.client.RestClient.performRequest(RestClient.java:235) ~[elasticsearch-rest-client-6.3.2.jar:6.3.2]at org.elasticsearch.client.RestClient.performRequest(RestClient.java:198) ~[elasticsearch-rest-client-6.3.2.jar:6.3.2]at org.elasticsearch.client.RestHighLevelClient.performRequest(RestHighLevelClient.java:522) ~[elasticsearch

查询的数据个数

apache-skywalking-apm-bin-es7\config\application.yml

storage:selector: ${SW_STORAGE:elasticsearch7}elasticsearch7:resultWindowMaxSize: ${SW_STORAGE_ES_QUERY_MAX_WINDOW_SIZE:10000}

这里控制SkyWalking的页面查询时的结果的个数。其一页是15个,所以会显示667页:

如果要修改这个参数,也要修改存储服务的查询的结果个数,比如ES的:

curl -XPUT "http://localhost:9200/my_index/_settings 282" -d '{ "index" : { "max_result_window" : 5000000 } }'

ES索引的含义

        如果选择了ES存储,产生数据时会自动创建索引并写入数据。索引的含义如下:

索引名 存的数据
sw_alarm_record-日期 告警记录
sw_log-日期 后端的日志
sw_segment-日期 链路追踪的信息(有traceId字段)

agent启动参数

启动命令示例

java \
-javaagent:D:\dev\MiddleGround\skywalking\apache-skywalking-apm-es7-8.7.0\apache-skywalking-apm-bin-es7\agent\skywalking-agent.jar \
-Dskywalking.agent.service_name=order \
-Dskywalking.collector.backend_service=127.0.0.1:11800 \
-jar order.jar

参数说明

参数

说明

-javaagent

指定skywalking的jar。
它是解析jar包用的,它会解析出jar包里网络操作然后记录到SkyWalking。

-Dskywalking.agent.service_name

指定服务名字(会将此名字显示在SkyWalking的前端页面上)

-Dskywalking.collector.backend_service

Skywalking-Collector的ip。(也就是Skywalking前端所在ip)

默认为:127.0.0.1:11800。

如果是用的Idea,设置位置如下

-D指定的参数可在agent配置文件里配置(agent/config/agent.config)

配置大全 (agent/config/agent.config)

# 命名空间,用于隔离跨进程传播的header。如果进行了配置,header将为HeaderName:Namespace.
# agent.namespace=${SW_AGENT_NAMESPACE:default-namespace}# 展示界面中现实服务名称
agent.service_name=${SW_AGENT_NAME:lizz-gw}# 每3秒采样道数默认情况下,负或零表示关闭
agent.sample_n_per_3_secs=${SW_AGENT_SAMPLE:-1}# 鉴权是否开启取决于后端的配置,可查看application.yml的详细描述。对于大多数的场景,需要后端对鉴权进行扩展。目前仅实现了基本的鉴权功能。
# agent.authentication = ${SW_AGENT_AUTHENTICATION:xxxx}# 单个线段中的最大跨距量。
# 通过这个配置项,SkyWalking可以估计应用程序内存开销。
# agent.span_limit_per_segment=${SW_AGENT_SPAN_LIMIT:150}# 如果段的操作名称以这些后缀结尾,则忽略这些段。
# agent.ignore_suffix=${SW_AGENT_IGNORE_SUFFIX:.jpg,.jpeg,.js,.css,.png,.bmp,.gif,.ico,.mp3,.mp4,.html,.svg}# 如果为true,则SkyWalking代理将在“/debugging”文件夹中保存所有检测到的类文件。
# SkyWalking可能会要求这些文件,以解决兼容问题。
# agent.is_open_debugging_class = ${SW_AGENT_OPEN_DEBUG:true}# 如果为true,SkyWalking代理将把所有检测到的类文件缓存到内存或磁盘文件中(由类缓存模式决定),
# 允许其他javaagent增强那些由SkyWalking agent增强的类。
# agent.is_cache_enhanced_class = ${SW_AGENT_CACHE_CLASS:false}# 插入指令的类缓存模式:内存或文件
# 内存:将类字节缓存到内存中,如果插入指令的类太多或太大,则可能会占用更多内存
# 文件:在“/class cache”文件夹中缓存类字节,当应用程序退出时自动清理缓存的类文件
# agent.class_cache_mode = ${SW_AGENT_CLASS_CACHE_MODE:MEMORY}# 操作名称最大长度
# 注意,在目前的实践中,我们不建议长度超过190。
# agent.operation_name_threshold=${SW_AGENT_OPERATION_NAME_THRESHOLD:150}# The agent use gRPC plain text in default.
# If true, SkyWalking agent uses TLS even no CA file detected.
# agent.force_tls=${SW_AGENT_FORCE_TLS:false}# 如果为true,则当用户创建新的配置文件任务时,skywalking代理将启用配置文件。否则禁用配置文件。
# profile.active=${SW_AGENT_PROFILE_ACTIVE:true}# 并行监视器段计数
# profile.max_parallel=${SW_AGENT_PROFILE_MAX_PARALLEL:5}# 最大监视段时间(分钟),如果当前段监视时间超出限制,则停止它。
# profile.duration=${SW_AGENT_PROFILE_DURATION:10}# 最大转储线程堆栈深度
# profile.dump_max_stack_depth=${SW_AGENT_PROFILE_DUMP_MAX_STACK_DEPTH:500}# 快照传输到后端缓冲区的大小
# profile.snapshot_transport_buffer_size=${SW_AGENT_PROFILE_SNAPSHOT_TRANSPORT_BUFFER_SIZE:50}# skywalking后端服务地址。
collector.backend_service=${SW_AGENT_COLLECTOR_BACKEND_SERVICES:127.0.0.1:11800}# 日志文件名
logging.file_name=${SW_LOGGING_FILE_NAME:skywalking-api.log}# 日志记录级别
logging.level=${SW_LOGGING_LEVEL:WARN}# 日志文件存储目录
# logging.dir=${SW_LOGGING_DIR:""}# 日志文件最大值, default: 300 * 1024 * 1024 = 314572800
# logging.max_file_size=${SW_LOGGING_MAX_FILE_SIZE:314572800}# 最大历史记录日志文件。当发生滚动时,如果日志文件超过这个数字,
# 然后删除最旧的文件。默认情况下,负数或零表示禁用。
# 如果不限制个数可能到只日志文件过大,磁盘爆满。
logging.max_history_files=${SW_LOGGING_MAX_HISTORY_FILES:5}# 忽略异常,有些异常属于业务需要,不用在sw中标示出来
# statuscheck.ignored_exceptions=${SW_STATUSCHECK_IGNORED_EXCEPTIONS:}# 异常链路的跟踪深度,最好不要高于10,对性能有影响
# statuscheck.max_recursive_depth=${SW_STATUSCHECK_MAX_RECURSIVE_DEPTH:1}# 增加agent下特定文件夹下的支持插件
plugin.mount=${SW_MOUNT_FOLDERS:plugins,activations,bootstrap-plugins}# 不加载某些支持插件,名称参考Plugin-list.md
plugin.exclude_plugins=${SW_EXCLUDE_PLUGINS:dubbo,motan}# 是否获取mysql操作sql的参数
# plugin.mysql.trace_sql_parameters=${SW_MYSQL_TRACE_SQL_PARAMETERS:false}# Kafka producer configuration
# plugin.kafka.bootstrap_servers=${SW_KAFKA_BOOTSTRAP_SERVERS:localhost:9092}# 跟踪Spring中的bean,需要耗费更多的资源
plugin.springannotation.classname_match_regex=${SW_SPRINGANNOTATION_CLASSNAME_MATCH_REGEX:}

关闭SkyWalking服务

由于官方没有提供关闭的脚本,详情见issue4698。只能手动去kill

1. 关闭Collector

默认是11800,查找占用端口11800的进程

lsof -i:11800

使用kill 杀掉进程

kill {pid}

2. 关闭SkyWlking UI的服务端口

默认是8080,查找占用端口8080的进程

lsof -i:8080

使用kill 杀掉进程

kill {pid}

写成脚本

#!/bin/shps -ef | grep skywalking-webapp.jar | grep -v grep | awk '{print $2}' | xargs kill
ps -ef | grep OAPServerStartUp | grep -v grep | awk '{print $2}' | xargs kill

插件

插件的配置文件也是agent/config/agent.config,只不过里边默认没有写插件的内容。

日志插件

参数

含义

-Dskywalking.plugin.toolkit.log.grpc.reporter.server_host

日志上报的服务器ip地址。默认为:localhost

-Dskywalking.plugin.toolkit.log.grpc.reporter.server_port

日志上报的服务器ip地址。默认为:11800

-Dplugin.toolkit.log.grpc.reporter.max_message_size

日志上报的最大信息大小。默认为:10485760

-Dplugin.toolkit.log.grpc.reporter.upstream_timeout

日志上报的超时时间。默认为:30

-Dplugin.toolkit.log.transmit_formatted

是否以格式化后再传输记录的数据。默认为true

可以写到agent/config/agent.config,内容为:

plugin.toolkit.log.grpc.reporter.server_host=${SW_GRPC_LOG_SERVER_HOST:127.0.0.1}
plugin.toolkit.log.grpc.reporter.server_port=${SW_GRPC_LOG_SERVER_PORT:11800}
plugin.toolkit.log.grpc.reporter.max_message_size=${SW_GRPC_LOG_MAX_MESSAGE_SIZE:10485760}
plugin.toolkit.log.grpc.reporter.upstream_timeout=${SW_GRPC_LOG_GRPC_UPSTREAM_TIMEOUT:30}

还要在logback里加入配置,例如:

<?xml version="1.0" encoding="UTF-8"?>
<configuration><!-- skywalking grpc 日志收集 8.4.0版本开始支持 --><appender name="SkyWalking"class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender"><encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout"><!--这里若用Spring的配置,显示会不正常,所以自定义--><pattern>[%tid] %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level --- [%15.15t] %logger{39} : %msg%n</pattern></layout></encoder></appender><root level="INFO"><appender-ref ref="SkyWalking"/></root>
</configuration>

忽略某个路径

官网:skywalking-java/trace-ignore-plugin.md at main · apache/skywalking-java · GitHub

很多插件中包含心跳请求,导致APM上传了很多不需要监控的路径,可以通过忽略这些路径减少上传分析的数据。

在agent/optional-plugins有个apm-trace-ignore-plugin-xxx.jar插件,用于处理忽略操作。

第1步:将apm-trace-ignore-plugin-xxx.jar拷贝到agent/activations或者agent/plugins目录

agent会扫描这两个路径下边的插件,插件路径的配置位置为:agent\config\agent.config:

plugin.mount=${SW_MOUNT_FOLDERS:plugins,activations}

第2步:配置要忽略的路径,有两种方案:

方案1:在agent/config下创建apm-trace-ignore-plugin.config文件

trace.ignore_path=/eureka/**,/apollo/**

方案2:使用启动参数

-javaagent:../skywalking-agent.jar=agent.service_name=gateway-dev3
-Dskywalking.trace.ignore_path=/eureka/**,Kafka/**

路径匹配规则(ant匹配模式)

  1. /path/?   单个字符
  2. /path/*   多个字符
  3. /path/**  多个字符和多级路径
  4. 多个规则使用逗号“,”分割

账号密码

从SkyWalking6.5开始,作者永久移除了UI页面的账号密码功能,说是不安全。

也就是说, 从SkyWalking6.5开始,访问UI页面无需账号密码就可以访问了,这样更不安全。所以,需要用第三方的工具来进行账号密码的验证。可以用Nginx。

组件支持

官网

官方的组件支持测试: https://github.com/SkyAPMTest/agent-integration-test-report

说明

SkyWalking支持如下组件的追踪(与组件版本有关,有的支持有的不支持):

  • Redisson
  • JdkHttp
  • Mysql
  • Spring-RestTemplate_Annotation_RestAnnotation
  • JettyClient_JettyServer
  • Vert.x
  • Strut2_H2
  • PostgreSQL
  • Spring-Async
  • OKHttp3
  • ActiveMQ
  • GRPC
  • MongoDB
  • Light4J
  • Elasticsearch
  • Httpasyncclient
  • RocketMQ
  • Httpclient
  • Gson
  • Jedis
  • Feign
  • Hystrix
  • spring-webflux
  • spring-gateway
  • Motan
  • RESTEasy
  • Zookeeper
  • Undertow
  • Lettuce
  • Pulsar
  • Skywalking-Header
  • Kafka
  • Undertow-Routing
  • Canal
  • solrj
  • RabbitMQ
  • Dubbox
  • Cassandra
  • Dubbo
  • SpringMVC
  • apm-toolkit-trace
  • Play
  • Servicecomb
  • ShardingSphere
  • Customize
  • jdkCrossThread
  • SOFARPC

性能

官方性能测试:https://github.com/SkyAPMTest/Agent-Benchmarks/blob/master/README_zh.md

用例1:高并发量

这个应用和用例1类似,但是我们做了一些调整,让他更像真实的应用。如我所说,用例-1只是一种证明极限的方法(后面还有更变态的用例☺)。这次,我们模拟300并发用户,将tps稳定在1000,当然,这也是很高的吞吐量了。CPU消耗会比之前明显降低,仅仅消耗6%

你可以看到,探针对TPS和响应时间,依然没有影响 。

用例2:超高并发量

这里一个常见的基于Spring的应用程序,他包含Spring Boot, Spring MVC,模拟的redis客户端,HikariCP连接池(匹配模拟的mysql客户端)。 监控这个应用程序,每个事务,探针会抓取5个span(1 Tomcat, 1 SpringMVC, 2 Jedis, 1 Mysql)。

请注意:我们这里提到了模拟客户端,之所以我们不使用真正的客户端,是因为,如果这样,服务端性能和网络的波动,会造成应用程序的tps不稳定,从而影响测试结果。如:mysql或redis服务器的配置,网络交换机性能,都会影响客户端性能,而这不是我们的测试目的。所以,我们要避免这种干扰因素。

这是一个近乎不可能的高流量应用。

我们模拟500并发用户,设置思考时间为10ms。而我们将应用性能设计的十分优秀,每秒能满足5000tps。

可以看到,探针进行监控时,针对一个负荷在200%以上的应用,只提高了10%的CPU负荷。并且我们不需要开启任何采样策略(注:当然skywalking是支持采样的),所以我们使用每秒要将超过5000个trace segment收集并发送到collector上。显然,skywalking探针拥有极高的性能。如大家所知,在一个x86服务器上的单应用实例,不太可能拥有如此之高的吞吐能力,除非,他内部是直接访问类似redis这样的高速缓存。即使如此,探针对tps和响应时间,也不会造成任何影响。

也就是说,在超高吞吐能力的服务器上,使用探针进行监控,也只是会消耗多一点点CPU,并不会影响应用性能。

老实说,一个单实例的应用,正常的tps都在100到1200之间。据我所知,即使是中国强大的电信和电商系统,单实例处理能力,也不过如此。所以,你真的不必担心探针的性能问题。

SkyWalking--官网/配置/指南相关推荐

  1. Vue3官网-高级指南(十五)Vue 与 Web Components

    Vue3官网-高级指南(十五)Vue 与 Web Components 文章目录 Vue3官网-高级指南(十五)Vue 与 Web Components 1. Vue 与 Web Components ...

  2. 天猫精灵智能家居对接,及天猫iot官网配置图文讲解(二)

    天猫精灵智能家居对接,及天猫iot官网配置图文讲解(二) 2.天猫精灵设备对接 2-1.介绍 ​ 上一章里,我已经讲了天猫精灵的技能配置,设备创建,登录验证这三个部分做了,此次篇文章就讲之后的设备查询 ...

  3. Vue3官网-高级指南(十七)响应式计算`computed`和侦听`watchEffect`(onTrack、onTrigger、onInvalidate、副作用的刷新时机、`watch` 、pre)

    Vue3官网-高级指南(十七)响应式计算computed和侦听watchEffect(onTrack.onTrigger.onInvalidate.副作用的刷新时机.watch .pre).渲染机制和 ...

  4. Threejs 官网 - 入门指南(Getting Started)

    Threejs 官网 - 入门指南(Getting Started) 太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一 ...

  5. 通过 Mysql 官网配置更新本地的mysql源

    参考连接:https://blog.csdn.net/xyang81/article/details/51759200前提环境:Centos 6.* 本身配置的yum源自带的mysql版本为5.1:后 ...

  6. SSR 实战:官网开发指南

    作者介绍 祯民,字节跳动前端开发工程师,公众号「祯民讲前端」作者.曾负责 抖音前端技术团队官网 和 字节官网中文版 的开发,现维护抖音直播内容安全相关的业务及 抖音直播宣传中心 的日常运营,对 SSR ...

  7. pytorch环境配置 一键官网配置+离线配置(anaconda+duda+cudnn+pytorch)

    pytorch环境配置(anaconda+duda+cudnn+pytorch) 目录 一:pytorch官网一键法 二:自行离线配置法 一:pytorch官网一键法 1.准备工作: 下载anacon ...

  8. Spring 官网阅读指南

    一.概述 Spring官网:https://spring.io/,界面如下: 二.各模块介绍 进入首页如上图,在首页官网会展示一些当前Spring比较流行的技术.可以看见导航栏有几个模块,信息如下: ...

  9. OpenStack L版官网配置转载(二)

    KeyStone安装与部署 控制节点: 完成下面的步骤以创建数据库: 用数据库连接客户端以 root 用户连接到数据库服务器: $ mysql -u root -p 创建 keystone 数据库: ...

最新文章

  1. PHP实现上一篇、下一篇
  2. 在redhat9上安装firefox
  3. Centos7.2搭建Openstack的Swift组件,查看状态:No such file or directory
  4. MyBatis和hibernate本质区别与应用场景
  5. 步进电机无细分和20细分_细分网站导航会话
  6. java 5 新特性 for_java5 新特性
  7. 微软.NET程序员必上的网站
  8. Spread基本知识(一)
  9. windows命令 笔记
  10. 【图像几何】基于matlab投影法测距【含Matlab源码 405期】
  11. 安卓系统dicom阅读器_文石BOOX发布新品poke2 color 全球首款开放系统彩色电纸书
  12. DCT--离散余弦变换
  13. 编译出的CHM文档读取页面发生脚本错误
  14. ESXi 6.7 封装驱动(Intel-I219V使用非vib的离线包驱动格式)
  15. Web认证方法探视(1)
  16. 身体的质量指数BMI
  17. android十大开源项目
  18. html如何添加web字体,html中字体如何实现加粗(方法介绍)_WEB前端开发,html,字体加粗...
  19. 世界各国坐标、中国各省会坐标、echars世界各国中英映射和省市区联动数据
  20. ECCV2022细粒度图像检索SEMICON代码学习记录

热门文章

  1. 关于整合ssh的问题,新人求关照
  2. Unix/Linux编程:exec()族函数
  3. 直播小程序推出,解锁2018微信直播新玩法
  4. 针对教育和软件行业的多平台Java勒索软件分析
  5. 中小企业如何才能招聘到合适的程序员?
  6. 瀚龙广告提供一站式的新型广告模式!大大增加用户体验
  7. 【游戏运营】【实战】首充分析——王国纪元
  8. 影响SAR图像电磁散射特性的因素
  9. 【实战技能】非技术背景经理的技术管理
  10. 鸿蒙系统电脑适配双面打印机,win10系统实现打印机双面打印的操作方法