Blog:博客园 个人

参考:《深入理解Zabbix监控系统》、《Zabbix用户手册》

Zabbix服务端进程被分为不同的种类,每一种进程负责相应的任务,包括收集原始监控数据、对原始监控数据进行预处理、将预处理后的监控数据同步到数据库、对监控数据进行计算以生成事件、计算和获取内部监控数据,以及对数据库中的数据进行清理等。

监控数据的收集进程

Zabbix服务器的重要任务之一就是被动接收由Zabbix代理和各种Zabbix客户端发送的监控数据,以及主动向Zabbix代理、Zabbix java gateway和Zabbix客户端等数据源请求数据,其中被动接收数据由trapper类进程实现,主动请求数据则由poller类进程实现。

trapper类进程通过监听TCP套接字来捕获符合通信协议的原始监控数据,poller类进程则使用ConfigCache作为输入,根据缓存信息实现完善的任务调度。trapper类和poller类进程的下游是预处理进程,这两类进程需要将收集到的原始监控数据发送到预处理进程。trapper类进程和poller类进程都会在进程内部维护一个静态变量cached_message,用于暂存待发送的监控数据,并在各种必要的时机将该变量中的消息发送到预处理进程。

trapper类进程

Zabbix服务器端的trapper进程负责接收来自Zabbix客户端、Zabbix代理、zabbix_sender及其他外部进程发来的请求并进行处理,按照Zabbix 5.0的通信协议规范,trapper进程只能接收JSON格式字符串的请求。

trapper进程由配置文件中的StartTrappers参数决定其启动数量(允许启动0~1000个进程,默认为5个)。

[root@prod-zabbix-server ~]# ps -ef|grep trapper
zabbix 8740 8643 0 Feb21 ? 01:55:26 /usr/sbin/zabbix_server: trapper #1 [processed data in 0.001288 sec, waiting for connection]
zabbix 8741 8643 0 Feb21 ? 01:13:24 /usr/sbin/zabbix_server: trapper #2 [processed data in 0.000863 sec, waiting for connection]
zabbix 8742 8643 0 Feb21 ? 01:02:48 /usr/sbin/zabbix_server: trapper #3 [processed data in 0.000664 sec, waiting for connection]
zabbix 8743 8643 0 Feb21 ? 01:55:36 /usr/sbin/zabbix_server: trapper #4 [processed data in 0.000788 sec, waiting for connection]
zabbix 8744 8643 0 Feb21 ? 01:43:59 /usr/sbin/zabbix_server: trapper #5 [processed data in 0.000802 sec, waiting for connection]

注意:至少要运行一个trapper进程用于在web前端展示服务器可用性和队列视图。

总体而言,trapper进程所做的事情就是循环从TCP 套接字读取请求消息,然后根据消息类型调用不同的函数进行处理,处理完毕后关闭该套接字连接。即每个循环处理一个请求,每个请求的处理都是在新的连接中进行通信的。

数据处理:

  • 处理agent data和sender data请求:两者处理过程类似,唯一区别是验证过程,agent data要求监控项属于主动客户端(active agent)类型,而发送者数据(sender data)要求监控项属于Zabbix trapper类型。请求的过程中,trapper进程的作用在于验证数据的有效性,包括监控项状态、监控项类型和主机状态等。
  • 处理proxy config请求:将Zabbix服务器的配置信息传输到Zabbix代理。可以由Zabbix代理发送到Zabbix服务器(主动模式,默认),也可以由Zabbix服务器发送到Zabbix代理(被动模式)。
  • 处理proxy data请求:可能由Zabbix服务器或者被动模式下的Zabbix代理来处理。如果是Zabbix服务器,说明它接收了一批来自Zabbix代理的监控值,此时需要将数据写入缓存或者进行LLD(Low-level discovery,自动发现)处理;如果是被动代理,说明它接收了Zabbix服务器发送的数据请求,此时需要做的是将监控数据回复给Zabbix服务器。从Zabbix 5.0开始,Zabbix代理具有了预处理的能力,所以proxy data中的监控值其实是已经预处理过的,不需要在Zabbix服务器端再次预处理。
snmp trapper进程

snmp trapper进程由配置参数StartSNMPTrapper决定其启动数量(允许0或1个进程),默认为0。该进程的工作方式是循环调用get_latest_data()和read_traps()函数,从trap文件(文件路径由SNMPTrapperFile配置参数决定)中读取数据,然后调用parse_traps()函数进行解析处理。

poller类进程

poller类进程是指以主动方式获取原始监控数据的进程,包括poller进程、unreachable poller进程、ipmi manager/poller进程、icmp pinger进程、javapoller进程、proxy poller进程和http poller进程,一共有7种,它们各自负责采集不同类型的监控项数据。与trapper类进程不同的是,poller类进程需要自己执行监控数据采集逻辑,每一种监控项都需要调用不同的函数进行处理才能得到监控数据,而trapper类进程可以直接接收监控数据。从这个角度来说,对于同样数量的监控任务,使用poller工作方式要比使用trapper工作方式的负载更高

工作机制

poller类进程首先需要解决的问题是如何调度数据采集过程,以保证大量数据采集任务的执行顺序和间隔是正确且准确的。此外,每一种进程都并非唯一的,所以还要保证多进程之间的协调,避免冲突。Zabbix的解决方案是通过ConfigCache中定义的6个二叉堆结构来确定数据采集任务的执行顺序和间隔。

多进程之间的冲突问题,解决方法是使用ConfigCache互斥锁,即在访问二叉堆之前加锁,在访问结束以后解锁,从而保证同一时间只有一个进程在访问。

poller进程

poller进程能够处理除IPMI类型之外的所有监控项的数据采集,包括Zabbix客户端(Zabbix agent)监控项、简单检查(Simple check)监控项、SNMP客户端(SNMP agent)监控项、Zabbix内部(Zabbix internal)监控项、Zabbix聚合(Zabbix aggregate)监控项、外部检查(External check)监控项、数据库监视(Database monitor)监控项、HTTP客户端(HTTP agent)监控项、SSH客户端(SSH agent)监控项、TELNET客户端(TELNET agent)监控项、JMX客户端(JMX agent)监控项以及计算型(Calculated)监控项,共12种。

Zabbix客户端监控项处理

poller进程对Zabbix客户端(Zabbix agent)监控项进行处理的过程实际上就是以TCP套接字客户端的身份与作为服务器端的Zabbix客户端进行通信的过程。因此,当poller进程需要处理大量Zabbix客户端监控项时,会同时与很多Zabbix客户端建立TCP连接。(同一时刻每个进程最多建立一个连接,用后即关闭。)

unreachable poller进程

在网络通信良好并且各方服务正常的情况下,poller进程所处理的Zabbix客户端和SNMP客户端监控项,以及IPMI进程处理的IPMI客户端(IPMIagent)监控项和java poller进程处理的JMX监控项,都能够成功执行并获取监控数据。但是,当出现agent服务故障时,如果继续由原来的poller类进程处理对应的监控项,大量的连接超时就有可能引起整体服务水平下降。unreachable poller进程就是对该问题的解决方案,当客户端(包括Zabbix客户端、SNMP客户端、IPMI客户端和JMX客户端)服务不可用时,对应的监控项会转移到unreachable poller队列中处理。当unreachable poller进程发现某个客户端已经恢复正常时,则将对应的监控项再转移回原始队列中。

一般情况下,由于大部分客户端状态是良好的,因此unreachable poller进程的负载并不高。但是,一旦发生大面积网络故障,会有大量监控项转移到unreachablepoller进程的任务队列中,此时进程的负载会飙升。如果要降低负载,可以考虑增加UnavailableDelay参数值,或者增加unreachable poller进程的启动数量。

总结

Zabbix支持两种收集监控数据的模式,在Zabbix服务器端表现为同时存在trapper类进程和poller类进程。

trapper类进程用于被动接收来自Zabbix客户端或者Zabbix代理的监控数据;poller类进程用于主动发起连接并向被监控对象请求监控数据。trapper类进程包括纯trapper进程和snmp trapper进程,前者用于从Zabbix客户端和Zabbix代理接收监控数据,后者用于从snmp trap文件读取监控数据。当采用拉的工作模式时,由于每种监控项的具体拉取方式存在较大区别,因此poller类进程进一步划分为多种进程,包括纯poller进程、unreachable poller进程、ipmi manager与ipmi poller进程、icmp pinger进程、java poller进程、proxy poller进程和http poller进程。每一种poller进程负责拉取相应类型的监控数据。

预处理进程

预处理(preprocessing)进程是从Zabbix 3.4开始新增的一种进程类型,它用于对原始的监控数据进行各种形式的变换和计算,并通过共享内存,将输出结果传递到history syncer进程进行处理。在Zabbix的早期版本中,预处理进程只能运行在Zabbix服务器端,当数据量大时会给Zabbix服务器端造成较大的压力。因此从Zabbix 4.2版本开始,预处理进程可以同时运行在Zabbix服务器端和Zabbix代理端。在这种情况下,由Zabbix代理负责采集的监控数据在传输到Zabbix服务器端之前就已经完成了预处理,直接从Zabbix客户端传输到Zabbix服务器端的数据则需要由Zabbix服务器端完成预处理。

[root@prod-zabbix-server ~]# ps -ef|grep preprocessing
zabbix 8652 8643 0 Feb21 ? 00:47:49 /usr/sbin/zabbix_server: preprocessing manager #1 [queued 0, processed 716 values, idle 5.029540 sec during 5.035809 sec]
zabbix 8653 8643 0 Feb21 ? 00:13:20 /usr/sbin/zabbix_server: preprocessing worker #1 started
zabbix 8654 8643 0 Feb21 ? 00:04:00 /usr/sbin/zabbix_server: preprocessing worker #2 started
zabbix 8655 8643 0 Feb21 ? 00:03:44 /usr/sbin/zabbix_server: preprocessing worker #3 started
zabbix 8656 8643 0 Feb21 ? 00:03:35 /usr/sbin/zabbix_server: preprocessing worker #4 started
zabbix 8657 8643 0 Feb21 ? 00:03:29 /usr/sbin/zabbix_server: preprocessing worker #5 started
zabbix 8658 8643 0 Feb21 ? 00:03:23 /usr/sbin/zabbix_server: preprocessing worker #6 started
zabbix 8659 8643 0 Feb21 ? 00:03:25 /usr/sbin/zabbix_server: preprocessing worker #7 started
zabbix 8660 8643 0 Feb21 ? 00:02:28 /usr/sbin/zabbix_server: preprocessing worker #8 started
zabbix 8661 8643 0 Feb21 ? 00:02:17 /usr/sbin/zabbix_server: preprocessing worker #9 started
zabbix 8662 8643 0 Feb21 ? 00:02:18 /usr/sbin/zabbix_server: preprocessing worker #10 started

以上命令结果可知,preprocessing进程由1个preprocessing manager(管理者进程)和多个preprocessing worker(工作者进程)进程组成。

processing manager进程负责监听预处理所使用的Unix域套接字并处理由poller / trapper进程和preprocessing worker进程发送过来的消息。还会向lld manager进程发送消息,因为原始监控数据中同时包含LLD规则监控项数据,这些数据在预处理完毕以后还需要进行LLD处理(由lld manager和lld worker进程完成)

预处理工作者(preprocessing worker)进程的数量由配置参数StartPreprocessors决定,允许1~1 000个进程。工作者进程负责读取管理者进程发送的进程间通信服务消息,并执行所获得的任务。

LLD进程

LLD进程是从Zabbix 5.0开始出现的专门负责LLD规则(LLD rule)监控数据处理的进程,由于底层发现(Low Level Discovery,LLD)得到越来越多的应用,因此这类数据的处理压力随之增加,将这些工作交给单独的进程来处理将有利于性能的提升和将来的进一步扩展。

LLD进程包括lld manager进程和lld worker进程两种,其中管理者进程是唯一的,工作者进程可以启动多个。LLD进程只能运行在Zabbix服务器端,它们位于预处理进程的下游,接收预处理进程发送的消息作为输入,而输出则是对各项监控配置的更新操作。本质上,LLD就是通过解析LLD规则监控项(一种特殊类型的监控项,其配置信息存储在items表中,其监控值不用于存储,只用于更新监控配置)返回的特殊格式的字符串,创建、更新或者删除监控项、触发器、图表或主机,使之与返回结果保持一致。由于LLD规则监控值会按照设定的频率进行更新,因此Zabbix可以随着数据的更新而动态调整监控对象、监控指标和监控参数等。从Zabbix 4.2开始,LLD规则的监控值跟普通监控项一样可以进行预处理,在预处理结束以后,LLD进程再对数据进行解析并更新配置信息,这一方式赋予用户更多对LLD规则数据进行处理的能力,从而增强了底层发现的功能。

[root@prod-zabbix-server ~]# ps -ef|grep lld
zabbix 8663 8643 0 Feb21 ? 00:01:33 /usr/sbin/zabbix_server: lld manager #1 [processed 15 LLD rules, idle 5.385801sec during 5.385996 sec]
zabbix 8664 8643 0 Feb21 ? 00:29:15 /usr/sbin/zabbix_server: lld worker #1 [processed 14 LLD rules, idle 6.001249 sec during 6.150509 sec]
zabbix 8665 8643 0 Feb21 ? 00:29:28 /usr/sbin/zabbix_server: lld worker #2 [processed 15 LLD rules, idle 8.471019 sec during 8.725697 sec]

lld manager进程虽然只有一个,但是其需要完成的任务有多种,包括注册lldworker进程、接收其他进程发送的消息、给lld worker进程分配任务、处理lldworker进程返回的结果以及响应队列长度请求等。

lld worker进程负责处理lld manager进程分配的任务,即接收并处理通过进程间通信服务发送过来的code 1100消息。总体的处理过程包括解析消息,验证LLD规则有效性(通过ConfigCache),加载filter、LLD macros和overrides,解析LLD消息的JSON数组,进行配置信息更新,以及根据LLD规则监控项状态生成内部事件。lld worker进程的工作机制是被动模式,即发出注册消息以后,并不会主动向管理者进程请求任务,而是等待管理者进程分配任务。

预处理进程和LLD进程处于poller类进程和trapper类进程的下游,负责处理poller类进程和trapper类进程获取的原始监控数据。预处理进程按照用户设置的处理规则对数据进行变换和计算,处理之后的数据传递给history syncer进程处理。预处理进程通过进程间通信服务方式与上游进程通信。处理之后的数据写入共享内存,供下游进程使用

history syncer进程

history syncer进程是Zabbix服务器端最为核心的进程,它负责将监控数据(包括趋势数据)写入数据库和写入缓存、生成并处理事件,以及处理动作(action)并生成升级序列(escalation)等。如果没有history syncer进程,Zabbix服务器将什么也做不了:既不能处理监控数据,又不能生成事件,也不能进行告警。history syncer进程位于预处理进程的下游,它将预处理进程写入HistoryCache和HistoryIndexCache的数据作为输入。

history syncer进程的启动数量由配置文件中的StartDBSyncers参数控制,允许1~100个进程。history syncer进程的作用是将HistoryCache和HistoryIndexCache中的监控值写入数据库中的history表和trends表,同时根据监控值计算触发器表达式,决定是否触发事件。该进程在Zabbix服务器端和Zabbix代理端都存在,但是有所不同,这一点体现在代码清单9-1所示的进程标题中。在Zabbix服务器端时,该进程既需要处理监控值(values),也需要处理触发器(triggers),在Zabbix代理端时,该进程只需要处理监控值,而不需要处理触发器,因为触发器表达式统一由Zabbix服务器端处理。本章讲述Zabbix服务器端的处理过程。

[root@prod-zabbix-server ~]# ps -ef|grep history
zabbix 8720 8643 0 Feb21 ? 00:30:13 /usr/sbin/zabbix_server: history syncer #1 [processed 10 values, 8 triggers in 0.004174 sec, idle 1 sec]
zabbix 8721 8643 0 Feb21 ? 00:30:28 /usr/sbin/zabbix_server: history syncer #2 [processed 12 values, 5 triggers in 0.004013 sec, idle 1 sec]
zabbix 8722 8643 0 Feb21 ? 00:30:38 /usr/sbin/zabbix_server: history syncer #3 [processed 24 values, 7 triggers in 0.006277 sec, idle 1 sec]
zabbix 8723 8643 0 Feb21 ? 00:30:21 /usr/sbin/zabbix_server: history syncer #4 [processed 4 values, 3 triggers in 0.004239 sec, idle 1 sec]
zabbix 8724 8643 0 Feb21 ? 00:30:30 /usr/sbin/zabbix_server: history syncer #5 [processed 236 values, 146 triggers in 0.058686 sec, idle 1 sec]
zabbix 8725 8643 0 Feb21 ? 00:30:18 /usr/sbin/zabbix_server: history syncer #6 [processed 0 values, 0 triggers in 0.000022 sec, idle 1 sec]

处理动作相关进程

escalator进程用于处理事件触发的整个动作序列,该进程读取escalations表中的数据并进行处理,并将生成的警报消息插入alerts表中,供alerter进程使用。所以,escalator进程并不实际发送警报消息,而只生成警报。

[root@prod-zabbix-server ~]# ps -ef|grep escalator
zabbix 8726 8643 0 Feb21 ? 00:00:32 /usr/sbin/zabbix_server: escalator #1 [processed 0 escalations in 0.001072 sec, idle 3 sec]

alerter进程族用于实际发送警报,该进程族包括alert syncer进程、alert manger进程和alerter进程。alert syncer进程负责将数据库中的警报信息和媒体类型信息同步到alert manager进程,具体方法是从数据库读取数据,然后构造为进程间通信服务消息并发送到alert manager进程。alert manager进程负责向alerter进程分发警报处理任务,并接收alerter进程反馈的结果。alerter进程负责按照alertmanager分配的任务处理警报并反馈结果。task manager进程运行在Zabbix服务器端和Zabbix代理端,它负责处理存储在数据库task表中的远程命令(remote command)、立即检查(check now)、问题确认(problem acknowledge)和问题关闭(problem close)等任务。

[root@prod-zabbix-server ~]# ps -ef|grep alert
zabbix 8645 8643 0 Feb21 ? 00:00:44 /usr/sbin/zabbix_server: alert manager #1 [sent 0, failed 0 alerts, idle 5.006731 sec during 5.006787 sec]
zabbix 8646 8643 0 Feb21 ? 00:00:00 /usr/sbin/zabbix_server: alerter #1 [sent 0, failed 0 alerts, idle 657.095715 sec during 657.405902 sec]
zabbix 8647 8643 0 Feb21 ? 00:00:00 /usr/sbin/zabbix_server: alerter #2 [sent 0, failed 0 alerts, idle 656.705429 sec during 657.122473 sec]
zabbix 8648 8643 0 Feb21 ? 00:00:00 /usr/sbin/zabbix_server: alerter #3 [sent 0, failed 0 alerts, idle 656.675887 sec during 657.107786 sec]
zabbix 8649 8643 0 Feb21 ? 00:00:00 /usr/sbin/zabbix_server: alerter #4 [sent 0, failed 0 alerts, idle 656.699989 sec during 657.124047 sec]
zabbix 8650 8643 0 Feb21 ? 00:00:00 /usr/sbin/zabbix_server: alerter #5 [sent 0, failed 0 alerts, idle 656.677134 sec during 657.137743 sec]
zabbix 8651 8643 0 Feb21 ? 00:00:00 /usr/sbin/zabbix_server: alerter #6 [sent 0, failed 0 alerts, idle 658.772114 sec during 659.591568 sec]
zabbix 8746 8643 0 Feb21 ? 00:01:29 /usr/sbin/zabbix_server: alert syncer [queued 0 alerts(s), flushed 0 result(s) in 0.001063 sec, idle 1 sec]

优化建议

以4C8G配置、能够处理监控项5万个为例,相关进程优化项如下(仅供参考):

配置 默认值 推荐值
StartDBSyncers 4 8,不宜太高,默认值已能处理4000 NVPS
StartAlerters 3 6
StartDiscoverers 1 3
StartPollers 5 12
StartPreprocessors 3 6
StartProxyPollers 1 3
StartTrappers 5 12
StartLLDProcessors 2 3
StartEscalators 1 1

Zabbix 5.0:服务端进程总结的更多相关文章

  1. centos 7 上zabbix 3.0 服务端安装

    zabbix服务端安装 安装完毕mysql-5.6.php5.6 mysql-5.6安装:https://www.cnblogs.com/xzlive/p/9771642.html  创建zabbix ...

  2. linux centos安装zabbix 4.0服务端

    1.服务器安装docker sudo yum install -y yum-utils device-mapper-persistent-data lvm2 sudo yum-config-manag ...

  3. Android native进程间通信实例-socket本地通信篇之——服务端进程异常退出解决办法

    导读: 好难受啊,为什么服务端说挂就挂,明明只是客户端关闭而已,服务端怎么能挂呢? 想想,如果手机上使用一个聊天程序的时候,手机端关闭了聊天程序,那么远端服务器程序总不能说挂就挂吧!所以一定要查明真相 ...

  4. Zabbix5.0服务端部署

    Zabbix5.0服务端部署 基础环境配置 [root@localhost ~]# systemctl disable --now firewalld Removed symlink /etc/sys ...

  5. Swift3.0服务端开发(一) 完整示例概述及Perfect环境搭建与配置(服务端+iOS端)

    本篇博客算是一个开头,接下来会持续更新使用Swift3.0开发服务端相关的博客.当然,我们使用目前使用Swift开发服务端较为成熟的框架Perfect来实现.Perfect框架是加拿大一个创业团队开发 ...

  6. Swift3.0服务端开发(五) 记事本的开发(iOS端+服务端)

    前边以及陆陆续续的介绍了使用Swift3.0开发的服务端应用程序的Perfect框架.本篇博客就做一个阶段性的总结,做一个完整的实例,其实这个实例在<Swift3.0服务端开发(一)>这篇 ...

  7. 创建自己的OAuth2.0服务端(一)

    如果对OAuth2.0有任何的疑问,请先熟悉OAuth2.0基础的文章:http://www.cnblogs.com/alunchen/p/6956016.html 1. 前言 本篇文章时对 客户端的 ...

  8. oauth2.0服务端与客户端搭建

    oauth2.0服务端与客户端搭建 - 推酷 今天搭建了oauth2.0服务端与客户端.把搭建的过程记录一下.具体实现的功能是:client.ruanwenwu.cn的用户能够通过 server.ru ...

  9. Swift3.0服务端开发(二) 静态文件添加、路由配置以及表单提交

    今天博客中就来聊一下Perfect框架的静态文件的添加与访问,路由的配置以及表单的提交.虽然官网上有聊静态文件的访问的部分,但是在使用Perfect框架来访问静态文件时还是有些点需要注意的,这些关键点 ...

随机推荐

  1. 【机器学习】VAE

    机器学习算法-VAE 目录 机器学习算法-VAE 1. VAE模型推导 1.1 算法引入 1.2 模型推导 1.3 损失函数 1.4 重参数技巧 2. 实现 2.1 模型定义 2.2 实验 1. VA ...

  2. 611. Valid Triangle Number

    Given an array consists of non-negative integers, your task is to count the number of triplets chose ...

  3. SSM项目使用拦截器实现登录验证功能

    SSM项目使用拦截器实现登录验证功能 登录接口实现 public User queryUser(String UserName, String Password,HttpServletRequest ...

  4. [WAF攻防]从WAF攻防角度重看sql注入

    从WAF攻防角度重看sql注入 攻防都是在对抗中逐步提升的,所以如果想攻,且攻得明白,就必须对防有深刻的了解 sql注入的大体流程 Fuzz测试找到注入点 对注入点进行过滤检测,及WAF绕过 构建pa ...

  5. kubernetes集群各模块功能描述

    Master节点: Master节点上面主要由四个模块组成,APIServer,schedule,controller-manager,etcd APIServer: APIServer负责对外提供R ...

  6. netstat in Linux

    # netstat -unlt Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address         ...

  7. 使用ajax登录验证,第一次点击登录按钮无反应,第二次点击才能正常运行。

    问题描述: 使用ajax进行登录验证时,第一次点击登录按钮无反应,第二次点击才能进去. 解决方法: 原来的代码 <form action="" method="po ...

  8. Linux 配置 mycat 和 分库分表配置。

    Linux 如何配置mycat? 3.配置mycat 3.1.规定linux的用户名和全名不能叫mycat!!!否则mycat会不生效(原因是影响整个linux系统的环境变量导致mycat的配置环境变 ...

  9. MySQL 事务的隔离级别及锁操作的一点点演示

    MySQL 版本:5.7 安装环境:MAC OS 一.测试数据 测试数据库:test:测试表:tt CREATE TABLE `tt` ( `id` int(11) DEFAULT NULL, `na ...

  10. 「ZJOI2014」璀灿光华

    「ZJOI2014」璀灿光华 实际上,可以不用建水晶立方体... 因为,发光水晶的方向都要枚举一遍. 只需知道发光水晶每个方向有哪些水晶就可以了. 对于一个发光水晶,将它连接的水晶标号. 从该水晶bf ...