hhhzua 发布的文章

今天上传一些图片到我们的网站上,发现有些图片上传后没有任何提示就报错500,调试一下发现是在做图片处理的时候报错的,查日志后发现如下提示:

FastCGI sent in stderr: "PHP message: PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 8192 bytes)

原来是内存溢出了,可是上传的图片都不大,因为网站限制上传文件不能超过10M,而ini配置文件中的上传限制和NGINX服务器的配置文件的上传限制都远大于10M,怎么还会内存溢出???

然后一番检索发现有位仁兄提出一个图片占用内存的公式:

(图片对象的width和height )X(图片的通道数,一般是3)X 1.7

按这个计算,我上传的4.2M的图片(6577 × 4385)占了140M,而默认的内存限制是128M,妥妥的超过了,不过这个公式应该是估算,实际报错提示占用了128.0078125M,也就刚好超过128M,离140M差得有点多,不过多次测试结果表明只要按这个公式计算结果小于134217728就不会内存溢出。

所以,方案是加上一个限制:长不超过6000px,宽不超过4000px,因为这个尺寸按上面的公式计算内存占用超不多116M。

我的个人博客:逐步前行STEP

NFS启动时会随机启动多个端口并向RPC注册,为了设置安全组以及iptables规则,需要设置NFS固定端口。
NFS服务需要开启 mountd,nfs,nlockmgr,portmapper,rquotad这5个服务,其中nfs、portmapper的端口是固定的,另外三个服务的端口是随机分配的,所以需要给mountd,nlockmgr,rquotad设置固定的端口。
其中,给mountd、rquotad设置端口的方式很简单,在/etc/sysconfig/nfs中添加一下设置即可:

RQUOTAD_PORT=30001
LOCKD_TCPPORT=30002
LOCKD_UDPPORT=30002
MOUNTD_PORT=30003
STATD_PORT=30004

重启rpc、nfs的配置与服务:

systemctl restart rpcbind.service
systemctl restart nfs.service

查看端口使用情况:

rpcinfo -p

可以看到mountd服务已经使用了配置的端口,但是nlockmgr的端口还是随机的,还需在/etc/modprobe.d/lockd.conf中添加以下设置:

options lockd nlm_tcpport=30002
options lockd nlm_udpport=30002

重新加载NFS配置和服务:

systemctl restart nfs-config
systemctl restart nfs-idmap
systemctl restart nfs-lock
systemctl restart nfs-server

然后重启服务器,nlockmgr的端口就是固定的端口了。

我的个人博客:逐步前行STEP

有一个使用laravel框架的项目,采用laravel自带的文件管理系统,还有一个使用laravel-admin扩展的管理端,更是依赖于自带的文件管理系统。因部署了多台服务器,需要打通数据,考虑了各种方案,比如fastdfs、oss,初步了解后发现无法完全满足需求:
fastdfs:在文件的存取上保证了一致的路径,用户端的上传和图片压缩都影响不大,只要最终把文件上传到fastdfs就行,但是laravel-admin中对图片上传封装得比较深,要改成上传到fastdfs中的话,工作量比较大,而且感觉很难做到,比较文件上传组件是通用的,除非自己重写一下文件上传组件,感觉难度比较大。
oss:现有的条件下要使用OSS得另行购买,而且同样存在上面的问题。

经过研究确定,必须有一个共享文件存储的东西,并且可以和现有的项目无缝衔接,存取方式,存储路径都不变,才能以最小的开发成本打通这几个项目的数据。
经过一番搜索,发现了别人类似需求的解决方案:NFS。
NFS就是网络文件系统,跟我们在windows上开放共享文件是一样效果的,虽然实际存储的位置在另外的服务器上,但是可以配置和当前一样的访问路径,这种中心存储模式和fastdfs的分布式存储刚好相反,不过我觉得可以在NFS服务器上搞fastdfs以便实现文件的冗余备份和分布式存储这样易于扩展容量。

下面是我配置的过程中的一些关键步骤:
1、首先关闭防火墙(生产环境下可以应该开启防火墙保证安全,然后开放相关端口)
2、首先安装 nfs-utils ,rpcbind

 yum -y install nfs-utils ,rpcbind

3、禁用selinux
(以上三步需在服务端、客户端都执行)
4、编写服务端配置:vi /etc/exports
写入:

/data/share ip(rw,sync,wdelay,hide,no_subtree_check,sec=sys,secure,root_squash,no_all_squash)

该配置的选项说明:

ro:共享目录只读
rw:共享目录可读可写

all_squash:所有访问用户都映射为匿名用户或用户组
no_all_squash(默认):访问用户先与本机用户匹配,匹配失败后再映射为匿名用户或用户组
root_squash(默认):将来访的root用户映射为匿名用户或用户组
no_root_squash:来访的root用户保持root帐号权限
anonuid=<UID>:指定匿名访问用户的本地用户UID,默认为nfsnobody(65534)
anongid=<GID>:指定匿名访问用户的本地用户组GID,默认为nfsnobody(65534)
secure(默认):限制客户端只能从小于1024的tcp/ip端口连接服务器
insecure:允许客户端从大于1024的tcp/ip端口连接服务器
sync:将数据同步写入内存缓冲区与磁盘中,效率低,但可以保证数据的一致性
async:将数据先保存在内存缓冲区中,必要时才写入磁盘
wdelay(默认):检查是否有相关的写操作,如果有则将这些写操作一起执行,这样可以提高效率
no_wdelay:若有写操作则立即执行,应与sync配合使用
subtree_check(默认) :若输出目录是一个子目录,则nfs服务器将检查其父目录的权限
no_subtree_check :即使输出目录是一个子目录,nfs服务器也不检查其父目录的权限,这样可以提高效率

该配置修改后执行exportfs -r以便重载该配置
5、启动rpc ,nfs

systemctl start   rpcbind.service      
systemctl start  nfs.service

nfs需要向rpc注册,rpc一旦重启,注册的文件都丢失,向他注册的服务都需要重启,注意启动顺序一定是先rpc再nfs
6、设置NFS服务开机启动

systemctl enable rpcbind.service
systemctl enable nfs.service

7、查看rpc ,nfs状态

systemctl status rpcbind.service
systemctl status nfs.service

8、查看NFS服务需要开启的端口,并在安全组中设置
rpcinfo -p

portmapper在NFS服务启动的时候给每一个NFS服务分配了一个动态的端口,如果重启的话端口又会变的,所以需要固定NFS的端口,目前的话只是测试使用NFS就不配置固定端口了,以后再说

9、检查服务端、客户端是否配置成功
showmount -e 服务端ip
(步骤8、9需在服务端、客户端都操作)
如果显示出:

Export list for ip:XXXXXXX

就表明配置正确可以正常连接了。
10、在客户端挂载服务端的共享目录

mount -t nfs 服务端ip:/data/share       /data/share

11、设置客户端开机自动挂载共享目录:
在root用户下:

vi /etc/fstab
 新增:服务端IP:/data/share  /data/share

12、卸载共享目录

 umount /data/share

如果执行该命令后提示:device is busy,则强制卸载:

umount -fl  /data/share

我的个人博客:逐步前行STEP

为了防止图片盗用,禁止外链以及禁止地址栏直接访问图片是必不可少的方案,当然这样的限制还比较基础,还是有别的途径可以盗图的,更多的限制之后会追加,现在先做好这两个基础防护。

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
            valid_referers server_names  *.abc.com *.abc.cn *.so.com *.baidu.com *.bing.com *.google.com *.sogou.com xx.xxx.xxx.xxx;
            if ($invalid_referer) {
                #rewrite ^/ http://www.abc.com/403.jpg;
                return 403;
            }
            root           /home/laravel/public;
            expires 30d;
        }

备注:
valid_referers:设置合法的referer列表,值可以是域名(不带协议头)、IP、server_names(表示当前域名)、正则表达式
$invalid_referer:当不符合valid_referers列表时,该值为1
expires:图片的浏览器的缓存时间