如何处理视频和图像上传到存储服务器? - php

我正在开发一个应用程序(使用Go或可能使用PHP),用户需要上传照片和图像。

我已经在不同位置设置了两个ZFS(镜像)存储服务器,但是我对如何让用户最好地上传文件存有疑问。 ZFS处理配额和预留。

我在所有服务器上都运行了复制的Galera数据库,这既出于安全性考虑,也便于从每个服务器访问用户帐户。换句话说,每个服务器始终具有数据库的本地副本。所有用户仅是虚拟用户。

到目前为止,我已经测试了以下设置选项:

解决方案1

在具有虚拟用户的存储服务器上运行SFTP(带模块的ProFTPD)或FTPS(带TLS的纯FTP)。

这使人们可以使用Filezilla之类的客户端直接访问存储服务器。同时,用户还可以使用我们的Web GUI从我们的主Web服务器上载。

这种设置的一个优点是FTP服务器可以处理虚拟用户。我们的Web应用程序还将通过SFTP或FTPS发送文件。

一个缺点是FTP很麻烦,它使防火墙烦人。我也更喜欢FTP而不是SSH(SFTP),而不是TLS之上的FTP(FTPS)。但是,只有ProFTPD具有用于SSH的模块,但与PureFTPd相比,使用它确实很痛苦(很多问题,包括无法使用的配置选项和文件权限错误),但是PureFTPd仅支持TLS。

不能使用真实的SSH / SCP帐户运行并使用PAM。

解决方案2

使用NFS或CIFS在Web服务器上本地安装存储服务器(Samba非常适合自动恢复,以防万一机器掉下来)。

在此设置中,用户只能通过我们的主Web服务器上载。然后,Web服务器应用程序以及在存储服务器上运行的应用程序需要支持可恢复的上载。我一直在研究使用tus协议。

上述两种设置的缺点是需要以某种方式管理存储容量。当存储服务器1达到最大用户数时,应用程序需要知道这一点,然后仅为存储服务器2、3等创建虚拟用户。

我已经计算出每个存储服务器可以容纳多少用户,然后让Web应用程序使用虚拟用户检查数据库,以查看何时需要将新创建的用户移至下一个存储服务器。

这是一所相当古老的学校,但是行得通。

解决方案3

与解决方案2相同(不使用FTP),但克隆我们的Web应用程序时将其上传到每个存储服务器,然后重定向用户(或为他们提供到存储服务器s1.example.com,s2.example.com等的物理链接) )

此设置的可能优点是,用户可以直接上载到已分配给他们的存储服务器,而不用经过我们的主Web服务器(防止它成为可能的瓶颈)。

解决方案4

在存储服务器上使用GlusterFS并构建可以轻松扩展的集群。我已经测试了GlusterFS,它可以很好地实现此目的。

这种设置的优点是,我实际上不需要关心文件在物理上在哪些存储服务器上运行,并且可以通过向群集添加更多服务器来轻松扩展存储。

但是,这里的缺点是我们的主Web服务器可能再次成为瓶颈。

我还考虑过添加一个负载平衡器,然后使用多个Web服务器,以防我们的主Web服务器成为上传文件的瓶颈。

无论如何,我更喜欢保持简单!我不喜欢添加东西。从长远来看,我希望它易于维护。

任何想法,建议和意见将不胜感激。

你怎么做呢?

参考方案

如果我们谈论文件存储,则Web应用程序应该与基础存储无关。关注点分离。

另一方面,(S)FTP(S)不是存储方法。它是一种通信协议。它并不排除您拥有共享存储。往上看。

ZFS不具备共享存储功能,因此基本上可以选择以下选项:

哪个底层文件系统?
是否要通过(S)FTP(S)提供其他访问模式?
如何使我的文件系统可在多个服务器上使用?是GlusterFS,CIFS还是NFS?

因此,让我们逐步解决。

文件系统

我知道ZFS令人着迷,但问题是这样的:例如xfs的最大文件系统大小为8 exb减去一个字节。专门的术语是“负载”。为您提供联系:国会图书馆拥有大约20TB的数字媒体-可以容纳大约40万次。即使是出色的ext4也可以容纳5万个LoC。而且,如果您拥有那么多数据,那么您的FS就是您的最小关注点。建立下两个发电厂以使您的工作正常进行。

Gist很高兴考虑,但请使用您认为合适的任何方式。我个人(几乎在LVM上)使用xfs。

其他访问方式

当然可以,为什么不呢?除了安全噩梦(特权升级,还有其他人吗?)。 ProFTPd(内置咖啡机和厨房水槽)是我将用于任何用途的最后一个FTP服务器。它具有庞大的代码库,可用于accidentally introducing vulnerabilities。

基本上,它可以归结为项目中存在的技能。你们能正确加固系统和FTP服务器并监视它的安全事件吗?除非您的答案是自信的,否则“是的,当然,有很多经验!”您应该最大程度地减少攻击面。

要点不要,除非您真的知道自己在做什么。而且,如果您不得不问,您可能不会问。没有意图冒犯,只是陈述事实。

共享文件系统

就个人而言,我对GlusterFS的体验还不完美。当涉及网络延迟和填充时,复制具有相当大的要求。简而言之:如果我们要谈论多个可用区,例如EMEA,APAC和NCSA,那几乎是不可能的。您会被困在georeplication上,这对于您描述的用例而言并不理想。

另一方面,NFS和CIFS的问题是根本没有复制,并且所有客户端都需要访问同一服务器实例才能访问数据-如果您认为需要基础ZFS来解决,这不是一个好主意。 。

全球范围内的Gist共享文件系统具有中等程度的复制滞后和访问时间,很难做到,而且价格可能非常昂贵。

哈哈,Smartypant,那么您有什么建议?

规模。慢慢来首先,您应该能够与基于文件的简单FS存储库相处。然后检查其他各种方式以进行大规模共享存储并迁移到该存储。

转向实现,我什至可以更进一步,您应该使存储成为接口:

// Storer takes the source and stores its contents under path for further reading via
// Retriever.
type Storer interface {
    StreamTo(path string, source io.Reader) (err error)
}

// Retriever takes a path and streams the file it has stored under path to w.
type Retriever interface {
    StreamFrom(path string, w io.Writer) (err error)
}

// Repository is a composite interface. It requires a
// repository to accept andf provide streams of files
type Repository interface {
    Storer
    Retriever
    Close() error
}

现在,您可以轻松实现各种存储方法:

// FileStore represents a filesystem based file Repository.
type FileStore struct {
    basepath string
}

// StreamFrom statisfies the Retriever interface.
func (s *FileStore) StreamFrom(path string, w io.Writer) (err error) {

    f, err := os.OpenFile(filepath.Join(s.basepath, path), os.O_RDONLY|os.O_EXCL, 0640)
    if err != nil {
        return handleErr(path, err)
    }
    defer f.Close()
    _, err = io.Copy(w, f)
    return err
}

就个人而言,我认为这对于GridFS来说将是一个很好的用例,尽管它不是文件系统,但却是MongoDB的功能,尽管它不是文件系统。至于原因:

MongoDB带有一个称为副本集的概念,可通过服务器之间的透明自动故障转移来确保可用性
它带有一个相当简单的自动数据分区机制,称为分片集群
它带有无限数量的称为mongos查询路由器的访问网关,用于访问分片数据。
对于客户端,除了连接URL外,所有这些都是透明的。因此,它的存储后端是由一台服务器还是由600个节点组成的全局复制分片集群,几乎没有什么区别(除了read preference和write concern之外)。
如果做得正确,就不会有单点故障,您可以跨可用性区域进行复制,同时使“热”数据保持在靠近各个用户的位置。

我创建了一个repository on GitHub,其中包含接口建议的示例,并实现了基于文件系统的存储库以及MongoDB存储库。您可能想看看它。目前缺少缓存。如果您希望看到它已实施,请在此处打开一个问题。

PHP-将日期插入日期时间字段 - php

我已在数据库中使用datetime字段存储日期,使用PHP将“今天的日期”插入该字段的正确方法是什么?干杯, 参考方案 我认为您可以使用php date()函数

PHP getallheaders替代 - php

我正在尝试从服务器上的apache切换到nginx。唯一的问题是我在PHP脚本中使用的getallheaders()函数,该函数不适用于Nginx。我已经尝试过用户在getallheaders函数上的php站点上提供的注释,但这并不返回所有请求标头。请告诉我如何解决这个问题。我真的想切换到Nginx。 参考方案 您仍然可以使用它,但是您必须像这里一样重新定义…

PHP mysqli获取查询返回的第一行的值 - php

我正在使用mysqli从数据库中获取某些数据。我正在使用的查询已设置为仅从数据库返回一行。有没有一种方法可以在不使用while循环的情况下获取该行的值?我知道一个while循环对于返回多于一行的行很有用,但是如果不需要while循环,我想避免这种情况,因为不必要的代码是不好的编程。 参考方案 是的-您可以使用:$row = $result->fetch…

php Singleton类实例将在多个会话中保留吗? - php

举一个简单的例子,如果我想计算一个不使用磁盘存储的脚本的命中次数,我可以使用静态类成员来执行此操作吗?用户1:<?php $test = Example::singleton(); $test->visits++; ?> 用户2:<?php $test = Example::singleton(); $test->visits+…

更改默认的URL PHP - php

如何更改默认网址。例如www.example.com/index.php-> www.example.com现在,我要将其设置为www.example.com/test.php。我应该在php.ini中进行更改吗? 参考方案 假设您正在使用apache,则可以通过DirectoryIndex指令执行此操作。Check out the docs。