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,关闭默认防火墙
Nginx模块GeoIP查询IP所在国家、城市,查询某个ip位置
地理位置数据在业务中有重要作用,这些数据可以用于向某些人群推广品牌、产品或服务,还有助于增强用户体验。
本文讲述仅通过配置Nginx加上GeoIP MaxMind数据库,就能获得用户IP地址的实际物理位置,而无需编写任何代码。
Nginx是一个开源的HTTP和IMAP/POP3代理服务器,主要用作Web服务器或反向代理服务器。Nginx的GeoIP模块(即ngx_http_geoip_module)使用了预编译的MaxMind数据库来设置变量,比如变量
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 #经度
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 命令基本语法如下:
- redis 127.0.0.1:6379> BGREWRITEAOF
可用版本
>= 1.0.0
返回值
反馈信息。
实例
- redis 127.0.0.1:6379>
- 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
- 基于Debian和Ubuntu的Linux发行版
- Enterprise Linux和Fedora
- FreeBSD和OpenBSD
- Gentoo的
- NetBSD的
- NVM
- openSUSE和SLE
- 苹果系统
- SmartOS和Illumos
- 无效的Linux
- 视窗
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® / RHEL,CentOS和Fedora。
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.js和npm软件包在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版本相对应的CentOS和Scientific 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.2:
nodejs4
-
openSUSE的飞跃42.3:
nodejs4
,nodejs6
-
openSUSE的Tumbleweed公司:
nodejs4
,nodejs6
,nodejs8
-
SUSE Linux企业服务器(SLES)12 1:
nodejs4
,nodejs6
例如,要在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 >
下载
-
jsmpeg.min.js 70kb
缩小,20kb gzipped。 -
github.com/phoboslab/jsmpeg
源代码和文档
低延迟的视频和音频流,无处不在 – 是的,即使在IPHONE上
JSMpeg可以连接到发送二进制MPEG-TS数据的WebSocket服务器。这些数据来自哪里,取决于你。
延迟时间仅取决于您的来源,网络条件以及您的浏览器,GPU和显示器可以吐出帧的速度。对于本地网络上的屏幕截图,它可以低至50ms。
最简单的方法之一就是使用 ffmpeg
一个小型的WebSocket服务器。有关 详细信息,请参阅github上的 文档。
使用JSMPEG和进一步阅读的项目
-
解码它就像是1999年
JSMpeg的发展各种有趣的一点 -
JSMpeg – Fronteers 2015,Dominic Szablewski
谈谈MPEG1编解码器的内部工作原理 -
即时网络摄像头
将视频从iPhone / iPad流式传输到Wi-Fi上的任何浏览器 -
jsmpeg-vnc
通过浏览器控制你的Windows PC
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将丢弃旧的(甚至未播放的)数据,为新到达的数据腾出空间,而不会有太多模糊。这可能在网络拥塞时引入解码伪像,但确保延迟保持在最低限度。如有必要,您可以增加videoBufferSize
和audioBufferSize
通过选项。
JSMpeg附带一个用Node.js编写的小型WebSocket“relay”。该服务器通过HTTP接受MPEG-TS源,并通过WebSocket将其提供给所有连接的浏览器。传入的HTTP流可以使用ffmpeg,gstreamer或其他方式生成。
源和WebSocket中继之间的拆分是必要的,因为ffmpeg不会说WebSocket协议。但是,这种拆分还允许您在公共服务器上安装WebSocket中继,并在Internet上共享您的流(通常,路由器中的NAT会阻止公共Internet连接到本地网络)。
总之,它的工作原理是这样的:
- 运行websocket-relay.js
- 运行ffmpeg,将输出发送到中继的HTTP端口
- 将浏览器中的JSMpeg连接到中继的Websocket端口
流的示例设置:Raspberry Pi Live网络摄像头
对于这个例子,ffmpeg和WebSocket中继在同一个系统上运行。这使您可以在本地网络中查看流,但不能在公共网络上查看。
这个例子假定你的网络摄像机与Video4Linux2兼容,并且出现/dev/video0
在文件系统中。大多数USB摄像头支持UVC标准,应该工作得很好。通过加载内核模块,板载树莓相机可以作为V4L2设备使用:sudo modprobe bcm2835-v4l2
。
-
安装ffmpeg(请参阅如何在Debian / Raspbian上安装ffmpeg)。使用ffmpeg,我们可以捕捉网络摄像头的视频和音频,并将其编码成MPEG1 / MP2。
-
安装Node.js和npm(请参阅在基于Debian和Ubuntu的Linux发行版上安装Node.js以获得更新的版本)。Websocket中继是用Node.js编写的
-
安装http-server。我们将使用它来提供静态文件(view-stream.html,jsmpeg.min.js),以便我们可以在浏览器中用视频查看网站。任何其他网络服务器也可以工作(nginx,apache等):
sudo npm -g install http-server
-
安装git并克隆这个仓库(或者直接将它下载为ZIP并解压)
sudo apt-get install git git clone https://github.com/phoboslab/jsmpeg.git
-
转到jsmpeg /目录
cd jsmpeg/
-
安装Node.js Websocket库:
npm install ws
-
启动Websocket中继。为输入的HTTP视频流和我们可以在浏览器中连接的Websocket端口提供密码和端口:
node websocket-relay.js supersecret 8081 8082
-
在一个新的终端窗口(仍然在
jsmpeg/
目录中,启动,http-server
所以我们可以服务view-stream.html到浏览器:http-server
-
在浏览器中打开流式传输网站。该
http-server
会告诉你的IP(通常192.168.[...]
)和端口(通常8080
)在哪里运行:http://192.168.[...]:8080/view-stream.html
-
在第三个终端窗口中,启动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
#./configure --enable-zip --with-php-config=/usr/local/php/bin/php-config
# make
# 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即可,无需编译和安装。