zoukankan      html  css  js  c++  java
  • zabbix监控服务

    Zabbix监控Nginx

    环境

    主机 ip 角色
    web01 172.16.1.7 nginx
    zabbix 172.16.1.71 zabbix_server

    开启状态监控

    server {
            listen 80;
            server_name 172.16.1.7;
            root /code;
            index index.html;
    
            location /nginx_status {
                stub_status on;
                access_log  off;
                allow all;
                deny all;
            }
    
            location ~ ^/(phpfpm_status)$ {
                 include fastcgi_params;
                 fastcgi_pass    127.0.0.1:9000;
                 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            }
    
    }
    

    本地访问nginx status

    [root@web01 ~]# curl http://127.0.0.1/nginx_status
    Active connections: 1 
    server accepts handled requests
     30927 30927 30922 
    Reading: 0 Writing: 1 Waiting: 0
    

    编写nginx的shell脚本

    [root@web01 ~]# mkdir -p /etc/zabbix/scripts
    [root@web01 scripts]# vim /etc/zabbix/scripts/nginx_status.sh
    #!/bin/bash
    ############################################################
    # $Name:         nginx_status.sh
    # $Version:      v1.0
    # $Function:     Nginx Status
    # $Author:       DriverZeng
    # $organization: blog.driverzeng.com
    # $Create Date:  2016-06-23
    # $Description:  Monitor Nginx Service Status
    ############################################################
    
    NGINX_PORT=80  #如果端口不同仅需要修改脚本即可,否则修改xml很麻烦
    NGINX_COMMAND=$1
    
    
    nginx_active(){
        /usr/bin/curl -s "http://127.0.0.1:"$NGINX_PORT"/nginx_status/" |awk '/Active/ {print $NF}'
    }
    
    nginx_reading(){
        /usr/bin/curl -s "http://127.0.0.1:"$NGINX_PORT"/nginx_status/" |awk '/Reading/ {print $2}'
    }
    
    nginx_writing(){
        /usr/bin/curl -s "http://127.0.0.1:"$NGINX_PORT"/nginx_status/" |awk '/Writing/ {print $4}'
           }
    
    nginx_waiting(){
        /usr/bin/curl -s "http://127.0.0.1:"$NGINX_PORT"/nginx_status/" |awk '/Waiting/ {print $6}'
           }
    
    nginx_accepts(){
        /usr/bin/curl -s "http://127.0.0.1:"$NGINX_PORT"/nginx_status/" |awk 'NR==3 {print $1}'
           }
    
    nginx_handled(){
        /usr/bin/curl -s "http://127.0.0.1:"$NGINX_PORT"/nginx_status/" |awk 'NR==3 {print $2}'
           }
    
    nginx_requests(){
        /usr/bin/curl -s "http://127.0.0.1:"$NGINX_PORT"/nginx_status/" |awk 'NR==3 {print $3}'
           }
    
    
      case $NGINX_COMMAND in
        active)
            nginx_active;
            ;;
        reading)
            nginx_reading;
            ;;
        writing)
            nginx_writing;
            ;;
        waiting)
            nginx_waiting;
            ;;
        accepts)
            nginx_accepts;
            ;;
        handled)
            nginx_handled;
            ;;
        requests)
            nginx_requests;
            ;;
              *)
            echo $"USAGE:$0 {active|reading|writing|waiting|accepts|handled|requests}"
        esac
    

    给脚本添加执行权限

    [root@web01]# chmod +x /etc/zabbix/scripts/nginx_status.sh
    

    配置监控项

    [root@web01 ~]# cat /etc/zabbix/zabbix_agentd.d/nginx_status.conf
    UserParameter=nginx_status[*],/bin/bash /etc/zabbix/zabbix_agentd.d/scripts/nginx_status.sh "$1"
    

    重启

    [root@web01 ~]# systemctl restart zabbix-agent
    

    取值

    #zabbix客户端取值
    [root@web01 ~]# zabbix_agent -t nginx_status[writing]
    1
    #zabbix服务端取值
    [root@web01 ~]# zabbix_get -s 172.16.1.7 -k nginx_status[writing]
    1
    
    
    [![wNYm5T.md.png](https://s1.ax1x.com/2020/09/11/wNYm5T.md.png)](https://imgchr.com/i/wNYm5T)
    

    添加监控项

    wNYeaV.md.png

    添加触发器

    wNYZV0.md.png](ht

    监控模板成品示例

    wNY5ss.md.png

    zabbix监控PHP

    环境

    主机 ip 角色
    web01 172.16.1.7 nginx,php
    zabbix 172.16.1.71 zabbix_server

    1.PHP-FPM工作模式通常与Nginx结合使用,修改php-fpm.conf

    [root@web01 ~]# vim /etc/php-fpm.d/www.conf
    pm.status_path = /phpfpm_status
    

    2.修改nginx.conf的配置文件,增加如下location访问PHP-FPM状态信息。

       location ~ ^/(phpfpm_status)$ {
            include fastcgi_params;
            fastcgi_pass    127.0.0.1:9000;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
    

    3.访问测试phpfpm_status

    [root@web01 ~]# curl http://127.0.0.1/phpfpm_status
    pool:                 www
    process manager:      dynamic
    start time:           05/Jul/2016:15:30:56 +0800
    start since:          409
    accepted conn:        22
    listen queue:         0
    max listen queue:     0
    listen queue len:     128
    idle processes:       4
    active processes:     1
    total processes:      5
    max active processes: 2
    max children reached: 0
    
    #PHP-FPM状态解释:
    pool 					#fpm池名称,大多数为www
    process manager 		#进程管理方式dynamic或者static
    start time 				#启动日志,如果reload了fpm,时间会更新
    start since				 #运行时间
    accepted conn 			#当前池接受的请求数
    listen queue 			#请求等待队列,如果这个值不为0,那么需要增加FPM的进程数量
    max listen queue 		#请求等待队列最高的数量
    listen queue len 		#socket等待队列长度
    idle processes 			#空闲进程数量
    active processes 		#活跃进程数量
    total processes 		#总进程数量
    max active processes 	#最大的活跃进程数量(FPM启动开始计算)
    max children reached 	#程最大数量限制的次数,如果这个数量不为0,那说明你的最大进程数量过小,可以适当调整。
    

    4.编写php-fpmShell脚本(如果端口不一致,只需要修改脚本端口即可)

    [root@web01 ~]# cd /etc/zabbix/scripts
    [root@web01 scripts]# vim phpfpm_status.sh
    #!/bin/bash
    ############################################################
    # $Name:         phpfpm_status.sh
    # $Version:      v1.0
    # $Function:     Nginx Status
    # $Author:       DriverZeng
    # $organization: blog.driverzeng.com
    # $Create Date:  2016-06-23
    # $Description:  Monitor Nginx Service Status
    ############################################################
    
    PHPFPM_COMMAND=$1
    PHPFPM_PORT=80  #根据监听不同端口进行调整
    
    start_since(){
        /usr/bin/curl -s "http://127.0.0.1:"$PHPFPM_PORT"/phpfpm_status" |awk '/^start since:/ {print $NF}'
    }
    
    accepted_conn(){
        /usr/bin/curl -s "http://127.0.0.1:"$PHPFPM_PORT"/phpfpm_status" |awk '/^accepted conn:/ {print $NF}'
    }
    
    listen_queue(){
        /usr/bin/curl -s "http://127.0.0.1:"$PHPFPM_PORT"/phpfpm_status" |awk '/^listen queue:/ {print $NF}'
    }
    
    max_listen_queue(){
        /usr/bin/curl -s "http://127.0.0.1:"$PHPFPM_PORT"/phpfpm_status" |awk '/^max listen queue:/ {print $NF}'
    }
    
    listen_queue_len(){
        /usr/bin/curl -s "http://127.0.0.1:"$PHPFPM_PORT"/phpfpm_status" |awk '/^listen queue len:/ {print $NF}'
    }
    
    idle_processes(){
        /usr/bin/curl -s "http://127.0.0.1:"$PHPFPM_PORT"/phpfpm_status" |awk '/^idle processes:/ {print $NF}'
    }
    
    active_processes(){
        /usr/bin/curl -s "http://127.0.0.1:"$PHPFPM_PORT"/phpfpm_status" |awk '/^active processes:/ {print $NF}'
    }
    
    total_processes(){
        /usr/bin/curl -s "http://127.0.0.1:"$PHPFPM_PORT"/phpfpm_status" |awk '/^total processes:/ {print $NF}'
    }
    
    max_active_processes(){
        /usr/bin/curl -s "http://127.0.0.1:"$PHPFPM_PORT"/phpfpm_status" |awk '/^max active processes:/ {print $NF}'
    }
    
    max_children_reached(){
        /usr/bin/curl -s "http://127.0.0.1:"$PHPFPM_PORT"/phpfpm_status" |awk '/^max children reached:/ {print $NF}'
    }
    
    slow_requests(){
        /usr/bin/curl -s "http://127.0.0.1:"$PHPFPM_PORT"/phpfpm_status" |awk '/^slow requests:/ {print $NF}'
    }
    
    case $PHPFPM_COMMAND in
        start_since)
            start_since;
            ;;
        accepted_conn)
            accepted_conn;
            ;;
        listen_queue)
            listen_queue;
            ;;
        max_listen_queue)
            max_listen_queue;
            ;;
        listen_queue_len)
            listen_queue_len;
            ;;
        idle_processes)
            idle_processes;
            ;;
        active_processes)
            active_processes;
            ;;
            total_processes)
                    total_processes;
                    ;;
            max_active_processes)
                    max_active_processes;
                    ;;
            max_children_reached)
                    max_children_reached;
                    ;;
            slow_requests)
                    slow_requests;
                    ;;
              *)
            echo $"USAGE:$0 {start_since|accepted_conn|listen_queue|max_listen_queue|listen_queue_len|idle_processes|active_processes|total_processes|max_active_processes|max_children_reached|slow_requests}"
        esac
    

    5.给脚本添加执行权限

    [root@web01 scripts]# chmod +x phpfpm_status.sh
    

    6.监控项的phpfpm_status.conf配置文件如下:

    [root@web01 ~]# cat /etc/zabbix/zabbix_agentd.d/phpfpm_status.conf
    UserParameter=phpfpm_status[*],/bin/bash /etc/zabbix/scripts/phpfpm_status.sh "$1"
    

    6.重启zabbix-agent

    [root@web01 ~]# systemctl restart zabbix-agent
    

    7.Server使用zabbix_get命令来获取Agent端的值

    [root@web01]# zabbix_get -s 172.16.1.7 -k phpfpm_status[accepted_conn]
    45
    

    添加监控项

    wNN6C8.md.png

    添加触发器

    wNNrUP.md.png

    监控模板成品示例

    wNNs4f.md.png

    Zabbix监控MySQL

    percona Monitoring Plugins是一个高质量的组件,为MySQL数据库添加企业级的监控和图表功能。但其脚本使用PHP实现,故而Zabbix-Agent需要安装PHP环境。

    percona工具集

    实践环境

    主机 ip 角色
    web01 172.16.1.7 mysql,php,percona
    zabbix 172.16.1.71 zabbix_server

    1.在Zabbix-Agent端安装percona Monitoring Plugins

    [root@web01 ~]# yum install -y http://www.percona.com/downloads/percona-release/redhat/0.1-3/percona-release-0.1-3.noarch.rpm
    [root@Agent ~]# yum install percona-zabbix-templates -y
    

    2.查看percona安装后的目录结构

    [root@web01 percona]# tree /var/lib/zabbix/percona
    /var/lib/zabbix/percona
    ├── scripts  #脚本文件路径
    │   ├── get_mysql_stats_wrapper.sh
    │   └── ss_get_mysql_stats.php
    └── templates
        ├── userparameter_percona_mysql.conf  #key文件位置
        └── zabbix_agent_template_percona_mysql_server_ht_2.0.9-sver1.1.6.xml #模板文件位置
    

    4.将自定义监控项配置文件复制至/etc/zabbix_agentd.conf.d目录下

    [root@web01 ~]# cp /var/lib/zabbix/percona/templates/userparameter_percona_mysql.conf  /etc/zabbix/zabbix_agentd.d/percona_mysql.conf
    

    5.重启zabbix-agent

    [root@web01 ~]# systemctl restart zabbix-agent
    

    6.修改脚本中的MySQL用户名和密码

    [root@web01 scripts]# vim /var/lib/zabbix/percona/scripts/ss_get_mysql_stats.php
    $mysql_user = 'root';
    $mysql_pass = '123';
    $mysql_port = 3306;
    

    7.在Zabbix-Server端上使用Zabbix_get获取值(否则会失败)

    [root@web01 ~]# zabbix_get -s 172.16.1.7 -k MySQL.pool-read-requests
    223003813
    
    #如果获取不到值常见问题
    1.看是否是MySQL密码错误
    2.不要直接执行脚本来获取
    3.在zabbix_agent删除/tmp/localhost-mysql_cacti_stats.txt文件
    4.权限问题导致
    

    8.在Zabbix页面模板选项中导入Percona模板, 模板存放在/var/lib/zabbix/percona/templates, 最后关联主机即可。

    上传监控模板

    wNaNmd.md.png

    监控模板实例

    wNaU0A.md.png

    Zabbix监控Redis

    Redis使用自带的INFO命令,进行状态监控。以一种易于解释且易于阅读的格式,返回关于Redis服务器的各种信息和统计数值。

    实践环境

    主机 ip 角色
    web01 172.16.1.7 redis,php
    zabbix 172.16.1.71 zabbix_server

    1.编写Shell脚本

    • 脚本端口、连接redis服务地址根据具体情况进行修改
    • AUTH认证没有开启,将PASSWD修改为空即可。
    [root@Agent ~]# mkdir -p  /etc/zabbix/scripts
    [root@Agent ~]# vim /etc/zabbix/scripts/redis_status.sh
    #!/bin/bash
    ############################################################
    # $Name:         redis_status.sh
    # $Version:      v1.0
    # $Function:     Redis Status
    # $Author:       DriverZeng
    # $organization: blog.driverzeng.com
    # $Create Date:  2016-06-23
    # $Description:  Monitor Redis Service Status
    ############################################################
    
    R_COMMAND="$1"
    R_PORT="6379"  #根据实际情况调整端口
    R_SERVER="127.0.0.1"  #根据具体情况调整IP地址
    PASSWD=""    #如果没有设置Redis密码,为空即可
    
    
    redis_status(){
       (echo -en "AUTH $PASSWD
    INFO
    ";sleep 1;) | /usr/bin/nc "$R_SERVER" "$R_PORT" > /tmp/redis_"$R_PORT".tmp
          REDIS_STAT_VALUE=$(grep "$R_COMMAND:" /tmp/redis_"$R_PORT".tmp | cut -d ':' -f2)
           echo "$REDIS_STAT_VALUE"
    }
    
    case $R_COMMAND in
        used_cpu_user_children)
        redis_status "$R_PORT" "$R_COMMAND"
        ;;
        used_cpu_sys)
        redis_status "$R_PORT" "$R_COMMAND"
        ;;
        total_commands_processed)
        redis_status "$R_PORT" "$R_COMMAND"
        ;;
        role)
        redis_status "$R_PORT" "$R_COMMAND"
        ;;
        lru_clock)
        redis_status "$R_PORT" "$R_COMMAND"
        ;;
        latest_fork_usec)
        redis_status "$R_PORT" "$R_COMMAND"
        ;;
        keyspace_misses)
        redis_status "$R_PORT" "$R_COMMAND"
        ;;
        keyspace_hits)
        redis_status "$R_PORT" "$R_COMMAND"
        ;;
        keys)
        redis_status "$R_PORT" "$R_COMMAND"
        ;;
        expires)
        redis_status "$R_PORT" "$R_COMMAND"
        ;;
        expired_keys)
        redis_status "$R_PORT" "$R_COMMAND"
        ;;
        evicted_keys)
        redis_status "$R_PORT" "$R_COMMAND"
        ;;
        connected_clients)
        redis_status "$R_PORT" "$R_COMMAND"
        ;;
        changes_since_last_save)
        redis_status "$R_PORT" "$R_COMMAND"
        ;;
        blocked_clients)
        redis_status "$R_PORT" "$R_COMMAND"
        ;;
        bgsave_in_progress)
        redis_status "$R_PORT" "$R_COMMAND"
        ;;
        bgrewriteaof_in_progress)
        redis_status "$R_PORT" "$R_COMMAND"
        ;;
        used_memory_peak)
        redis_status "$R_PORT" "$R_COMMAND"
        ;;
        used_memory)
        redis_status "$R_PORT" "$R_COMMAND"
        ;;
        used_cpu_user)
        redis_status "$R_PORT" "$R_COMMAND"
        ;;
        used_cpu_sys_children)
        redis_status "$R_PORT" "$R_COMMAND"
        ;;
        total_connections_received)
        redis_status "$R_PORT" "$R_COMMAND"
        ;;
        *)
        echo $"USAGE:$0 {used_cpu_user_children|used_cpu_sys|total_commands_processed|role|lru_clock|latest_fork_usec|keyspace_misses|keyspace_hits|keys|expires|expired_keys|connected_clients|changes_since_last_save|blocked_clients|bgrewriteaof_in_progress|used_memory_peak|used_memory|used_cpu_user|used_cpu_sys_children|total_connections_received}"
        esac
    

    Redis状态参数解释:

    server : Redis 服务器信息,包含以下域:
    redis_version : Redis 服务器版本
    redis_git_sha1 : Git SHA1
    redis_git_dirty : Git dirty flag
    os : Redis 服务器的宿主操作系统
    arch_bits : 架构(32 或 64 位)
    multiplexing_api : Redis 所使用的事件处理机制
    gcc_version : 编译 Redis 时所使用的 GCC 版本
    process_id : 服务器进程的 PID
    run_id : Redis 服务器的随机标识符(用于 Sentinel 和集群)
    tcp_port : TCP/IP 监听端口
    uptime_in_seconds : 自 Redis 服务器启动以来,经过的秒数
    uptime_in_days : 自 Redis 服务器启动以来,经过的天数
    lru_clock : 以分钟为单位进行自增的时钟,用于 LRU 管理
    clients : 已连接客户端信息,包含以下域:
    connected_clients : 已连接客户端的数量(不包括通过从属服务器连接的客户端)
    client_longest_output_list : 当前连接的客户端当中,最长的输出列表
    client_longest_input_buf : 当前连接的客户端当中,最大输入缓存
    blocked_clients : 正在等待阻塞命令(BLPOP、BRPOP、BRPOPLPUSH)的客户端的数量
    memory : 内存信息,包含以下域:
    used_memory : 由 Redis 分配器分配的内存总量,以字节(byte)为单位
    used_memory_human : 以人类可读的格式返回 Redis 分配的内存总量
    used_memory_rss : 从操作系统的角度,返回 Redis 已分配的内存总量(俗称常驻集大小)。这个值和 top 、 ps 等命令的输出一致。
    used_memory_peak : Redis 的内存消耗峰值(以字节为单位)
    used_memory_peak_human : 以人类可读的格式返回 Redis 的内存消耗峰值
    used_memory_lua : Lua 引擎所使用的内存大小(以字节为单位)
    mem_fragmentation_ratio : used_memory_rss 和 used_memory 之间的比率
    persistence : RDB 和 AOF 的相关信息
    stats : 一般统计信息
    replication : 主/从复制信息
    cpu : CPU 计算量统计信息
    commandstats : Redis 命令统计信息
    cluster : Redis 集群信息
    keyspace : 数据库相关的统计信息
    参数还可以是下面这两个:
    all : 返回所有信息
    default : 返回默认选择的信息
    当不带参数直接调用 INFO 命令时,使用 default 作为默认参数。
    

    3.添加脚本执行权限

    [root@Agent ~]# chmod +x /etc/zabbix/scripts/redis_status.sh
    

    4.Zabbix权限不足处理办法

    [root@Agent ~]# rm -f /tmp/redis_6379.tmp
    

    5.key的redis_status.conf的配置文件如下:

    [root@Agent ~]# cat /etc/zabbix/zabbix_agentd.d/redis_status.conf
    UserParameter=redis_status[*],/bin/bash /etc/zabbix/scripts/redis_status.sh "$1" 
    

    6.重启zabbix-agent

    [root@Agent ~]# systemctl restart  zabbix-agent
    

    7.在Zabbix-Server使用Zabbix_get获取值

    [root@Server ~]# zabbix_get -s 172.16.1.7 -k redis_status[used_cpu_sys]
    16.81
    

    上传模板

    wNdujg.md.png

    模板示例

    wNdMuQ.md.png

    Zabbix监控JVM

    在Zabbix中,JMX监控数据的获取由专门的代理程序来实现,即Zabbix-Java-Gateway来负责数据的采集,Zabbix-Java-Gateway和JMX的Java程序之间通信获取数据

    JMX在Zabbix中的运行流程:

    1.Zabbix-Server找Zabbix-Java-Gateway获取Java数据
    2.Zabbix-Java-Gateway找Java程序(zabbix-agent)获取数据
    3.Java程序返回数据给Zabbix-Java-Gateway
    4.Zabbix-Java-Gateway返回数据给Zabbix-Server
    5.Zabbix-Server进行数据展示
    

    配置JMX监控的步骤:

    1.安装Zabbix-Java-Gateway。
    2.配置zabbix_java_gateway.conf参数。
    3.配置zabbix-server.conf参数。
    4.Tomcat应用开启JMX协议。
    5.ZabbixWeb配置JMX监控的Java应用。
    

    环境

    主机 角色 IP
    zabbix Zabbix-Server 172.16.1.71
    web01 Zabbix-java-gateway 10.0.0.8
    web01 Zabbix-Agent 172.16.1.7

    zabbix_java_gateway

    1.安装java以及zabbix-java-gateway (如果源码安装加上--enable-java参数)

    //安装java-gateway
    [root@web01 ~]# yum install  zabbix-java-gateway java-1.8.0-openjdk -y
    

    2.配置zabbix-java-gateway

    vim /etc/zabbix/zabbix_java_gateway.conf
    

    3.启动zabbix-java-gateway

    [root@web01 ~]# systemctl start zabbix-java-gateway
    [root@web01 ~]# netstat -lntup|grep 10052
    tcp6       0      0 :::10052                :::*                    LISTEN      13042/java
    

    4.修改zabbix-server 配置文件

    [root@web01 ~]# vim /etc/zabbix/zabbix_server.conf
    #java gateway地址
    JavaGateway=172.16.1.7  
    #java gateway默认端口10052
    JavaGatewayPort=10052
    #启动进程轮询java gateway
    StartJavaPollers=5
    

    5.重启zabbix-server

    [root@web01 ~]# systemctl restart zabbix-server
    

    6.安装tomcat服务

    mkdir /soft/package/src -p
    wget http://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-9/v9.0.2/bin/apache-tomcat-9.0.2.tar.gz
    tar xf apache-tomcat-9.0.2.tar.gz -C /soft/
    ln -s /soft/apache-tomcat-9.0.2/ /soft/tomcat
    

    7.开启tomcat的远程jvm配置文件

    [root@web01 ~]# vim /usr/local/tomcat/bin/catalina.sh
    CATALINA_OPTS="$CATALINA_OPTS
    -Dcom.sun.management.jmxremote
    -Dcom.sun.management.jmxremote.port=12345
    -Dcom.sun.management.jmxremote.authenticate=false
    -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=172.16.1.7"
    
    
    #jvm配置文件解释
    CATALINA_OPTS="$CATALINA_OPTS
    //启用远程监控JMX
    -Dcom.sun.management.jmxremote
    //jmx启用远程端口,Zabbix添加时必须一致
    -Dcom.sun.management.jmxremote.port=12345
    //不开启用户密码认证
    -Dcom.sun.management.jmxremote.authenticate=false
    //不启用ssl加密传输
    -Dcom.sun.management.jmxremote.ssl=false
    //运行tomcat主机的IP地址
    -Djava.rmi.server.hostname=172.16.1.7"
    

    7.重启tomcat服务

    [root@web01 ~]# /usr/local/tomcat/bin/shutdown.sh
    [root@web01 ~]# /usr/local/tomcat/bin/startup.sh
    

    8.zabbix添加tomcat主机,并添加Zabbix自带java监控模板

    监控项的感叹号解决方法

    wNgcTS.md.png

  • 相关阅读:
    判断arm立即数是否合法的小程序
    一个操作系统的实现:关于ALIGN的若干解释
    一个郁闷的C语言小问题
    test
    浮点数的比较
    一个操作系统的实现:Descriptor 3详解
    一个操作系统的实现:关于CPL、RPL、DPL
    C99可变长数组VLA详解
    SVProgressHUD 用法
    IOS CALayer 详解
  • 原文地址:https://www.cnblogs.com/syy1757528181/p/13655823.html
Copyright © 2011-2022 走看看