分布式对象存储服务器minio

一、什么是分布式对象存储服务器?

分布式存储服务器简单解释为将数据分布在多个存储型服务器上,并且这些分散的存储资源可以构成一个虚拟化的存储设备,但是现实是数据是分散存储在企业的各个角落。

例如:您需要存储10PB的一个视频文件,但是您的个人电脑发生故障无法存储,需要存储在多个香港服务器上,每台香港服务器看作是一个datanode,在获取文件时,逐一去访问效率低。

所以安排一个中间人来存放文件在哪台服务器的信息,通过这个中间的服务器信息更快找到文件。这个中间人称namenode,存储关于文件的信息称之为元数据。

为了数据安全,每一个小的视频(存储单元)复制一份存放到不同服务器上,当有一台服务器出现了无法运行情况,利用访问备份可以快速找到自己需要的数据,以上这样的存储方式便是分布式存储服务器。

二、常见的文件存储服务器对比

(1)Minio和FastDFS

目前可用于文件存储的网络服务选择有很多,比如阿里云OSS、七牛云、腾讯云等等,但是收费都有点小贵。为了帮公司节约成本,之前一直是使用fastDFS作为文件服务器,准确的说是图片服务器。直到我发现了MinIO,我决定放弃FastDFS。

分布式对象存储服务器minio_第1张图片
理由一:安装部署(运维)复杂度
之前公司在使用fastDFS的时候,只有少数的几个人能够掌握fasdtDFS的部署结构。所以只要出现有点问题,能够顶上的只有这么几个人。如果将一个fastDFS分布式服务部署完成,需要具备以下的知识

linux基础的目录操作
常用的分布式主从原理
C语言代码的编译
nginx安装部署
nginx插件的使用(防盗链)
如果仅仅是上面的这些基础知识,安排几个程序员学一学还好说。主要是fastdfs的部署结构之复杂,如果我长时间不回顾,自己都会忘了这复杂的架构是怎么回事。
当我看到MinIO的安装过程之后,以及分布式的部署命令之后(分布式MinIO快速入门),放弃fastDFS的决心就已经做出了一大半。
说白了:FastDFS的部署不过是零件的组装过程,需要你去理解fastDFS的架构设计,才能够正确的安装部署。MinIO在安装的过程是黑盒的,你不用去深入关注它的架构,也不需要你进行零件组装,基本上可以做到开箱即用。普通的技术人员就能够参与后期运维。

理由二:文档
我觉得从我知道fastDFS开始,也有十年了。竟然没有官方文档,所有的文档全是某某公司的自己总结的文档,或者是某某网友自己总结的文档。
从这点上看fastDFS真的是一败涂地,当然阿里余庆大神在做这个项目的时候可能也没有考虑到后来会有这么多人用。即使用的人多了,在余庆大神眼里可能觉得这只是自己开发的一个小玩具,没有继续深入运营的必要。

理由三:开源项目运营组织
fastdfs是阿里余庆做的一个个人项目,在一些互联网创业公司中有应用,没有官网,不活跃,6个contributors。目前已经很少做更新。
MinIO目前是由2014年在硅谷创立的公司MinIO.Inc运营的开源项目,社区论坛的活跃度目前也非常的不错。

理由四:UI界面
我们都知道fastDFS默认是不带UI界面的,看看MinIO的界面吧。这个界面不需要你单独的部署,和服务端一并安装。开箱即用,爱了爱了。
分布式对象存储服务器minio_第2张图片

理由五:性能
MinIO号称是世界上速度最快的对象存储服务器。在标准硬件上,对象存储的读/写速度最高可以达到183 GB/s和171 GB/s。关于fastDFS我曾经单线程测试写了20万个文件,总共200G,大约用时10个小时。总体上是很难达到MinIO“号称的”以G为单位的每秒读写速度。
分布式对象存储服务器minio_第3张图片

理由六:容器化支持
MinIO提供了与k8s、etcd、docker等容器化技术深度集成方案,可以说就是为了云环境而生的。这点是FastDFS不具备的。

分布式对象存储服务器minio_第4张图片

理由七:丰富的SDK支持
fastDFS目前提供了 C 和 Java SDK ,以及 PHP 扩展 SDK。下图是MinIO提供的SDK支持,MinIO几乎提供了所有主流开发语言的SDK以及文档。同志们,重要的是文档。

理由八:AWS S3标准兼容
Amazon的S3 API是对象存储领域的事实标准。MinIO是S3兼容性的事实上的标准,是第一个采用API和第一个添加对S3 Select支持的标准之一。包括微软Azure在内的750多家公司使用MinIO的S3网关,这一数字超过了业内其他公司的总和。
分布式对象存储服务器minio_第5张图片

什么意思?就是说你现在为了节约成本使用MinIO,等你的公司壮大了、有钱了。不想自己运维基础设施了,你就可以把对象存储放到云上,只要云厂商支持S3标准,你的应用程序是不需要重新开发的。

(2)nginx

nginx作为一个高性能的HTTP和反向代理web服务器当然也是可以用作图片文件等发布服务器,但是在分布式场景中显然不太适宜了。在我们实际项目开发过程中用nginx作为文件存储服务器的前提是nginx与后端服务部署在同一主机上,后端服务将文件上传至系统本地的某个文件夹下,然后通过修改nginx配置文件对这个文件夹进行发布,这样就可以通过访问nginx的发布路径对文件进行访问了。如下所示:

		location /upload/ {
           root   /usr/local/upload/;
         }

但是这种方式在nginx和后端服务不在同一主机上时就无法使用了(当然还是有一些方法可以解决这个问题的,不过实现起来较复杂且不合理),更好的方法当然是采用分布式对象存储服务器进行文件存储。

(3)FTP

FTP(File Transfer Protocol,文件传输协议) 是 TCP/IP 协议组中的协议之一。FTP协议包括两个组成部分,其一为FTP服务器,其二为FTP客户端。其中FTP服务器用来存储文件,用户可以使用FTP客户端通过FTP协议访问位于FTP服务器上的资源。在开发网站的时候,通常利用FTP协议把网页或程序传到Web服务器上。此外,由于FTP传输效率非常高,在网络上传输大的文件时,一般也采用该协议。

默认情况下FTP协议使用TCP端口中的 20和21这两个端口,其中20用于传输数据,21用于传输控制信息。但是,是否使用20作为传输数据的端口与FTP使用的传输模式有关,如果采用主动模式,那么数据传输端口就是20;如果采用被动模式,则具体最终使用哪个端口要服务器端和客户端协商决定。

FTP支持两种模式,一种方式叫做Standard (也就是 PORT方式,主动方式),一种是 Passive(也就是PASV,被动方式)。 Standard模式 FTP的客户端发送 PORT 命令到FTP服务器。Passive模式FTP的客户端发送 PASV命令到 FTP Server。
Minio与FTP区别:
一个是web服务器一个是FTP服务器,FTP服务器采用FTP协议进行文件传输与访问,Minio则是采用http协议。minio与Java项目整合更方便,且若在浏览器前端页面中通过ftp协议显示图片显示不出,但是可以下载,一般是通过FTP+nginx解决该问题。

三 、minio简介

分布式对象存储服务器minio_第6张图片

MinIO 是一款高性能、分布式的对象存储系统. 它是一款软件产品, 可以100%的运行在标准硬件。即X86等低成本机器也能够很好的运行MinIO。

MinIO与传统的存储和其他的对象存储不同的是:它一开始就针对性能要求更高的私有云标准进行软件架构设计。因为MinIO一开始就只为对象存储而设计。所以他采用了更易用的方式进行设计,它能实现对象存储所需要的全部功能,在性能上也更加强劲,它不会为了更多的业务功能而妥协,失去MinIO的易用性、高效性。 这样的结果所带来的好处是:它能够更简单的实现局有弹性伸缩能力的原生对象存储服务。

MinIO在传统对象存储用例(例如辅助存储,灾难恢复和归档)方面表现出色。同时,它在机器学习、大数据、私有云、混合云等方面的存储技术上也独树一帜。当然,也不排除数据分析、高性能应用负载、原生云的支持。

在中国:阿里巴巴、腾讯、百度、中国联通、华为、中国移动等等9000多家企业也都在使用MinIO产品。

四、使用docker部署minio

1.下载镜像

docker pull minio/minio

2.启动容器

 docker run \
          -p 9000:9000 \
          -p 9001:9001 \
          --name minio \
          -d --restart=always \
          -v /usr/local/minio/data:/data \
          -v /usr/local/minio/config:/root/.minio \
          -e "MINIO_ROOT_USER=用户名" \
          -e "MINIO_ROOT_PASSWORD=密码" \
          minio/minio server /data --console-address ":9001"

3.访问

http://ip:9000

分布式对象存储服务器minio_第7张图片

4.采用https访问
采用网上安装SSL证书的方法一直有问题,可以采用nginx代理的方式实现。

五、springboot集成Minio

1.pom文件引入依赖

		<dependency>
		    <groupId>io.minio</groupId>
		    <artifactId>minio</artifactId>
		    <version>8.2.0</version>
		</dependency>

2.yml文件添加配置

minio:
  url:   #对象存储服务的URL
  accessKey:  #Access key账户
  secretKey: #Secret key密码

3.编写config配置类

@Configuration
public class MinioConfig {
	
	@Value("${minio.url}")
    private String url;
    @Value("${minio.accessKey}")
    private String accessKey;
    @Value("${minio.secretKey}")
    private String secretKey;
    
    @Bean
    public MinioClient getMinioClient() {
        MinioClient minioClient = MinioClient.builder().endpoint(url)
				.credentials(accessKey, secretKey).build();
        return minioClient;
    }
    
}

4.编写util工具类

@Component
public class MinioUtil {
	@Autowired
    private MinioClient minioClient;
	
	/**
	 * 创建一个桶
	 */
	public void createBucket(String bucket) throws Exception {
		boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucket).build());
		if (!found) {
			minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucket).build());
		}
	}
	
	/**
	 * 上传一个文件
	 */
	public void uploadFile(InputStream stream, String bucket, String objectName) throws Exception {
		minioClient.putObject(PutObjectArgs.builder().bucket(bucket).object(objectName)
				.stream(stream, -1, 10485760).build());
	}
	
	/**
	 * 列出所有的桶
	 */
	public List<String> listBuckets() throws Exception {
		List<Bucket> list = minioClient.listBuckets();
		List<String> names = new ArrayList<>();
		list.forEach(b -> {
			names.add(b.name());
		});
		return names;
	}
	
	/**
	 * 列出一个桶中的所有文件和目录
	 */
	public List<Fileinfo> listFiles(String bucket) throws Exception {
		Iterable<Result<Item>> results = minioClient.listObjects(
			    ListObjectsArgs.builder().bucket(bucket).recursive(true).build());
			
			List<Fileinfo> infos = new ArrayList<>();
				results.forEach(r->{
					Fileinfo info = new Fileinfo();
					try {
						Item item = r.get();
						info.setFilename(item.objectName());
						info.setDirectory(item.isDir());
						infos.add(info);
					} catch (Exception e) {
						e.printStackTrace();
					}
				});
		return infos;
	}
	
	/**
	 * 下载一个文件
	 */
	public InputStream download(String bucket, String objectName) throws Exception {
		InputStream stream = minioClient.getObject(
		              GetObjectArgs.builder().bucket(bucket).object(objectName).build());
		return stream;
	}
	
	/**
	 * 删除一个桶
	 */
	public void deleteBucket(String bucket) throws Exception {
		minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucket).build());
	}
	
	/**
	 * 删除一个对象
	 */
	public void deleteObject(String bucket, String objectName) throws Exception {
		minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucket).object(objectName).build());
	}

5.编写实体类

public class Fileinfo {
	String filename;
	
	Boolean directory;

	public String getFilename() {
		return filename;
	}

	public void setFilename(String filename) {
		this.filename = filename;
	}

	public Boolean getDirectory() {
		return directory;
	}

	public void setDirectory(Boolean directory) {
		this.directory = directory;
	}

}

6.编写接口

@Api(tags = "文件操作接口")
@Controller
public class FileController {

	@Autowired
	MinioUtil minioUtil;

	@ApiOperation("上传一个文件")
	@RequestMapping(value = "/uploadfile", method = RequestMethod.POST)
	@ResponseBody
	public AjaxResult fileupload(@RequestParam("files") MultipartFile files, @RequestParam String bucket,
			@RequestParam(required=false) String objectName) throws Exception {
		minioUtil.createBucket(bucket);
		minioUtil.uploadFile(files.getInputStream(), bucket, objectName+"/"+files.getOriginalFilename());
		return AjaxResult.success();
	}

	@ApiOperation("列出所有的桶")
	@RequestMapping(value = "/listBuckets", method = RequestMethod.GET)
	@ResponseBody
	public AjaxResult listBuckets() throws Exception {
		return AjaxResult.success(minioUtil.listBuckets());
	}

	@ApiOperation("递归列出一个桶中的所有文件和目录")
	@RequestMapping(value = "/listFiles", method = RequestMethod.GET)
	@ResponseBody
	public AjaxResult listFiles(@RequestParam String bucket) throws Exception {
		return AjaxResult.success("200", minioUtil.listFiles(bucket));
	}

	@ApiOperation("下载一个文件")
	@RequestMapping(value = "/downloadFile", method = RequestMethod.GET)
	@ResponseBody
	public void downloadFile(@RequestParam String bucket, @RequestParam String objectName,
			HttpServletResponse response) throws Exception {
		InputStream stream = minioUtil.download(bucket, objectName);
		ServletOutputStream output = response.getOutputStream();
		response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(objectName.substring(objectName.lastIndexOf("/") + 1), "UTF-8"));
        response.setContentType("application/octet-stream");
        response.setCharacterEncoding("UTF-8");
		IOUtils.copy(stream, output);
	}


	@ApiOperation("删除一个文件")
	@RequestMapping(value = "/deleteFile", method = RequestMethod.GET)
	@ResponseBody
	public AjaxResult deleteFile(@RequestParam String bucket, @RequestParam String objectName) throws Exception {
		minioUtil.deleteObject(bucket, objectName);
		return AjaxResult.success();
	}

	@ApiOperation("删除一个桶")
	@RequestMapping(value = "/deleteBucket", method = RequestMethod.GET)
	@ResponseBody
	public AjaxResult deleteBucket(@RequestParam String bucket) throws Exception {
		minioUtil.deleteBucket(bucket);
		return AjaxResult.success();
	}
}

以上部分内容转载自:https://blog.csdn.net/hanxiaotongtong/article/details/107830363

你可能感兴趣的:(中间件,微服务,服务器,分布式,运维)