项目场景

  • 为了熟悉使用docker,最近学习zabbix时,用docker来搭建lnmp(Linxu + Nginx + MySQL + PHP)环境,而zabbix直接安装在物理机上,由于第一次搭建zabbix的环境,不熟悉,各种bug出现,下面是我遇到的一个挺有意思的bug,在这里聊一下
  • Linux:centos7.9
  • zabbix:5.0
  • MySQL:8.0,默认使用 TCP/IP 进行通信而不是套接字文件 (mysql.sock)

一、问题描述

zabbix报错 
28375:20240308:204318.827 [Z3001] connection to database 'zabbix' 
failed: [2002] Can't connect to local MySQL server through socket '/tmp/mysql.sock' (13)

二、原因分析

  1. MySQL问题:MySQL未正常启动或是MySQL8.0默认TCP/IP通信而不是socket文件
  2. zabbix配置错误

三、解决方案

  • 读者点进来肯定是为了怎么解决这个问题,我就先给出解决方法
  • 我们先看这个错误,说zabbix不能通过 mysql.sock 这个文件来与mysql进行通信,我分情况讨论

注:下面讨论的前提是lnmp环境是正确搭建的,至少MySQL要是正常运行的,比如你可以登录进入MySQL,并进行增删改查

1、zabbix 与 lnmp都安装在linux物理机上

我们先来到 /etc/zabbix/zabbix_server.conf,zabbix服务端的配置文件,我们找到下面配置,我们只需将DBSocket的注释删除就行。

### Option: DBSocket
#       Path to MySQL socket.
#
# Mandatory: no
# Default:
#DBSocket=/tmp/mysql.sock 
DBSocket=/tmp/mysql.sock

# 然后
systemctl restart zabbix-server

如果还是报相同的错,也有可能是MySQL8.0的问题,因为 MySQL8.0中默认使用 TCP/IP 进行通信而不是套接字文件 (mysql.sock),就是使用IP地址加上端口来连接。
这里有两种解决方法

  1. 修改MySQL8.0的配置

打开 MySQL 配置文件 my.cnf(在 Linux 上通常位于 /etc/mysql/my.cnf 或 /etc/my.cnf),然后修改如下配置。

[mysqld]
# 设置套接字文件路径
socket=/tmp/mysql.sock

systemctl restart mysql
  1. 修改zabbix的配置

因为zabbix的也可以配置以TCP/IP的方式来访问MySQL,我们再找到zabbix-server的配置文件,/etc/zabbix/zabbix_server.conf,找到以下配置,其实你看配置的英文介绍也就明白了,DBHost=localhost 时,zabbix就用socket去连接MySQL,那么我就做出下面的修改

### Option: DBHost
#       Database host name.
#       If set to localhost, socket is used for MySQL.
#       If set to empty string, socket is used for PostgreSQL.
#
# Mandatory: no
# Default:
# DBHost=localhost 
DBHost=127.0.0.1 # 将localhost改为127.0.0.1
# 虽然都指向本地,但这样可以让zabbix用tcp/ip的方式连接数据库,以端口的方式
# 注意注释或删除该项可能会让zabbix不能启动

2、zabbix与 lnmp 不安装在同一环境下,特别是MySQL是安装在其他机器上或者运行在docker容器中

在这种情况下,多半是用TCP/IP的方式来连接,这样就用上面的 第二种方法–修改zabbix的配置 将DBHost用IP的方式来表示

四、多提一嘴,我们来扩展一下,本机socket通信与TCP/IP通信的关系

Unix/Linux基本哲学之一就是 一切皆文件,都可以用 打开open -》 读写write/read -》 关闭close 来操作。socket就是基于该模式实现,socket就是一种特殊的文件。

在现在的Linux中,进程间通信(IPC)可以使用套接字(Socket)和 TCP/IP 网络连接两种方式实现。

  • IPC 套接字

使用套接字进行进程间通信更加轻量级和高效,因为数据在内存中直接传送,无需经过网络协议栈的处理。套接字通信适用于本地机器上的进程间通信,通常用于相同主机上的进程之间进行通信。比如这次的zabbix无法通过mysql.sock连接MySQL而导致报错,就说明进程zabbix是可以用IPC 套接字与另外一个进程MySQL通信。

  • TCP/IP套接字

使用 TCP/IP 套接字进行通信可在多台计算机之间进行数据传输,通信基于 TCP/IP 协议栈来实现,适用于网络环境中的进程间通信。

注:套接字是一种抽象概念,它提供了一种接口,使进程能够通过网络或本地进行通信。
因此,常见的就有IPC 套接字TCP/IP 套接字,它们的底层实现是不一样的。这里我们讨论的是本机进程的通信,因此这里的套接字是 IPC 套接字,即本机进程的套接字。这种套接字的底层实现是基于以下机制。

  1. IPC(Interprocess Communication)机制:本机套接字通信通常是基于 IPC 机制实现的,通过操作系统提供的进程间通信机制来实现不同进程之间的通信。
  2. 内存传输:本机套接字通信的数据传输是在本地内存中进行的,数据直接从一个进程的内存传递到另一个进程的内存,无需经过网络传输。这使得本机套接字通信更加高效。
  3. 本地套接字文件或抽象命名空间:在本机套接字通信中,通常使用文件系统中的文件路径或抽象命名空间来标识和连接套接字,用来确保进程之间的通信。

而平常我们见的最多的套接字其实是TCP/IP套接字,这种套接字的底层实现是用TCP/IP,比如创建一个socket对象,绑定并监听某个IP及port,或者说是将TCP/IP给你封装好方便你使用。底层就是常见的什么三次握手四次挥手。

五、结语

如有读者有什么疑问或者本文有什么错误,欢迎到评论区留言。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐