2024年10月

近日,Gartner发布了24年《中国数据分析及人工智能成熟度周期报告》,在成熟度曲线中声明“数据中台”已被淘汰。数据中台,这个曾被奉若圭臬,视为先进架构的标志性建筑,将就此将淡出历史舞台。

有些东西,在它真正消亡前,就已经被遗忘。

其实,早在几年前,国内技术圈已经不再热衷于数据中台概念,一位IT媒体编辑曾和我说,他们根本不考虑做数据中台主题,因为太多厂商借助这个概念贩卖各种各样的产品,根本无法聚焦。

数据中台概念的过度泛化,导致使用该词汇时,沟通成本极大,要花不少时间理解对方想表达的真正意图是什么。

数据中台,常见的一种用法是指代
全套数据平台解决方案
,当然这个方案涉及的工具也是可以拆开单独售卖的。这个语境下的数据中台,就像麦当劳的全家桶,本质上不是新产品,而只是对原有产品重新打包的一种营销方式。

另外一种用法,我称之为
医美版的数据仓库
,就像上了年纪的女人通过医美找回青春一样,冠以数据中台这个时尚的名称后,立即消除了数据仓库的老气,但本质上两者并没有太大的差别。对于已经拥有数据仓库的用户,厂商还要细化两者的界限,以便获得新订单。而对于未建设数据仓库的用户,数据中台总是乐于满足客户对数据平台的各种想象。

这个概念是如此多变和充满弹性,像极了一个油腻、市侩的中年人,为达目的可以用尽各种花招。以至于,数据中台的消亡,让我甚至感到数据技术的世界中多了几分清爽。

当然,那些曾经投射到数据中台上的理想,仍希望能够延续和发扬。真正有价值的事情是,
基于强大的企业级能力复用,
提供更加灵活、更加敏捷、更低成本的数据交付能力,比数据仓库更加重视联机数据交付,突破分析报表等传统使用模式,让数据模块化,嵌入业务场景

期待下一个概念,是个眉目清秀的孩子,有边界感。

有时需要将MySQL数据库中的数据导出到外部存储文件中,MySQL数据库中的数据可以导出成sql文本文件、xml文件或者html文件。本节将介绍数据导出的常用方法。

11.4.1  使用SELECT…INTO OUTFILE导出文本文件

MySQL数据库导出数据时,允许使用包含导出定义的SELECT语句进行数据的导出操作。该文件被创建到服务器主机上,因此必须拥有文件写入权限(FILE权限)才能使用此语法。“SELECT...INTO OUTFILE 'filename'”形式的SELECT语句可以把被选择的行写入一个文件中,并且filename不能是一个已经存在的文件。SELECT...INTO OUTFILE语句的基本格式如下:

SELECT columnlist  FROM table WHERE condition  INTO OUTFILE 'filename'  [OPTIONS]

可以看到SELECT columnlist FROM table WHERE condition为一个查询语句,查询结果返回满足指定条件的一条或多条记录;INTO OUTFILE语句的作用就是把前面SELECT语句查询出来的结果,导出到名称为“filename”的外部文件中;[OPTIONS]为可选参数选项,OPTIONS部分的语法包括FIELDS和LINES子句,其可能的取值如下:

—  FIELDS TERMINATED BY 'value':设置字段之间的分隔字符,可以为单个或多个字符,默认情况下为制表符(\t)。

—  FIELDS [OPTIONALLY] ENCLOSED BY 'value':设置字段的包围字符,只能为单个字符,若使用了OPTIONALLY关键字,则只有CHAR和VERCHAR等字符数据字段被包围。

—  FIELDS ESCAPED BY 'value':设置如何写入或读取特殊字符,只能为单个字符,即设置转义字符,默认值为“\”。

—  LINES STARTING BY 'value':设置每行数据开头的字符,可以为单个或多个字符,默认情况下不使用任何字符。

—  LINES TERMINATED BY 'value':设置每行数据结尾的字符,可以为单个或多个字符,默认值为“\n”。

FIELDS和LINES两个子句都是自选的,但是如果两个都被指定了,则FIELDS必须位于LINES的前面。

使用SELECT...INTO OUTFILE语句,可以非常快速地把一张表转储到服务器上。如果想要在服务器主机之外的部分客户主机上创建结果文件,不能使用SELECT...INTO OUTFILE,应该使用“MySQL –e "SELECT ..." > file_name”这类的命令来生成文件。

SELECT...INTO OUTFILE是LOAD DATA INFILE的补语,用于语句的OPTIONS部分的语法包括部分FIELDS和LINES子句,这些子句与LOAD DATA INFILE语句同时使用。

【例11.10】使用SELECT...INTO OUTFILE将test_db数据库中的person表中的记录导出到文本文件,SQL语句如下:

mysql> SELECT *  FROM test_db.person INTO OUTFILE 'D:/person0.txt';

语句执行后报错信息如下:

ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement

这是因为MySQL默认对导出的目录有权限限制,也就是说使用命令行进行导出的时候,需要指定目录。那么指定的目录是什么呢?

查询指定目录的命令如下:

show global variables like '%secure%';

执行结果如下:

+-------------------------+-----------------------------------------------+

| Variable_name             | Value                                                  |

+-------------------------+-----------------------------------------------+

|require_secure_transport | OFF                                                    |

|secure_file_priv           | D:\ProgramData\MySQL\MySQL Server 9.0\Uploads\|

+-------------------------+-----------------------------------------------+

因为secure_file_priv配置的关系,所以必须导出到D:\ProgramData\MySQL\MySQL Server 9.0\Uploads\目录下,该目录就是指定目录。如果想自定义导出路径,需要修改my.ini配置文件。打开路径D:\ProgramData\MySQL\MySQL Server 9.0,用记事本打开my.ini文件,然后搜索以下代码:

secure-file-priv="D:/ProgramData/MySQL/MySQL Server 9.0/Uploads"

在上述代码前添加#注释掉,然后添加以下内容:

secure-file-priv="D:/"

结果如图11.1所示。

图11.1  设置数据表的导出路径

重启MySQL服务器后,再次使用SELECT...INTO OUTFILE将test_db数据库中的person表中的记录导出到文本文件,SQL语句如下:

mysql>SELECT *  FROM test_db.person INTO OUTFILE 'D:/person0.txt';

Query OK,
1 row affected (0.01 sec)

由于指定了INTO OUTFILE子句,因此SELECT会将查询出来的3个字段值保存到C:\person0.txt文件中。打开该文件,内容如下:

1   Green       21Lawyer2   Suse         22dancer3   Mary         24Musician4   Willam      20sports man5   Laura       25\N6   Evans       27secretary7   Dale          22cook8   Edison      28singer9   Harry       21magician10  Harriet     19  pianist

默认情况下,MySQL使用制表符(\t)分隔不同的字段,字段没有被其他字符包围。另外,第5行中有一个字段值为“\N”,表示该字段的值为NULL。默认情况下,当遇到NULL时,会返回“\N”,代表空值,其中的反斜线(\)表示转义字符;如果使用ESCAPED BY选项,则N前面为指定的转义字符。

【例11.11】使用SELECT...INTO OUTFILE语句,将test_db数据库person表中的记录导出到文本文件,使用FIELDS选项和LINES选项,要求字段之间使用逗号分隔,所有字段值用双引号引起来,定义转义字符为单引号“\'”,SQL语句如下:

SELECT * FROM  test_db.person INTO OUTFILE "D:/person1.txt"FIELDS

TERMINATED BY
','ENCLOSED BY'\"'ESCAPED BY'\''LINES

TERMINATED BY
'\r\n';

该语句将把person表中所有记录导入D盘目录下的person1.txt文本文件中。

“FIELDS TERMINATED BY ','”表示字段之间用逗号分隔;“ENCLOSED BY '\"'”表示每个字段用双引号引起来;“ESCAPED BY '\'”表示将系统默认的转义字符替换为单引号;“LINES TERMINATED BY '\r\n'”表示每行以回车换行符结尾,保证每一条记录占一行。

执行成功后,在D盘下生成一个person1.txt文件。打开文件,内容如下:

"1","Green","21","Lawyer"

"2","Suse","22","dancer"

"3","Mary","24","Musician"

"4","Willam","20","sports man"

"5","Laura","25",'N'

"6","Evans","27","secretary"

"7","Dale","22","cook"

"8","Edison","28","singer"

"9","Harry","21","magician"

"10","Harriet","19","pianist"

可以看到,所有的字段值都被双引号引起来;第5条记录中空值的表示形式为“N”,即使用单引号替换了反斜线转义字符。

【例11.12】使用SELECT...INTO OUTFILE语句,将test_db数据库person表中的记录导出到文本文件,使用LINES选项,要求每行记录以字符串“>”开始、以字符串“<end>”结尾,SQL语句如下:

SELECT * FROM  test_db.person INTO OUTFILE "D:/person2.txt"LINES

STARTING BY
'>'TERMINATED BY'<end>';

语句执行成功后,在D盘下生成一个person2.txt文件。打开该文件,内容如下:

> 1 Green   21  Lawyer <end>> 2  Suse 22  dancer <end>> 3  Mary 24  Musician <end>> 4 Willam  20  sports man <end>> 5  Laura   25  \N <end>> 6 Evans   27    secretary <end>> 7   Dale 22  cook <end>> 8    Edison  28  singer <end>> 9    Harry   21  magician <end>> 10   Harriet 19  pianist <end>

可以看到,虽然将所有的字段值导出到文本文件中,但是所有的记录没有分行,出现这种情况是因为TERMINATED BY选项替换了系统默认的换行符。如果希望换行显示,则需要修改导出语句:

SELECT * FROM  test_db.person INTO OUTFILE "D:/person3.txt"LINES

STARTING BY
'>'TERMINATED BY'<end>\r\n';

执行完语句之后,换行显示每条记录,结果如下:

> 1 Green       21  Lawyer <end>

> 2 Suse         22  dancer <end>

> 3 Mary         24  Musician <end>

> 4 Willam      20  sports man <end>

> 5 Laura       25  \N <end>

> 6 Evans       27  secretary <end>

> 7 Dale         22  cook <end>

> 8 Edison      28  singer <end>

> 9 Harry       21  magician <end>

> 10 Harriet     19  pianist <end>

11.4.2  使用mysqldump命令导出文本文件

除了使用SELECT… INTO OUTFILE语句导出文本文件之外,还可以使用mysqldump命令。11.1节开始介绍了使用mysqldump备份数据库,该工具不仅可以将数据导出为包含CREATE、INSERT的sql文件,也可以导出为纯文本文件。

mysqldump创建一个包含创建表的CREATE TABLE语句的tablename.sql文件和一个包含其数据的tablename.txt文件。mysqldump导出文本文件的基本语法格式如下:

mysqldump -T path-u root -p dbname [tables] [OPTIONS]

只有指定了-T参数才可以导出纯文本文件;path表示导出数据的目录;tables为指定要导出的表名称,如果不指定,将导出数据库dbname中所有的表;[OPTIONS]为可选参数选项,这些选项需要结合-T选项使用。OPTIONS常见的取值有:

—  --fields-terminated-by=value:设置字段之间的分隔字符,可以为单个或多个字符,默认情况下为制表符(\t)。

—  --fields-enclosed-by=value:设置字段的包围字符。

—  --fields-optionally-enclosed-by=value:设置字段的包围字符,只能为单个字符,只能包括CHAR和VERCHAR等字符数据字段。

—  --fields-escaped-by=value:控制如何写入或读取特殊字符,只能为单个字符,即设置转义字符,默认值为\。

—  --lines-terminated-by=value:设置每行数据结尾的字符,可以为单个或多个字符,默认值为“\n”。

这里的OPTIONS的设置与SELECT…INTO OUTFILE语句中的OPTIONS不同,各个取值中等号后面的value值不要用引号括起来。

【例11.13】使用mysqldump将test_db数据库person表中的记录导出到文本文件,SQL语句如下:

mysqldump -T D:\ test_db person -u root -p

语句执行成功,系统D盘目录下面将会有两个文件,分别为person.sql和person.txt。person.sql包含创建person表的CREATE语句,其内容如下:

-- MySQL dump 10.13  Distrib 9.0.1, forWin64 (x86_64)--

--Host: localhost    Database: test_db-- ------------------------------------------------------

-- Server version    9.0.1

 

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT*/;/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS*/;/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION*/;

SET NAMES utf8mb4 ;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE*/;/*!40103 SET TIME_ZONE='+00:00'*/;/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE=''*/;/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0*/;-- -- Table structure fortable `person`--DROP TABLE IF EXISTS `person`;/*!40101 SET @saved_cs_client = @@character_set_client*/;/*!40101 SET character_set_client = utf8*/;

CREATE TABLE `person` (

`id`
int(10) unsigned NOT NULL AUTO_INCREMENT,

`name`
char(40) NOT NULL DEFAULT '',

`age`
int(11) NOT NULL DEFAULT '0',

`info`
char(50) DEFAULT NULL,

PRIMARY KEY (`id`)

) ENGINE
=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;/*!40101 SET character_set_client = @saved_cs_client*/;/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE*/;/*!40101 SET SQL_MODE=@OLD_SQL_MODE*/;/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT*/;/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS*/;/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION*/;/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES*/;-- Dump completed on 2024-07-25 16:40:55

备份文件中的信息已在11.1.1节中介绍了。

person.txt包含数据包中的数据,其内容如下:

1   Green       21Lawyer2   Suse         22dancer3   Mary         24Musician4   Willam      20sports man5   Laura       25\N6   Evans       27secretary7   Dale         22cook8   Edison      28singer9   Harry       21magician10  Harriet     19      pianist

【例11.14】使用mysqldump命令将test_db数据库中的person表中的记录导出到文本文件,使用FIELDS选项,要求字段之间使用逗号“,”间隔,所有字符类型字段值用双引号引起来,定义转义字符为“?”,每行记录以“\r\n”结尾,SQL语句如下:

mysqldump -T D:\ test_db person -u root -p --fields-terminated-by=, --fields-optionally-enclosed-by=\"--fields-escaped-by=? --lines-terminated-by=\r\n
Enter password:******

上面语句要在一行中输入,语句执行成功后,系统D盘目录下面将会有两个文件,分别为person.sql和person.txt。person.sql包含创建person表的CREATE语句,其内容与【例11.13】中的相同;person.txt文件的内容与【例11.13】中的不同,显示如下:

1,"Green",21,"Lawyer"

2,"Suse",22,"dancer"

3,"Mary",24,"Musician"

4,"Willam",20,"sports man"

5,"Laura",25,?N6,"Evans",27,"secretary"

7,"Dale",22,"cook"

8,"Edison",28,"singer"

9,"Harry",21,"magician"

10,"Harriet",19,"pianist"

可以看到,只有字符类型的值被双引号引起来了,而数值类型的值没有;第5行记录中的NULL表示为“?N”,使用“?”替代了系统默认的“\”。

11.4.3  使用mysql命令导出文本文件

mysql是一个功能丰富的工具命令,使用它们还可以在命令行模式下执行SQL指令,将查询结果导入文本文件中。相比mysqldump,mysql工具导出的结果具有更强的可读性。

如果MySQL服务器是单独的机器,用户是在一个客户端上进行操作,要把数据结果导入客户端上。

使用mysql导出数据文本文件的基本语法格式如下:

mysql -u root -p --execute= "SELECT语句" dbname > filename.txt

该命令使用--execute选项,表示执行该选项后面的语句并退出,后面的语句必须用双引号引起来;dbname为要导出的数据库名称;导出的文件中不同列之间使用制表符分隔,第1行包含了各个字段的名称。

【例11.15】使用mysql命令,将test_db数据库中的person表中的记录导出到文本文件,SQL语句如下:

mysql -u root -p --execute="SELECT * FROM person;" test_db > D:\person3.txt

语句执行完毕之后,系统D盘目录下面将会有名称为“person3.txt”的文本文件,其内容如下:

id  name         age     info1   Green       21Lawyer2   Suse         22dancer3   Mary         24Musician4   Willam      20sports man5   Laura       25NULL6   Evans       27secretary7   Dale         22cook8   Edison      28singer9   Harry       21magician10  Harriet     19      pianist

可以看到,person3.txt文件中包含了每个字段的名称和各条记录,该显示格式与MySQL命令行下SELECT查询结果的显示格式相同。

使用mysql命令还可以指定查询结果的显示格式,如果某条记录的字段很多,可能一行不能完全显示,可以使用--vartical参数将每条记录分为多行显示。

【例11.16】使用mysql命令将test_db数据库中的person表中的记录导出到文本文件,使用--vertical参数显示结果,SQL语句如下:

mysql -u root -p --vertical --execute="SELECT * FROM person;" test_db > D:\person4.txt

语句执行之后,D:\person4.txt文件中的内容如下:

*** 1. row ***id:1name: Green

age:
21info: Lawyer*** 2. row ***id:2name: Suse

age:
22info: dancer*** 3. row ***id:3name: Mary

age:
24info: Musician*** 4. row ***id:4name: Willam

age:
20info: sports man*** 5. row ***id:5name: Laura

age:
25info: NULL*** 6. row ***id:6name: Evans

age:
27info: secretary*** 7. row ***id:7name: Dale

age:
22info: cook*** 8. row ***id:8name: Edison

age:
28info: singer*** 9. row ***id:9name: Harry

age:
21info: magician*** 10. row ***id:10name: Harriet

age:
19info: pianist

可以看到,SELECT的查询结果导出到文本文件之后,显示格式发生了变化,如果person表中的记录内容很长,这样显示会让人更加容易阅读。

mysql还可以将查询结果导出到html文件中,使用--html选项即可。

【例11.17】使用MySQL命令将test_db数据库中的person表中的记录导出到html文件,SQL语句如下:

mysql -u root -p --html --execute="SELECT * FROM person;" test_db > D:\person5.html

语句执行成功,将在D盘创建文件person5.html,该文件在浏览器中的显示效果如图11.2所示。

如果要将表数据导出到xml文件中,可使用--xml选项。

【例11.18】使用mysql命令将test_db数据库中的person表中的记录导出到xml文件,SQL语句如下:

mysql -u root -p --xml --execute="SELECT * FROM person;" test_db >D:\person6.xml

语句执行成功,将在D盘创建文件person6.xml,该文件在浏览器中的显示效果如图11.3所示。

不同浪潮来临时,开始着不同的浪花,云计算浪潮开始时没人敢用,AI浪潮开始时人人试水。

除了满天飞的大模型,除了千金难买的AI芯(GPU显卡),除了让开发者惊叹与恐惧的AI编程助手,还有阿里云官网那个强塞给用户的AI助手。

当AI对算力的疯狂需求,当计算有可能成为AI时代的石油,让云计算厂商有望富得流油,而那个标志着阿里云全面拥抱AI的小助手却给普通的云计算用户带来了忧愁。

不知道从今年的哪一天开始,一进入阿里云控制台,笔记本电脑CPU风扇就开始呼呼作响(详见
博问
),与徐徐转动的AI助手图标遥相呼应,才猛然意识到这台用了多年的电脑已经跟不上云厂商紧跟的「AI时代」。

2013年,因为穷买不起服务器,才冒险地上了阿里云。

2024年,却因为穷买不起更好的笔记本电脑,而一上阿里云就想逃。

这点柴米油盐的小烦恼,现在想想,也许就是
想分手
的小火苗。

这点微不足道的小苦恼,今天想想,也要写篇随笔小题大做地吐槽,吐槽是为了更好。

致阿里云:请帮忙提供一个选项可以去掉AI助手,不仅是因为CPU风扇的烦恼,更是因为我们根本不需要。

起因

之前写过一篇 Nuxt3 的文章,
Nuxt3 环境变量配置
,用到了 PM2,但是里面的一些配置存在问题,最近有空又验证了一下,这里做一个勘误。

问题

PM2 的启动配置中有一项是
exec_mode
,默认是
fork
,另一个可选值是
cluster

fork
是单进程模式,
cluster
是多进程模式,也就是常说的集群模式。

最早开始用 Nuxt3 的时候,还在内测阶段,当时找到的资料很多都是基于 Nuxt2 的,Nuxt3 的文档也不是很全,所以很多配置都是参考 Nuxt2 的,有点病急乱投医了,最后拼凑出一套能正常启动的配置就没有再调整了,详情可以看之前的文章,这里把有问题的字段挑出来。

{
  exec_mode: "cluster",
  instances: "max", // Or a number of instances
  script: "npm",
  args: "start",
}

这里的配置造成了什么问题呢?首先可以看出来是通过 npm 来启动程序的,通过
npm run start
这个命令来执行
package.json
中的
start
脚本
node .output/server/index.mjs
,首先这样是可以启动的,但是存在一些问题:

服务器偶尔会出现 CPU 占用过高的情况,查看 CPU 占用情况发现是 node 进程,于是定位到 PM2,查看运行情况发现多个进程只有一个启动成功,其他的进程都在反复重启,CPU 自然升高。再去查看日志发现是因为端口被占用导致只有一个进程能启动成功,这时我意识到配置可能有问题,不过当时没有时间调整,于是一直以来都是通过手动停止其他进程来解决问题。

解决

有问题当然要解决,集群模式我接触的不多,但既然有这个配置,肯定不会因为端口占用就无法启动,Nuxt3 至今已有较大的版本变化,于是我再次翻看 Nuxt3 的文档,看下官方是怎么配置 PM2 的:

docs/getting-started/deployment

module.exports = {
  apps: [
    {
      name: "NuxtAppName",
      port: "3000",
      exec_mode: "cluster",
      instances: "max",
      script: "./.output/server/index.mjs",
    },
  ],
};

最早我是没觉得问题出在启动脚本这的,直到我又找到一个 github 上的 issue
Port Already in Use in Cluster Mode
,包括里面关联的问题都提到了不应使用 npm 来启动,而是直接使用脚本路径。

You can't cluster application via npm start. To make cluster work, in the script attribute of your ecosystem.config.js, directly put the path of your javascript app.

通过 npm 启动时并没有将这个进程直接托管给 pm2,而是通过 npm 启动了一个进程,pm2 只是监控这个进程,所以 pm2 并不能很好地管理这个进程,上面的截图中也可以看到版本号是 0.39.7,其实这个是服务器上 nvm 的版本,而不是 nuxt3 程序的版本。

关于集群模式

最早我怀疑是集群模式的问题,但即使改成 fork,也还是会出现端口占用的报错,虽然可以通过修改
instances
来解决,但隐约觉得不是正确的方法,在解决启动报错问题之后,我再次尝试了使用集群模式,不过我仍然不太清楚是否应该使用这个配置,于是我做了一些测试,只是在本地环境的一些测试,结果并不准确,只能做个参考。

instances
是要使用的进程数量,它的值可以是
'max'

-1
或其他数字,
'max'
表示使用最大的实例数,
-1
表示使用最少的基本就是 1 个,其他数字表示使用指定数量的实例数,这个实例数是根据 CPU 核心数来计算的,比如单核双线程的 CPU,实例数就是 2。

首先我在本地启动了一个 nuxt3 项目,这里模拟服务器环境只用了 2 个实例,然后使用两种不同的 pm2 启动方式执行。

使用
pm2 monit
监控进程,可以看到这时还没什么区别,这时用 jmeter 进行压测,创建 500 个线程访问集群模式的进程,可以看到两个进程都在运行:

然后同样的压测,但是使用 fork 模式,可以看到只有一个进程在运行:

我并不了解压测,只是简单对比一下,可以看出集群模式的 CPU 波动还是比较明显的,fork 模式 CPU 的波动不明显,但是内存占用会极速攀升,没有截到图。继续增加压测线程,内存的变化并不明显,集群模式的 CPU 占用会更加明显,也有可能是因为压测应用和被压测应用都在本地,所以这个测试结果并不准确,在错误率方面,也没有测出两者的区别。通过简单的测试并没有感受出优劣,集群的优势可能体现在性能和容错方面,在硬件上看不出太多效果,这里只是做一个记录,具体还需要更多的实践经验。

集群模式允许联网的 Node.js 应用程序(http(s)/tcp/udp 服务器)在所有可用的 cpu 上扩展,无需任何代码修改。根据可用 cpu 的数量,这将极大地提高应用程序的性能和可靠性。

liwen01 2024.10.01

前言

麦克斯韦预言了电磁波的存在,赫兹通过实验证实了麦克斯韦的预言,马可尼基于无线电磁波的原理发明了无线电报系统,从此人类进入无线通信系统时代。

天线是通信系统中必不可少的组成部分,它的作用是将电信号转换为电磁波信号发射出去,也可以将接收到的电磁波信号转换为电信号。

在 WiFi 应用中,WiFi 天线与 WiFi 性能关系密切,包括但不限于天线的方向、极化、增益、工作频率范围等参数。

(一) 中学物理基础

要理解天线的工作原理,需要复习一下中学物理基础知识,这里只做概述,不做详细介绍。其中部分基础知识可以参考第一篇文章内容《
wifi基础(一):无线电波与WIFI信号干扰、衰减

(1) 麦克斯韦方程

詹姆斯·克拉克·麦克斯韦
提出了将电、磁、光统归为电磁场现象的麦克斯韦方程组,实现了物理学自牛顿后的第二次统一。

麦克斯韦方程组的微分表达式为:

可以简单概述为:

  • 高斯定律(电场)
    :描述电场与电荷之间的关系,表明电荷是电场的源头,电场从正电荷发散,朝向负电荷收敛。

  • 高斯定律(磁场)
    :说明磁场没有单极子(即不存在
    孤立的
    磁极),磁场线是闭合的,即磁场的通量通过任意闭合曲面为零,南北磁极总是成对存在。

  • 法拉第定律
    :描述变化的磁场如何产生电场,变化的磁场会在周围空间产生旋转电场,这就是电磁感应现象。

  • 安培-麦克斯韦定律
    :描述电流和变化的电场如何产生磁场。变化的电场会感应出磁场,电磁波的传播是依靠这种变化的电场和磁场相互生成。

麦克斯韦在1864年发表的论文《电磁场的动力学理论》中提出电场和磁场以波的形式以光速在空间中传播,并提出光是引起同种介质电场和磁场中许多现象的电磁扰动,同时在理论上预测了电磁波的存在。

(2) 赫兹试验

1886 年海因里希·鲁道夫·赫兹用实验证实了电磁波的存在,并测出了电磁波传播的速度与光速相同,还进一步观察到电磁波具有聚焦、直进性、反射、折射和偏振等性质。

赫兹证明电磁波存在的试验,使用的装置是火花间隙发射器。

(1) 电路元件介绍

B
:电池或电源,提供电路所需的电能。

SW
:开关,用来控制电路的通断,启动实验。

C
:电容器,用于存储电能

T
:变压器,使 S 两端产生高电压。

L
: 变压器上的线圈,与电容一起形成 LC 谐振电路

I
:断续器(Interrupter),周期性地断开和闭合电路,使电容器快速充放电,产生一连串的阻尼波。

S
:火花间隙,当电容器充满电后,电压升高到足够水平时,火花间隙处会产生火花放电,释放电容器C的能量。

M
:接收器中的火花间隙,当电磁波到达时,这里也会产生火花,证明电磁波的存在。

(2) 工作原理

能量储存

当开关 SW 闭合时,电源 B 给电容器 C1 充电,在充电过程中,电流是变化的,变化的电流通过线圈 L1,产生变化的磁场,变化的磁场在线圈 L2 中产生感应电动势,为两个电容 C 充电。

C1 电容器逐渐储存能量,直到电路中没有电流流动,或者是 S 产生电离火花。

火花产生

当电容器 C 的电压升高到足够高的水平时,在火花间隙 S 处因为高压会把空气电离,在电场的作用下产生火花放电,释放电容器 C 中储存的能量。

火花放电时,产生了一个快速的电流变化(电流脉冲),激发线圈 L 中的电流,并在周围的空间中产生电磁波。

这里产生的放电火花,其原理与特斯拉线圈原理类似,都是通过高电压电离空气放电产生火花。

电磁波传播

由于电流的快速变化,根据麦克斯韦方程,变化的电流会产生变化的磁场,而变化的磁场在线圈中会感应出电场,这种变化的电磁场会以电磁波的形式在空间中传播。

接收电磁波

当电磁波到达收器的环形天线 M 时,它在导线环中激发出感应电动势,使得导线环两个小球之间也产生了火花,说明这个导线环接收到了电磁波。

火花隙发射器的一个基本限制是它们产生的是瞬态脉冲,称为阻尼波,无法产生用于在现代无线电传输中的连续波
(比如广播,无线电话信号等)。

(二) 偶极子天线

偶极子天线(Dipole Antenna)是最简单、最基础的天线类型之一,也是现代无线通信系统中应用最广泛的天线之一,它由两个相同长度的导体构成。

  • 在偶极子天线的金属导体中,通过输入交变电流,电流会随着时间以正弦波的形式周期性变化
  • 当交变电流继续在天线中流动时,电流的方向反复改变,形成不断变化的电场和磁场。
  • 这两个场互相感应:变化的电场产生磁场,变化的磁场又产生电场,形成了电磁波。

电磁波可以想象为电场和磁场的自传播横向振荡波

  • 若两导线的距离很近,电场被束缚在两导线之间,因而辐射很微弱
  • 将两导线张开,电场就散播在周围空间,电磁波辐射增强。
  • 在实际应用中,偶极子天线会向所有方向发射电磁波,但发射的强度在不同方向上是不均匀的。

通常,天线的主要辐射方向与天线轴垂直,呈现出一种圆环形辐射模式。

偶极子天线中产生电磁波的这两根导线叫
振子
。一般情况下,振子的大小在半个波长的时候效果最好,所以也经常被称作
半波振子

有了振子,就可以发送连续的电磁波了。

(三) 天线的方向

天线的方向性是指天线向一定方向辐射电磁波的能力。对于接收天线而言,方向性表示天线对不同方向传来的电磁波所具有的接收能力。

天线对空间不同方向具有不同的辐射或接收能力,这就是天线的方向性。

按天线的方向性可以将天线可以分为全向天线和定向天线两大类。

(1) 全向天线

  • 在水平面上,辐射与接收无最大方向的天线称为全向天线。
  • 全向天线由于其无方向性,所以多用在点对多点通信的中心台。
  • 常用的 WiFi 天线都是全向天线

半波对称振子天线的辐射方向

水平面(H面)

  • 左边的圆形图表示的是从天线的顶部往下看的水平切面,即天线在水平方向上的辐射图。
  • 这个天线在水平方向上是全向辐射的(辐射范围均匀),类似于一个圆形的辐射图,箭头表明信号向四面八方均匀扩展。
  • 这意味着在水平方向上,信号强度是相等的

垂直面(E面)

  • 右边的图是垂直面上的辐射方向图,即从天线的侧面看。天线的垂直辐射模式在垂直面上类似于一个“8”字形。
  • 表明天线在垂直方向上不是全向的,而是有一定的方向性。信号强度在某些角度较强,而在其他角度(例如上下方向)较弱。
  • 在振子的轴线方向上它的辐射为零

(2)定向天线

  • 在水平面上,有一个或多个最大方向的天线称为定向天线
  • 定向天线由于具有最大辐射或接收方向,因此能量集中,适合于远距离通信
  • 由于具有方向性,抗干扰能力比较强
  • 常见的有平板天线(Panel Antenna)、抛物面天线(Parabolic Antenna)

使用抛物反射面,把功率反射到单侧方向,能量集中到一个小立体角内,反射从而获得很高的增益。

(四) 天线的极化

天线的极化(Antenna Polarization)指的是天线辐射或接收电磁波的
电场
矢量的方向。

由于电场与磁场有恒定的关系,故一般都以
电场矢量
的方向作为天线辐射电磁波的极化方向,并且是以天线最大辐射方向上的电场矢量方向为天线的极化方向。

天线极化主要有:线性极化、圆形极化和椭圆极化三大类:

(1) 线极化(Linear Polarization)

线极化是指电磁波的电场矢量沿一条直线振动,根据方向可以进一步分为:

  • 垂直极化(Vertical Polarization)
    :电场矢量在垂直方向上振动。这种极化方式常用于地面通信、广播和一些移动通信应用,因为信号传播时更容易绕过障碍物。
  • 水平极化(Horizontal Polarization)
    :电场矢量在水平方向上振动。它在某些特殊的环境中有更好的穿透性,比如远距离无线电通信。

线极化特点

  • 线极化天线通常用于固定方向的点对点通信,因为它的电场方向是单一的
  • 垂直和水平极化天线之间的匹配度非常重要,极化不匹配会导致信号损耗(称为极化损耗)

(2) 圆极化(Circular Polarization)

圆极化是指电场矢量随着时间呈螺旋形旋转,电场的方向不断变化,形成圆形振动轨迹。圆极化分为两种类型:

右旋圆极化(Right-Hand Circular Polarization, RHCP)
:电场矢量以顺时针方向旋转。

左旋圆极化(Left-Hand Circular Polarization, LHCP)
:电场矢量以逆时针方向旋转。

  • 圆极化的优势在于它能够适应多径传播环境中的复杂反射,因为电场方向不断变化,接收器能够在不同的反射路径上保持良好的信号接收。
  • 圆极化天线广泛应用于卫星通信、无人机控制、GPS等场景,特别适合移动和旋转设备的通信。

(3) 椭圆极化(Elliptical Polarization)

椭圆极化是介于线极化和圆极化之间的一种极化类型。电场矢量以椭圆的轨迹旋转,极化不完全是线性或圆形。这种极化通常出现在天线设计中的一些特殊应用中

(4)双极化天线(Dual-Polarized Antenna)

双极化天线通过两个独立的辐射单元来传输和接收信号,每个单元具有不同的极化方向.

这两个极化方向彼此正交,因此可以在同一频率下发送和接收两组不同的信号,极大地提高了数据传输的效率。

这种正交极化的方式能够在不干扰对方的情况下实现双流信号传输

下图是某款AP的内置天线

双极化天线的主要优势

提高频谱效率
:双极化天线可以在同一个频率上同时传输两个独立的信号流,从而实现双倍的数据传输速率。这对于提高频谱利用率尤其重要,特别是在蜂窝通信和无线局域 WiFi 网中。

增强信号质量(MIMO 技术支持)
:双极化天线可以支持MIMO(多输入多输出)技术,通过使用多个天线单元和极化方向,能够更好地应对信号的反射、衰减和多径效应,从而提升无线信号的覆盖范围和稳定性。

降低相互干扰(Cross-Polarization Isolation)
:双极化天线能够减少相互干扰,因为它的两个极化方向是正交的(90度相位差)。这种隔离减少了相邻频率段的干扰,尤其是在高密度的无线电环境中。

提升抗干扰能力
:通过同时使用两个正交极化信号,双极化天线能够更好地应对环境中的干扰,特别是在复杂的多径传播环境中。极化不同的信号路径会有不同的干扰行为,因此可以有效分离信号和噪声。

增强空间多路复用(Spatial Multiplexing)
:在MIMO系统中,双极化天线通过同时使用两个正交极化方向,可以实现空间多路复用,从而进一步增加数据传输速率。这在现代的无线通信系统中极为重要。

(5)极化匹配

天线之间的极化匹配对于信号传输的效率至关重要。如果发射天线和接收天线的极化不匹配(例如一个天线是垂直极化而另一个是水平极化),会导致显著的信号损耗,这种现象被称为极化损耗。在极端情况下,极化不匹配的天线可能会完全无法接收信号。

同极化通信
:发射天线和接收天线的极化相同,通信效率高,信号损耗小。

交叉极化损耗
:发射和接收天线的极化不一致时,接收信号会显著减弱,损耗增加s

(五) 天线的增益

天线通常是无源器件,它并不放大电磁信号。

天线增益并不表示天线实际
放大
了信号,而是表示天线能够将输入的功率在某个方向上更集中地辐射。更高的增益意味着天线在某个方向上辐射或接收的功率更强,但在其他方向上相应的功率较弱。因此,天线增益越高,天线的方向性越强。

天线增益是用来衡量天线朝一个特定方向收发信号的能力,是选择天线最重要的参数之一,与具体的天线型号相关。

(1)天线增益的单位

天线的增益单位有两个 dBi 和 dBd

(a)dBi(相对于各向同性天线的增益)

  • dBi 是天线增益相对于
    各向同性天线(Isotropic Antenna)
    的增益。各向同性天线是一种理想的天线,它能够在所有方向上均匀辐射能量,因此它的增益在所有方向都是相同的,且定义为 0 dBi
  • 使用 dBi 作为增益单位时,它表示天线在特定方向上的辐射功率与同等条件下的各向同性天线相比多了多少分贝。
  • dBi 是天线增益的国际标准单位,因此它被广泛用于天线的规格说明中,尤其是在Wi-Fi路由器、无线电、卫星通信等设备中。

(b) dBd (相对于偶极子天线的增益)

  • dBd 是天线增益相对于 半波偶极子天线(Half-Wave Dipole Antenna)的增益。半波偶极子天线是一种常用的参考天线,其辐射能量相对于各向同性天线有更强的方向性,且在水平方向上具有更大的辐射能力。
  • 半波偶极子天线的增益为 2.15 dBi,这意味着偶极子天线在水平方向上辐射的功率比各向同性天线高出 2.15 dB。因此,当天线增益以 dBd 为单位时,表示的是天线与半波偶极子天线相比的增益。

由于半波偶极子天线的增益为 2.15 dBi,因此 dBi 和 dBd 之间的关系是:
dBi=dBd+2.15

在多数 WiFi 设备中,天线增益通常以 dBi 标注,表明其相对于各向同性天线的辐射性能。常见的家用WiFi路由器天线增益在 2 dBi到 5 dBi之间。

(六) 波瓣宽度

天线的波瓣宽度一般指主瓣的半功率波瓣宽度(Half-Power Beamwidth,HPBW)。它表示主瓣内两个方向上信号强度下降到最大强度一半(-3 dB)时所形成的角度差,通常用角度度数(°)来表示。

波瓣(Lobe)
:天线辐射方向图的每个凸起部分称为波瓣。主波瓣是辐射最强的波瓣,侧波瓣和背波瓣是相对较弱的波瓣。

半功率点(Half-Power Point)
:波瓣宽度定义为天线主瓣功率达到其最大功率的50%处的角度范围,即从最大辐射方向减弱3 dB的功率点。

波瓣宽度(Beamwidth)
:波瓣宽度表示主波瓣从左侧半功率点到右侧半功率点之间的角度。这一角度通常定义为 -3 dB波瓣宽度

宽波瓣
:全向天线通常具有较宽的波瓣宽度,辐射或接收的方向性较弱,适合覆盖较大的区域,例如家庭WiFi路由器的全向天线。

窄波瓣
:定向天线具有较窄的波瓣宽度,适合长距离和高精度的通信场景,例如微波通信、卫星通信和无线电传输等。

(1)波瓣宽度与天线增益的关系

天线的波瓣宽度与增益之间存在反比关系。通常情况下,天线的波瓣宽度越窄,天线的增益越高。这是因为窄波瓣天线能将更多的能量集中在较小的角度范围内,从而提高在该方向上的信号强度

(2)波瓣宽度的测量方法

天线的波瓣宽度通常通过测量天线的 辐射方向图(Radiation Pattern)得到。辐射方向图是一个三维图像,展示天线在不同方向上辐射功率的分布情况。

通过在不同方向上测量功率密度,找到主波瓣的半功率点,计算两个半功率点之间的角度差,即波瓣宽度

结尾

天线是 WiFi 设备的一个重要组成部分,电波传播与天线也是一门独立的学科,涉及到的知识非常多。我并非通信专业人员、对天线知识仅知皮毛。

为了写这个 WiFi 系列介绍,其实很多知识点我也是现学的,虽然已尽全力,但错误之处在所难免。若蒙读者诸君不吝告知,将不胜感激。

下篇将补上 WiFi 组网相关的基础知识介绍。

------------------End------------------
如需获取更多内容
请关注 liwen01 公众号