Nginx负载均衡的优缺点

Nginx的优点是:
1、工作在网络的7层之上,可以针对http应用做一些分流的策略,比如针对域名、目录结构,它的正则规则比HAProxy更为强大和灵活,这也是它目前广泛流行的主要原因之一,Nginx单凭这点可利用的场合就远多于LVS了。
2、Nginx对网络稳定性的依赖非常小,理论上能ping通就就能进行负载功能,这个也是它的优势之一;相反LVS对网络稳定性依赖比较大,这点本人深有体会;
3、Nginx安装和配置比较简单,测试起来比较方便,它基本能把错误用日志打印出来。LVS的配置、测试就要花比较长的时间了,LVS对网络依赖比较大。
3、可以承担高负载压力且稳定,在硬件不差的情况下一般能支撑几万次的并发量,负载度比LVS相对小些。
4、Nginx可以通过端口检测到服务器内部的故障,比如根据服务器处理网页返回的状态码、超时等等,并且会把返回错误的请求重新提交到另一个节点,不过其中缺点就是不支持url来检测。比如用户正在上传一个文件,而处理该上传的节点刚好在上传过程中出现故障,Nginx会把上传切到另一台服务器重新处理,而LVS就直接断掉了,如果是上传一个很大的文件或者很重要的文件的话,用户可能会因此而不满。
5、Nginx不仅仅是一款优秀的负载均衡器/反向代理软件,它同时也是功能强大的Web应用服务器。LNMP也是近几年非常流行的web架构,在高流量的环境中稳定性也很好。
6、Nginx现在作为Web反向加速缓存越来越成熟了,速度比传统的Squid服务器更快,可以考虑用其作为反向代理加速器。
7、Nginx可作为中层反向代理使用,这一层面Nginx基本上无对手,唯一可以对比Nginx的就只有lighttpd了,不过lighttpd目前还没有做到Nginx完全的功能,配置也不那么清晰易读,社区资料也远远没Nginx活跃。
8、Nginx也可作为静态网页和图片服务器,这方面的性能也无对手。还有Nginx社区非常活跃,第三方模块也很多。
淘宝的前端使用的Tengine就是基于nginx做的二次开发定制版。
  Nginx的缺点是:
1、Nginx仅能支持http、https和Email协议,这样就在适用范围上面小些,这个是它的缺点。
2、对后端服务器的健康检查,只支持通过端口来检测,不支持通过url来检测不支持Session的直接保持,但能通过ip_hash来解决

Nginx下利用rewrite实现强制跳转https

Nginx下利用rewrite实现强制跳转https

if ($scheme = http) {
rewrite ^(.*) https://$server_name$1 permanent;
}

以上代码直接放入主机给的rewrite规则中即可,其中

scheme #HTTP的方法(如http,https)

$1 permanent #规则为http://domains/xxx 跳转到https://domains/xxx

项目前期使用http,后期为了安全方面的考虑,启用了https。

项目架构:前端使用nginx作为多个tomcat实例的反向代理和负载均衡。

实际上只需要在nginx上启用https即可,使客户端与nginx之后使用https方式通信,而nginx与tomcat之间依然以http方式通信。

现在需要将之前客户端所有的http请求全部都自动重定向为https,只需要在nginx上添加相应配置即可。

如下配置实现来源于Nginx HTTP 跳转至 HTTPS,但是我都实践验证过。

另外,也加入了一些自己的理解整理而成。

方式1:使用rewrite指令

server {
    listen 80;
    server_name domain.com;
    rewrite ^(.*) https://$server_name$1 permanent;
}
server {
    listen 443 ssl;
    server_name domain.com;
    ssl on;
    ssl_certificate     /etc/nginx/ssl/domain.com.crt;
    ssl_certificate_key /etc/nginx/ssl/domain.com.crt;
    # other
}

如果此时nginx作为Tomcat的前端反向代理的话,需要将相应配置放在配置ssl的server块中。

方式2:使用return指令

server {
    listen 80;
    server_name domain.com;
    return 301 https://$server_name$request_uri;
}
server {
    listen 443 ssl;
    server_name domain.com;
    ssl on;
    ssl_certificate     /etc/nginx/ssl/domain.com.crt;
    ssl_certificate_key /etc/nginx/ssl/domain.com.crt;
    # other
}

如果此时nginx作为Tomcat的前端反向代理的话,需要将相应配置放在配置ssl的server块中。

方式三:使用error_page指令

只允许HTTP来访问时,用HTTP访问会让Nginx报497错误,然后利用error_page将链接重定向至HTTPS上。

server {
    listen 80;
    listen 443 ssl;
    server_name domain.com;
    ssl on;
    ssl_certificate     /etc/nginx/ssl/domain.com.crt; 
    ssl_certificate_key /etc/nginx/ssl/domain.com.crt;
    # other
    error_page 497 https://$server_name$request_uri;
}

使用error_page指令时,将http和https的监听配置写在同一个server块中,对应的其他配置也需要在该server配置块中完成。

需要注意的是,此时需要将error_page指令语句写在最后,否则不能生效。

深入分析HTTP状态码502(nginx+php-fpm)

我们的一个web项目,由于新上城市增多,导致访问量增大,DB压力增大,作为提供接口的业务方,最近被下游反馈大量请求“502”。

502,bad gateway,一般都是upstream(这里就是php)出错,对于php,造成502的原因常见的就是脚本执行超过timeout设置时间,或者timeout设置过大,导致php进程长时间不能被释放,没有空闲worker进程来接客。

我们的项目就是php执行时间设置过短导致的,对于这种情况,可以先适当增大php的执行时间,先保证清除502,优化的事情毕竟要花更多的时间。

控制php执行时间的选项有两个,在php.ini中 max_execution_time 和php-fpm中 request_terminate_timeout,其中 request_terminate_timeout 可以覆盖 max_execution_time,所以如果不想改全局的php.ini,那只改php-fpm的配置就可以了。

 

下边我就来详细的分析一下为什么php脚本执行超出设置时间会导致nginx返回502。

先来布景,让问题复现:

nginx和php分别只启动一个worker,方便追踪。

php-fpm的request_terminate_timeout设置为3S。

测试脚本test.php

sleep(20); echo 'ok';

go go go:

在浏览器访问www.v.com/test.php,3S后如期出现…404???what???

出师不利啊,赶紧看看nginx的配置文件

这个location配置是当发生5xx错误时跳转到一个好看点的界面,但是我在/usr/share/nginx/html下并没有50x.html这个文件。所以搞了个404出来。这不是很影响我判断问题的准确性?直接注释掉!再次访问,等待3S,终于’正常’的界面出来了。

 

环境好了,下边就上套路,按照web问题的排查套路走一遍,先看看错误日志吧:

nginx:

报错都是 recv() failed (104: Connection reset by peer。

recv时失败了,连接被重置了。为啥连接被重置了?难道一言不合。

我们在看看php-fpm的错误日志:

(注意php-fpm中php_admin_value[error_log]选项指定php的错误日志,会覆盖php.ini中的。但是这里不是看php的错误,而是看php-fpm的错误。php-fpm的错误日志由php-fpm.conf中的error_log选项指定。)

每一次请求都是产生2个WARNING和1个NOTICE:

WARNING:脚本执行超时了,终止了。

WARNING:子进程收到SIGTERM信号退出了。

NOTICE:启了一个新的子进程(因为我设置的pm.min_spare_servers = 1)

看来如果php的worker进程执行超时,不仅终止脚本执行,而且worker进程也会退出。看来nginx的报错连接被重置是因为php的worker进程退出了(在TCP连接中一方如果断掉的话会发送RST给另一方)

 

通过日志已经可以知道php脚本执行超时,worker子进程退出,导致nginx报错Connection reset by peer,下边我们通过strace来看看php和nginx的情况:

php:

1.accept一个nginx的连接请求(socket,bind,listen都在master中完成 ),可以看到nginx的端口是47039,从FD0中读取数据,就是从标准输入中,这个是fast-cgi协议规定的。accept之后的已连接描述符是3。

2.从FD3中读取nginx传递过来的数据,fastcgi协议格式,接收了856字节。为什么read5次呢?

因为fastcgi协议数据包是8字节对齐,由包头和包体组成。并且都是会先发一个request数据包,包含一些请求ID,版本,typpe等信息(包头包体各占8字节),再发一个params数据包,传递get参数和环境变量(包头8字节,包体变长),最后发送一个没有包体只有包头的params数据包,表示参数发送结束(包头8字节)。所以前3个read用来读出request包的包头和包体,还有params包的包头,第四个read是读取真正的数据,最后一个read是读取最后一个params包的包头。所以nginx传递的数据应该是8+8+8+856+8=896字节(和下边nginx的传输bytes能对应上)。注意如果是post方式,还会发送stdin数据包。

3.设置休眠20S,就是php程序中的sleep(20),之后由于进程被终止了,所以后边就没啦。strace程序也退出啦。

nginx:

1.accept到浏览器的请求,可以看到浏览器端的端口是56434,IP是192.168.1.105,已建立连接的FD是3。

2.从FD3中接收数据,HTTP协议。

3.创建一个socket,FD21,用于和php建立连接。

4.连接到FD21,可以看到连接的是本机的9000端口,这里nginx和php-fpm使用IP socket连接方式,nginx和php-fpm部署在一台机器上可以考虑unix domain socket。

5.向FD21写入数据,fast-cgi协议格式,我们看到写入的长度是896,和上边的php接收的长度是对应的。

6.recvfrom函数从FD21中返回 ECONNRESET (Connection reset by peer)

7.向FD9中写入错误信息,可以推断FD9就是nginx错误日志的文件描述符。

8.关闭和FD21的连接。

9.向FD3写入502 Bad Gateway,就是返回给浏览器的信息。

10.向FD8写入一条访问日志,可以推断FD8就是nginx访问日志的文件描述符。

来验证一下nginx访问日志和错误日志的推断。可以看到的确是FD8,FD9,并处于写入模式。

 

那么在这个过程中整个网络包的传输我们不妨也看一下:

通过tcpdump抓包,用神器看比较方便。

因为只想看nginx和php的通讯,在上边又知道nginx的端口是47039,可以通过tcp.srcport==47039过滤出对应的包。

可以看到nginx和php-fpm数据交互的过程:47039->9000建立三次握手,接着向9000发送数据,9000回复ACK,3S后9000回复RST。没毛病。

注意:

SYN,FIN各占一个序列号

ACK,RST不占序列号(28,29两个包的reqnum和acknum都是相同的)

序列号是每一字节加1(29包发送896字节,同时29包seq为4219146879,30包的ack为4219147775,正好相差896)

RST不需要回复。

CentOS7 配置iptables,关闭默认防火墙

一、防火墙配置

1、检测并关闭系统默认的防火墙firewall

[plain] view plain copy

  1. systemctl status firewalld.service #检测是否开启了firewall  
  2. systemctl stop firewalld.service #关闭firewall  
  3. sytsemctl disable firewalld.service #关闭禁止firewall开机自启  

2、检测并安装iptables

[plain] view plain copy

  1. yum install iptables-services  

将规则写入iptables配置文件

[plain] view plain copy

  1. vim /etc/sysconfig/iptables  

iptables文件内容:

[plain] view plain copy

  1. *filter  
  2. :INPUT ACCEPT [0:0]  
  3. :FORWARD ACCEPT [0:0]  
  4. :OUTPUT ACCEPT [0:0]  
  5. -A INPUT -m state –state RELATED,ESTABLISHED -j ACCEPT  
  6. -A INPUT -p icmp -j ACCEPT  
  7. -A INPUT -i lo -j ACCEPT  
  8. -A INPUT -p tcp -m state –state NEW -m tcp –dport 22 -j ACCEPT  
  9. -A INPUT -p tcp -m state –state NEW -m tcp –dport 80 -j ACCEPT  
  10. -A INPUT -p tcp -m state –state NEW -m tcp –dport 8080 -j ACCEPT   
  11. -A INPUT -j REJECT –reject-with icmp-host-prohibited  
  12. -A FORWARD -j REJECT –reject-with icmp-host-prohibited  
  13. COMMIT  

重启iptable服务:

[plain] view plain copy

  1. systemctl restart iptables.service  

使iptable服务开机自启:

[plain] view plain copy

  1. systemctl enable iptables.service    

二、关闭SELINUX

[plain] view plain copy

  1. vim /etc/selinux/config  

修改为:

[plain] view plain copy

  1. #SELINUX=enforcing #注释掉  
  2.   
  3. #SELINUXTYPE=targeted #注释掉  
  4.   
  5. SELINUX=disabled #增加  

使配置立即生效:

[plain] view plain copy

  1. setenforce 0   

Nginx模块GeoIP查询IP所在国家、城市,查询某个ip位置

地理位置数据在业务中有重要作用,这些数据可以用于向某些人群推广品牌、产品或服务,还有助于增强用户体验。
本文讲述仅通过配置Nginx加上GeoIP MaxMind数据库,就能获得用户IP地址的实际物理位置,而无需编写任何代码。
Nginx是一个开源的HTTP和IMAP/POP3代理服务器,主要用作Web服务器或反向代理服务器。Nginx的GeoIP模块(即ngx_http_geoip_module)使用了预编译的MaxMind数据库来设置变量,比如变量geoipcountrynamegeoip_country_code、变量$geoip_city等等,而这些值则取决于用户客户端的访问地址。

Nginx可配合GeoIP模块定位IP所在物理位置并做相应处理,支持多个条件匹配:

#http://www.haiyun.me
$geoip_country_code #国家代码2位,如CN
$geoip_country_code3 #国家代码3位,如CHN
$geoip_country_name #国家完整名称,如China
$geoip_region #所在地区
$geoip_city #所在城市,如BeiJing
$geoip_postal_code #邮政编码
$geoip_city_continent_code #所在洲,如AS
$geoip_latitude #纬度
$geoip_longitude #经度

编译安装Nginx并添加GeoIP模块:

yum install geoip-devel #安装GeoIP解析库
wget http://nginx.org/download/nginx-1.0.15.tar.gz
tar zxvf nginx-1.0.15.tar.gz
cd nginx-1.0.15
 ./configure --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module \
--with-http_ssl_module --with-http_gzip_static_module --with-ipv6 --with-http_geoip_module
make
make install

下载GeoIP城市国家数据库:

#http://www.haiyun.me
mkdir -p /usr/local/nginx/geoip
cd /usr/local/nginx/geoip
wget http://www.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
gunzip GeoIP.dat.gz
gunzip GeoLiteCity.dat.gz

编辑Nginx配置文件加载GeoIP数据库:

http
    [...]
geoip_country  /usr/local/nginx/geoip/GeoIP.dat; #国家数据库
geoip_city     /usr/local/nginx/geoip/GeoLiteCity.dat; #城市数据库
[...]

如需Nginx传递变量给PHP,编辑fastcgi_params添加:

fastcgi_param GEOIP_CITY_COUNTRY_CODE $geoip_city_country_code;
fastcgi_param GEOIP_CITY_COUNTRY_CODE3 $geoip_city_country_code3;
fastcgi_param GEOIP_CITY_COUNTRY_NAME $geoip_city_country_name;
fastcgi_param GEOIP_REGION $geoip_region;
fastcgi_param GEOIP_CITY $geoip_city;
fastcgi_param GEOIP_POSTAL_CODE $geoip_postal_code;
fastcgi_param GEOIP_CITY_CONTINENT_CODE $geoip_city_continent_code;
fastcgi_param GEOIP_LATITUDE $geoip_latitude;
fastcgi_param GEOIP_LONGITUDE $geoip_longitude;

应用示例,Nginx判断如果访问者IP所在国家为美国或中国,返回404错误

server
    [...]
                if ($geoip_country_code ~* (US|CN)) {
                #return 404;
                }
[...]

新建PHP程序测试GeoIP:

<html>
<head>
 <title>IP地址检测,我的IP地址是多少?</title>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<?php
    if (getenv(HTTP_X_FORWARDED_FOR)) {
        $pipaddress = getenv(HTTP_X_FORWARDED_FOR);
        $ipaddress = getenv(REMOTE_ADDR);
        echo "<br>您的代理IP地址是: ".$pipaddress. " (via $ipaddress) " ;
    } else {
        $ipaddress = getenv(REMOTE_ADDR);
        echo "<br>您的IP地址是 : $ipaddress";
    }
  $geoip_city_country_code = getenv(GEOIP_CITY_COUNTRY_CODE);
  $geoip_city_country_code3 = getenv(GEOIP_CITY_COUNTRY_CODE3);
  $geoip_city_country_name = getenv(GEOIP_CITY_COUNTRY_NAME);
  $geoip_region = getenv(GEOIP_REGION);
  $geoip_city = getenv(GEOIP_CITY);
  $geoip_postal_code = getenv(GEOIP_POSTAL_CODE);
  $geoip_city_continent_code = getenv(GEOIP_CITY_CONTINENT_CODE);
  $geoip_latitude = getenv(GEOIP_LATITUDE);
  $geoip_longitude = getenv(GEOIP_LONGITUDE);
  echo "<br>国家 : $geoip_city_country_name ( $geoip_city_country_code3 , $geoip_city_country_code ) ";
  echo "<br>地区 :  $geoip_region";
  echo "<br>城市 :  $geoip_city ";
  echo "<br>邮政编码 :  $geoip_postal_code";
  echo "<br>所在洲 :  $geoip_city_continent_code";
  echo "<br>纬度 :  $geoip_latitude ";
  echo "<br>经度 :   $geoip_longitude ";
 
?>
</body>
</html>

如果要查询某个IP属于哪个国家地区。

http://pecl.php.net/get/geoip-1.1.1.tgz

php需要增加这个扩展。

tar -zxvf geoip-1.1.1.tgz

cd geoip-1.1.1

/usr/local/php/bin/phpize  

./configure –with-php-config=/usr/local/php/bin/php-config 

make

make install

 vi /usr/local/php/etc/php.ini

增加extension=geoip.so

详细使用geoip扩展参考

http://php.net/manual/zh/book.geoip.php

Redis Bgrewriteaof 命令 – 异步执行一个 AOF(AppendOnly File) 文件重写操作

Redis Bgrewriteaof 命令用于异步执行一个 AOF(AppendOnly File) 文件重写操作。重写会创建一个当前 AOF 文件的体积优化版本。

即使 Bgrewriteaof 执行失败,也不会有任何数据丢失,因为旧的 AOF 文件在 Bgrewriteaof 成功之前不会被修改。

注意:从 Redis 2.4 开始, AOF 重写由 Redis 自行触发, BGREWRITEAOF 仅仅用于手动触发重写操作。

语法

redis Bgrewriteaof 命令基本语法如下:

	
  1. redis 127.0.0.1:6379> BGREWRITEAOF

可用版本

>= 1.0.0

返回值

反馈信息。

实例

	
  1. redis 127.0.0.1:6379>
  2. Background append only file rewriting started

Redis Save 与 BGSAVE 的区别

一,save保存数据到磁盘的方式:

Redis Save 命令执行一个同步保存操作,将当前 Redis 实例的所有数据快照(snapshot)以 RDB 文件的形式保存到硬盘。

语法
redis Save 命令基本语法如下:

redis 127.0.0.1:6379> SAVE

返回值

保存成功时返回 OK 。

 

二,BGSAVE保存数据到磁盘的方式:

BGSAVE 命令执行之后立即返回 OK ,然后 Redis fork 出一个新子进程,原来的 Redis 进程(父进程)继续处理客户端请求,而子进程则负责将数据保存到磁盘,然后退出。

客户端可以通过 LASTSAVE 命令查看相关信息,判断 BGSAVE 命令是否执行成功。

 

时间复杂度:

O(N), N 为要保存到数据库中的 key 的数量。

案例:

redis> BGSAVE
Background saving started

 

 

三,结论

SAVE  保存是阻塞主进程,客户端无法连接redis,等SAVE完成后,主进程才开始工作,客户端可以连接

BGSAVE  是fork一个save的子进程,在执行save过程中,不影响主进程,客户端可以正常链接redis,等子进程fork执行save完成后,通知主进程,子进程关闭。很明细BGSAVE方式比较适合线上的维护操作,两种方式的使用一定要了解清楚在谨慎选择。

1.Master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务,所以Master最好不要写内存快照。

 

2.Master AOF持久化,如果不重写AOF文件,这个持久化方式对性能的影响是最小的,但是AOF文件会不断增大,AOF文件过大会影响Master重启的恢复速度。

 

3.Master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,出现短暂服务暂停现象。

下面是我的一个实际项目的情况,大概情况是这样的:一个Master,4个Slave,没有Sharding机制,仅是读写分离,Master负责写入操作和AOF日志备份,AOF文件大概5G,Slave负责读操作,当Master调用BGREWRITEAOF时,Master和Slave负载会突然陡增,Master的写入请求基本上都不响应了,持续了大概5分钟,Slave的读请求过也半无法及时响应,Master和Slave的服务器负载图如下:

 

Master Server load:

 

Slave server load: 

 

上面的情况本来不会也不应该发生的,是因为以前Master的这个机器是Slave,在上面有一个shell定时任务在每天的上午10点调用BGREWRITEAOF重写AOF文件,后来由于Master机器down了,就把备份的这个Slave切成Master了,但是这个定时任务忘记删除了,就导致了上面悲剧情况的发生,原因还是找了几天才找到的。

 

no-appendfsync-on-rewrite的配置设为yes可以缓解这个问题,设置为yes表示rewrite期间对新写操作不fsync,暂时存在内存中,等rewrite完成后再写入。最好是不开启Master的AOF备份功能。

 

4.Redis主从复制的性能问题,第一次Slave向Master同步的实现是:Slave向Master发出同步请求,Master先dump出rdb文件,然后将rdb文件全量传输给slave,然后Master把缓存的命令转发给Slave,初次同步完成。第二次以及以后的同步实现是:Master将变量的快照直接实时依次发送给各个Slave。不管什么原因导致Slave和Master断开重连都会重复以上过程。Redis的主从复制是建立在内存快照的持久化基础上,只要有Slave就一定会有内存快照发生。虽然Redis宣称主从复制无阻塞,但由于磁盘io的限制,如果Master快照文件比较大,那么dump会耗费比较长的时间,这个过程中Master可能无法响应请求,也就是说服务会中断,对于关键服务,这个后果也是很可怕的。

 

以上1.2.3.4根本问题的原因都离不开系统io瓶颈问题,也就是硬盘读写速度不够快,主进程 fsync()/write() 操作被阻塞。

 

5.单点故障问题,由于目前Redis的主从复制还不够成熟,所以存在明显的单点故障问题,这个目前只能自己做方案解决,如:主动复制,Proxy实现Slave对Master的替换等,这个也是Redis作者目前比较优先的任务之一,作者的解决方案思路简单优雅,详情可见
Redis Sentinel design draft http://redis.io/topics/sentinel-spec

 

总结:

1.Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化。

2.如果数据比较关键,某个Slave开启AOF备份数据,策略为每秒同步一次。

3.为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内。

4.尽量避免在压力较大的主库上增加从库

5.为了Master的稳定性,主从复制不要用图状结构,用单向链表结构更稳定,即主从关系为:Master<–Slave1<–Slave2<–Slave3…….,这样的结构也方便解决单点故障问题,实现Slave对Master的替换,也即,如果Master挂了,可以立马启用Slave1做Master,其他不变。

通过包管理器安装Node.js

此页面上的软件包由各自的软件包维护和支持,而不是 Node.js核心团队。请向维护人员报告遇到的任何问题。如果事实证明你的问题是Node.js本身的错误,维护人员会向上报告问题。



Arch Linux

Node.js和npm包在Community Repository中可用。

pacman -S nodejs npm 

基于Debian和Ubuntu的Linux发行版

还包括:Linux Mint的Linux Mint的Debian的版本(LMDE) elementaryOS在Windows庆典等。

Node.js可从NodeSource Debian和Ubuntu二进制发行版库(以前称为Chris Lea的 Launchpad PPA)中获得。对这个存储库及其脚本的支持可以在GitHub的nodesource / distributions上找到

注意:如果您使用的是Ubuntu Precise或Debian Wheezy,则可能需要阅读有关在较旧发行版中运行Node.js> = 6.x的信息

curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - sudo apt-get install -y nodejs 

或者,对于Node.js 9:

curl -sL https://deb.nodesource.com/setup_9.x | sudo -E bash - sudo apt-get install -y nodejs 

可选:安装构建工具

要从npm编译和安装本地插件,您可能还需要安装构建工具:

sudo apt-get install -y build-essential 

可用的体系结构:

  • i386(32位)
  • amd64(64位)
  • armhf(ARM 32位硬浮点,ARMv7及以上:arm-linux-gnueabihf

支持的Ubuntu版本:

  • Ubuntu 14.04 LTS(Trusty Tahr)
  • Ubuntu 16.04 LTS(Xenial Xerus)

支持的Debian版本:

  • Debian 7(wheezy)
  • Debian 8 / stable(jessie)
  • Debian测试(伸展,jessie别名)
  • Debian unstable(sid)

使Node.js的包也是可用的官方回购 Debian的SID(不稳定),杰西(测试)和喘息(喘鸣backports中)为“的NodeJS”。它只安装一个nodejs二进制文件。

的NodeJS遗留包安装了一个node由许多模块需要建立并正常运行的符号链接。分发官方仓库中可用的Node.js模块不需要它。

支持的Linux Mint版本:

  • Linux Mint 17“Qiana”(通过Ubuntu 14.04 LTS)
  • Linux Mint 17.1“Rebecca”(通过Ubuntu 14.04 LTS)
  • Linux Mint 17.2“Rafaela”(通过Ubuntu 14.04 LTS)
  • Linux Mint Debian Edition(LMDE)2“Betsy”(通过Debian 8)

支持的基本OS版本:

  • 初级操作系统Freya(通过Ubuntu 14.04 LTS)

支持的Trisquel版本:

  • Trisquel 7“Belenos”(通过Ubuntu 14.04 LTS)

支持的BOSS版本:

  • BOSS 5.0“Anokha”(通过Debian 7)

Enterprise Linux和Fedora

包括RedHat®EnterpriseLinux® / RHELCentOSFedora

Node.js可以从NodeSource Enterprise Linux和Fedora二进制版本库获得。对这个存储库及其脚本的支持可以在GitHub的nodesource / distributions上找到

请注意,EL 5(RHEL5和CentOS 5)的Node.js包依赖于可用EPEL存储库。如果没有安装,安装脚本将检查并提供指示。

在RHEL,CentOS或Fedora上,用于Node.js v6 LTS:

curl --silent --location https://rpm.nodesource.com/setup_8.x | sudo bash - 

另外对于Node.js 9:

curl --silent --location https://rpm.nodesource.com/setup_9.x | sudo bash - 

然后安装:

sudo yum -y install nodejs 

可选:安装构建工具

要从npm编译和安装本地插件,您可能还需要安装构建工具:

sudo yum install gcc-c++ make # or: sudo yum groupinstall 'Development Tools' 

可用的体系结构:

  • i386(32位,不适用于EL7)
  • x86_64(64位)

支持的RedHat®EnterpriseLinux®版本:

  • RHEL 5(32位和64位)
  • RHEL 6(32位和64位)
  • RHEL 7(64位)

支持的CentOS版本:

  • CentOS 5(32位和64位)
  • CentOS 6(32位和64位)
  • CentOS 7(64位)

支持的CloudLinux版本:

  • CloudLinux 6(32位和64位)

支持的Fedora版本:

  • Fedora 21(二十一)(32位和64位)
  • Fedora 20(Heisenbug)(32位和64位)
  • Fedora 19(Schrödinger’s Cat)(32位和64位)

其他已知支持的发行版本:

  • Oracle Linux(非常密切地反映了RHEL)
  • 亚马逊Linux(2016.03测试)

备择方案

官方Fedora Node.jsnpm软件包在Fedora 18和更高版本中可用。安装时使用:

sudo dnf install nodejs 

急于获得最新的更新? 从更新 – 测试中抓取它们。

Enterprise Linux(RHEL和CentOS)用户可以使用EPEL存储库中的Node.js和npm包

为您的版本安装相应的epel-release RPM(在EPEL存储库主页上找到),然后运行:

sudo yum install nodejs npm --enablerepo=epel 

急于获得最新的更新? 抓住他们从epel测试。

可用的体系结构:

  • i686(32位,不适用于EL7)
  • x86_64(64位)
  • armv6hl(树莓派,只有Pidora
  • armv7hl(32位ARM hard-float,ARMv7及更高版本,仅限Fedora)

支持的RedHat®EnterpriseLinux®版本:

  • RHEL 6(i686 / x86_64)
  • RHEL 7(x86_64)

通过EPEL不再支持RHEL 6,但可以使用Red Hat软件集合

另外,与上述RHEL版本相对应CentOSScientific Linux版本也被所有EPEL软件包(包括nodejs)正式支持。由于以前向epel-devel邮件列表报告的严重不兼容问题,Amazon Linux并未得到EPEL的正式支持,但您可能会发现nodejs至少仍然有效。

支持的Fedora版本:

  • Fedora Rawhide(i686 / x86_64 / armv7hl / aarch64 / ppc64 / ppc64le / s390x)
  • Fedora 26(i686 / x86_64 / armv7hl / aarch64 / ppc64 / ppc64le)
  • Fedora 25(i686 / x86_64 / armv7hl)
  • Fedora 24(i686 / x86_64 / armv7hl)

FreeBSD和OpenBSD

Node.js可以通过ports系统使用。

FreeBSD

/usr/ports/www/node 

OpenBSD

/usr/ports/lang/node 

开发版本也可以在FreeBSD上使用端口

cd /usr/ports/www/node-devel/ && make install clean 

或FreeBSD上的软件包:

pkg_add -r node-devel 

在FreeBSD上使用pkg-ng

pkg install node 

或者开发版本:

pkg install node-devel 

在OpenBSD上使用pkg_add

pkg_add node 

Gentoo的

在portage树中可以使用Node.js。

emerge nodejs 

NetBSD的

Node.js在pkgsrc树中可用:

cd /usr/pkgsrc/lang/nodejs && make install 

或者使用pkgin安装二进制包(如果适用于您的平台):

pkgin -y install nodejs 

NVM

节点版本管理器是一个bash脚本,用于管理多个发布的Node.js版本。它允许您执行像安装,卸载,切换版本等操作。要安装nvm,请使用此安装脚本

在Unix / OS X系统上,从源代码构建的Node.js可以使用 nvm安装到nvm所期望的位置:

$ env VERSION=`python tools/getnodeversion.py` make install DESTDIR=`nvm_version_path v$VERSION` PREFIX="" 

之后,您可以使用nvm从源代码构建的发行版本和版本之间切换。例如,如果Node.js的版本是v8.0.0-pre:

$ nvm use 8 

一旦官方发布出来,你会想要卸载从源代码构建的版本:

$ nvm uninstall 8 

openSUSE和SLE

Node.js在以下软件包的主要存储库中可用:

  • openSUSE Leap 42.2nodejs4
  • openSUSE的飞跃42.3nodejs4nodejs6
  • openSUSE的Tumbleweed公司nodejs4nodejs6nodejs8
  • SUSE Linux企业服务器(SLES)12 1nodejs4nodejs6

1:安装前必须添加 “Web和脚本模块” 

例如,要在openSUSE Leap 42.2上安装Node.js 4.x,请以root用户身份运行以下命令:

zypper install nodejs4 

苹果系统

只需nodejs.org网站直接下载Macintosh Installer 即可

如果你想用bash下载包:

curl "https://nodejs.org/dist/latest/node-${VERSION:-$(wget -qO- https://nodejs.org/dist/latest/ | sed -nE 's|.*>node-(.*)\.pkg</a>.*|\1|p')}.pkg" > "$HOME/Downloads/node-latest.pkg" && sudo installer -store -pkg "$HOME/Downloads/node-latest.pkg" -target "/" 

备择方案

使用自制软件

brew install node 

使用MacPorts

port install nodejs<major version> # Example port install nodejs7 

使用pkgsrc

安装二进制包:

pkgin -y install nodejs 

或者从pkgsrc手动构建:

cd pkgsrc/lang/nodejs && bmake install 

SmartOS和Illumos

SmartOS图像预先安装了pkgsrc。在其他Illumos发行版中,首先安装pkgsrc,然后你可以像平常一样安装二进制包:

pkgin -y install nodejs 

或者从pkgsrc手动构建:

cd pkgsrc/lang/nodejs && bmake install 

无效的Linux

Void Linux在主存储库中提供了稳定的node.js。

xbps-install -Sy nodejs 

视窗

只需nodejs.org网站直接下载Windows安装程序即可

备择方案

使用巧克力

cinst nodejs # or for full install with npm cinst nodejs.install 

使用Scoop

scoop install nodejs

一个JAVASCRIPT的MPEG1视频和MP2音频解码器JSMpeg

一个JAVASCRIPT的MPEG1视频和MP2音频解码器

JSMpeg是用JavaScript编写的视频播放器。它由MPEG-TS分配器,MPEG1视频和MP2音频解码器,WebGL和Canvas2D渲染器以及WebAudio声音输出组成。JSMpeg可以通过Ajax加载静态文件,并通过WebSocktes实现低延迟流(〜50ms)。

JSMpeg可以在iPhone 5S上以30fps解码720p视频,适用于任何现代浏览器(Chrome,Firefox,Safari和Edge),并以20kb的格式进行压缩。

使用它可以这样简单:

< script  src =  jsmpeg.min.js  > </ script > < div  class =  jsmpeg   data-url =  video.ts  > </ div >

下载

低延迟的视频和音频流,无处不在 – 是的,即使在IPHONE上

JSMpeg可以连接到发送二进制MPEG-TS数据的WebSocket服务器。这些数据来自哪里,取决于你。

延迟时间仅取决于您的来源,网络条件以及您的浏览器,GPU和显示器可以吐出帧的速度。对于本地网络上的屏幕截图,它可以低至50ms。

最简单的方法之一就是使用 ffmpeg一个小型的WebSocket服务器。有关 详细信息,请参阅github上的 文档

使用JSMPEG和进一步阅读的项目


JSMpeg – JavaScript中的MPEG1视频和MP2音频解码器

JSMpeg是用JavaScript编写的视频播放器。它由MPEG-TS分路器,MPEG1视频和MP2音频解码器,WebGL和Canvas2D渲染器以及WebAudio声音输出组成。JSMpeg可以通过Ajax加载静态视频,并通过WebSockets实现低延迟流(〜50ms)。

JSMpeg可以在iPhone 5S上以30fps的速度解码720p视频,适用于任何现代浏览器(Chrome,Firefox,Safari,Edge),并且只需要20KB的压缩文件。

使用它可以这样简单:

< script  src =  jsmpeg.min.js  > </ script > < div  class =  jsmpeg   data-url =  video.ts  > </ div >

一些更多的信息和演示:jsmpeg.com

用法

JSMpeg视频播放器可以使用jsmpeg容器的CSS类在HTML中创建

< div  class =  jsmpeg   data-url =  <url>  > </ div >

或者直接JSMpeg.Player()在JavaScript中调用构造函数:

var player =  new  JSMpeg.Player(url [,options]);

请注意,使用HTML元素(内部JSMpeg.VideoElement)提供了一些功能JSMpeg.Player即一个SVG暂停/播放按钮,并能够在iOS设备上“解锁”音频。

url参数接受一个URL到MPEG的.ts文件或网页套接字服务器(WS:// …)。

options参数支持以下属性:

  • canvas – 用于视频渲染的HTML Canvas元素。如果没有提供,渲染器将创建自己的画布元素。
  • loop – 是否循环播放视频(仅限静态文件)。默认true
  • autoplay – 是否立即开始播放(仅限静态文件)。默认false
  • audio – 是否解码音频。默认true
  • video – 是否解码视频。默认true
  • poster – 在视频播放前用作海报的图像的URL。
  • pauseWhenHidden – 选项卡处于非活动状态时是否暂停播放。默认true请注意,浏览器通常在非活动选项卡上调节JS。
  • disableGl – 是否禁用WebGL并始终使用Canvas2D渲染器。默认false
  • preserveDrawingBuffer– WebGL上下文是否创建preserveDrawingBuffer– 通过“屏幕截图”需要canvas.toDataURL()默认false
  • progressive – 是否以块(仅限静态文件)加载数据。启用时,可以在整个源完全加载之前开始播放。默认true
  • throttled– 使用时progressive,是否推迟加载块,当他们不需要播放呢。默认true
  • chunkSize– 使用时progressive,以字节为单位的块大小一次加载。默认1024*1024(1mb)。
  • decodeFirstFrame – 是否解码并显示视频的第一帧。用于设置画布大小,并使用该框架作为“海报”图像。这在使用autoplay或流媒体源时不起作用默认true
  • maxAudioLag – 流式传输时,以秒为单位的最大入队音频长度。
  • videoBufferSize – 流传输时,视频解码缓冲区的大小(以字节为单位)。默认512 * 1024(512kb)。您可能需要增加非常高的比特率。
  • audioBufferSize – 流式传输时,音频解码缓冲区的大小(以字节为单位)。默认128 * 1024(128kb)。您可能需要增加非常高的比特率。

除了from之外的所有选项canvas也可以通过data-属性与HTML Element一起使用例如,要在JavaScript中指定循环和自动播放:

var player =  new  JSMpeg.Player' video.ts ' {loop  true,autoplay  true });

或HTML

< div  class =  jsmpeg   data-url =  video.ts   data-loop =  true   data-autoplay =  true  > </ div >

请注意,camelCased用作数据属性时选项必须使用连字符。例如decodeFirstFrame: true成为data-decode-first-frame="true"HTML元素。

JSMpeg.Player API

一个JSMpeg.Player实例支持以下方法和属性:

  • .play() – 开始播放
  • .pause() – 暂停播放
  • .stop() – 停止播放并寻求开始
  • .destroy() – 停止播放,断开源代码并清理WebGL和WebAudio状态。玩家以后不能使用。
  • .volume – 获取或设置音量(0-1)
  • .currentTime – 以秒为单位获取或设置当前播放位置

为JSMpeg编码视频/音频

JSMpeg只支持MPEG1视频编解码器和MP2音频编解码器的MPEG-TS容器播放。视频解码器不能正确处理B帧(尽管现在的编码器似乎没有默认使用这些),视频的宽度必须是2的倍数。

你可以使用ffmpeg编码一个合适的视频,如下所示:

ffmpeg -i in.mp4 -f mpegts -codec:v mpeg1video -codec:a mp2 -b 0 out.ts

您还可以控制视频大小(-s),帧率(-r),视频比特率(-b:v),音频比特率(-b:a),音频通道数量(-ac),采样率(-ar)等等。有关详细信息,请参阅ffmpeg文档。

综合例子:

ffmpeg -i in.mp4 -f mpegts \ -codec:v mpeg1video -s 960x540 -b:v 1500k -r 30 -bf 0 \ -codec:a mp2 -ar 44100 -ac 1 -b:a 128k \ out.ts

性能考虑

尽管JSMpeg甚至可以在iPhone 5S上以30fps处理720p视频,但请记住,MPEG1并不像现代编解码器那样高效。MPEG1需要相当多的高清视频带宽。720p在2 Mbits / s(250kb / s)时开始显示正常。而且,比特率越高,JavaScript解码的工作就越多。

这不应该是一个静态文件的问题,或者如果你只在你的本地WiFi流。如果您不需要支持移动设备,那么10mbit / s的1080p就可以正常工作(如果您的编码器能够继续使用)。对于其他一切,我建议您使用最大2Mbit / s的540p(960×540)。

通过WebSockets流媒体

JSMpeg可以连接到发送二进制MPEG-TS数据的WebSocket服务器。在流式传输时,JSMpeg会尽可能降低延迟 – 它会立即解码所有内容,忽略视频和音频时间戳。为了使所有内容保持同步(以及延迟较低),音频数据应该非常频繁地在视频帧之间交错(-muxdelay在ffmpeg中)。

一个单独的,缓冲的流模式,其中JSMpeg预加载数秒的数据,并提供准确的时间和音频/视频同步的一切是可以想象的,但目前尚未实现。

视频和音频的内部缓冲区相当小(分别为512kb和128kb),JSMpeg将丢弃旧的(甚至未播放的)数据,为新到达的数据腾出空间,而不会有太多模糊。这可能在网络拥塞时引入解码伪像,但确保延迟保持在最低限度。如有必要,您可以增加videoBufferSizeaudioBufferSize通过选项。

JSMpeg附带一个用Node.js编写的小型WebSocket“relay”。该服务器通过HTTP接受MPEG-TS源,并通过WebSocket将其提供给所有连接的浏览器。传入的HTTP流可以使用ffmpeggstreamer或其他方式生成。

源和WebSocket中继之间的拆分是必要的,因为ffmpeg不会说WebSocket协议。但是,这种拆分还允许您在公共服务器上安装WebSocket中继,并在Internet上共享您的流(通常,路由器中的NAT会阻止公共Internet连接本地网络)。

总之,它的工作原理是这样的:

  1. 运行websocket-relay.js
  2. 运行ffmpeg,将输出发送到中继的HTTP端口
  3. 将浏览器中的JSMpeg连接到中继的Websocket端口

流的示例设置:Raspberry Pi Live网络摄像头

对于这个例子,ffmpeg和WebSocket中继在同一个系统上运行。这使您可以在本地网络中查看流,但不能在公共网络上查看。

这个例子假定你的网络摄像机与Video4Linux2兼容,并且出现/dev/video0在文件系统中。大多数USB摄像头支持UVC标准,应该工作得很好。通过加载内核模块,板载树莓相机可以作为V4L2设备使用:sudo modprobe bcm2835-v4l2

  1. 安装ffmpeg(请参阅如何在Debian / Raspbian上安装ffmpeg)。使用ffmpeg,我们可以捕捉网络摄像头的视频和音频,并将其编码成MPEG1 / MP2。

  2. 安装Node.js和npm(请参阅在基于Debian和Ubuntu的Linux发行上安装Node.js以获得更新的版本)。Websocket中继是用Node.js编写的

  3. 安装http-server。我们将使用它来提供静态文件(view-stream.html,jsmpeg.min.js),以便我们可以在浏览器中用视频查看网站。任何其他网络服务器也可以工作(nginx,apache等): sudo npm -g install http-server

  4. 安装git并克隆这个仓库(或者直接将它下载为ZIP并解压)

sudo apt-get install git git clone https://github.com/phoboslab/jsmpeg.git 
  1. 转到jsmpeg /目录 cd jsmpeg/

  2. 安装Node.js Websocket库: npm install ws

  3. 启动Websocket中继。为输入的HTTP视频流和我们可以在浏览器中连接的Websocket端口提供密码和端口: node websocket-relay.js supersecret 8081 8082

  4. 在一个新的终端窗口(仍然在jsmpeg/目录中,启动,http-server所以我们可以服务view-stream.html到浏览器: http-server

  5. 在浏览器中打开流式传输网站。http-server会告诉你的IP(通常192.168.[...])和端口(通常8080)在哪里运行:http://192.168.[...]:8080/view-stream.html

  6. 在第三个终端窗口中,启动ffmpeg来捕捉摄像头视频并将其发送到WebSocket中继。在目标网址中提供密码和端口(从第7步开始):

ffmpeg \ -f v4l2 \ -framerate 25 -video_size 640x480 -i /dev/video0 \ -f mpegts \ -codec:v mpeg1video -s 640x480 -b:v 1000k -bf 0 \ http://localhost:8081/supersecret 

您现在应该在您的浏览器中看到一个活的摄像头图像。

如果ffmpeg无法打开输入视频,则可能是因为您的摄像头不支持给定的分辨率,格式或帧速率。要获得兼容模式的列表,请运行:

ffmpeg -f v4l2 -list_formats all -i /dev/video0

要添加摄像头音频,只需使用两个独立的输入调用ffmpeg即可。

ffmpeg \ -f v4l2 \ -framerate 25 -video_size 640x480 -i /dev/video0 \ -f alsa \ -ar 44100 -c 2 -i hw:0 \ -f mpegts \ -codec:v mpeg1video -s 640x480 -b:v 1000k -bf 0 \ -codec:a mp2 -b:a 128k \ -muxdelay 0.001 \ http://localhost:8081/supersecret 

注意这个muxdelay论点。这应该会减少延迟,但在流式传输视频和音频时并不总是有效 – 请参阅下面的注释。

关于fmpeg muxing和延迟的一些评论

将音频流添加到MPEG-TS有时会引起相当大的延迟。我特别发现这是使用ALSA和V4L2的Linux上的一个问题(在macOS上使用AVFoundation工作得很好)。但是,有一个简单的解决方法:只运行ffmpeg的两个实例。一个是音频,一个是视频。发送两个输出到相同的Websocket中继。由于MPEG-TS格式的简单性,两个流的适当的“混合”在继电器中自动发生。

ffmpeg \ -f v4l2 \ -framerate 25 -video_size 640x480 -i /dev/video0 \ -f mpegts \ -codec:v mpeg1video -s 640x480 -b:v 1000k -bf 0 \ -muxdelay 0.001 \ http://localhost:8081/supersecret  # In a second terminal ffmpeg \ -f alsa \ -ar 44100 -c 2 -i hw:0 \ -f mpegts \ -codec:a mp2 -b:a 128k \ -muxdelay 0.001 \ http://localhost:8081/supersecret 

在我的测试中,USB摄像头引入了大约180ms的延迟,似乎我们无能为力。树莓派然而有一个摄像头模块,提供较低的延迟视频采集。

要使用ffmpeg捕获Windows或MacOS上的网络摄像头输入,请参阅ffmpeg Capture / Webcam Wiki

JSMpeg架构和内部

这个库建立在一个相当模块化的方式,同时保持在最低限度的开销。应该可以实现新的分配器,解码器,输出(渲染器,音频设备)或信号源,而无需更改任何其他部分。但是,您仍然需要继承JSMpeg.Player以使用任何新的模块。

查看一下jsmpeg.js源代码,了解这些模块如何互连以及应该提供哪些API。我还写了一篇关于JSMpeg内部部分的博文:解码就像是1999年

使用库的一部分而不创建一个完整的播放器也应该相当简单。例如,您可以创建一个独立的JSMpeg.Decoder.MPEG1Video实例.connect()一个渲染器,.write()一些数据和.decode()一个框架,而不需要触及JSMpeg的其他部分。

以前的版本

目前生活在这个回购的JSMpeg版本是完全重写原始的jsmpeg库,只能够解码原始mpeg1video。如果您正在查找旧版本,请参阅v0.2标签

php安装swoole扩展

swoole是一个PHP的异步、并行、高性能网络通信引擎,使用纯C语言编写,提供了PHP语言的异步多线程服务器,异步TCP/UDP网络客户端,异步MySQL,异步Redis,数据库连接池,AsyncTask,消息队列,毫秒定时器,异步文件读写,异步DNS查询。
Swoole内置了Http/WebSocket服务器端/客户端、Http2.0服务器端。
Swoole可以广泛应用于互联网、移动通信、企业软件、云计算、网络游戏、物联网(IOT)、车联网、智能家居等领域。 使用PHP+Swoole作为网络通信框架,可以使企业IT研发团队的效率大大提升,更加专注于开发创新产品。

注意事项:
1、server.php中的ip地址必须是外网可访问地址 123.57.232.99,不能为localhost

1、安装

全部版本链接:https://pecl.php.net/package/swoole

# wget https://github.com/swoole/swoole-src/archive/swoole-1.7.6-stable.tar.gz

# tar zxvf swoole-1.7.6-stable.tar.gz

# cd swoole-src-swoole-1.7.6-stable

# /usr/local/php/bin/phpize

  1. #./configure  --enable-zip --with-php-config=/usr/local/php/bin/php-config 
  2. # make
  3. # make install

提示:
Build complete.
Don’t forget to run ‘make test’.

Installing shared extensions: /usr/lib64/php/modules/
说明安装成功

2、php加载swoole扩展

extension=/xxx/xxx/php5.6/lib/php/extensions/no-debug-non-zts-20131226/swoole.so

3、重启服务
service php-fpm restart

4、测试,查看phpinfo信息,如下图所示:

5、代码测试

server.php代码:

# telnet 123.57.232.99 55152
  • 1

Trying 123.57.232.99…
Connected to 123.57.232.99.
Escape character is ‘^]’.
rr
Swoole: rr
测试
Swoole: 测试

官网方式参考(php7.2.19)使用了这个方式:

安装Swoole框架和扩展

Swoole扩展

到GitHub首页下载Swoole扩展源码,地址:https://github.com/swoole/swoole-src 下载后按照标准的PHP扩展编译方式进行编译和安装。一般是

phpize
./configure
make install 

编译安装完后,修改php.ini加入extension=swoole.so开启swoole扩展。也可以通过dl(‘swoole.so’)动态载入,推荐修改php.ini。


下载swoole_framework源码,地址:https://github.com/swoole/framework。放置到您的workspace目录中即可。swoole_framework是PHP代码,只需要require/include即可,无需编译和安装。