S3(Simple Storage Service)对象存储简介及使用

S3(Simple Storage Service)对象存储简介及使用

什么是S3服务

S3是一套基于HTTP协议并采用RESTful风格构建起来的Web存储管理服务

S3的一些特点

  • 存储桶是S3用于数据存储的基础容器
  • 存储桶中可以存储无限量的数据,每个对象最多5TB数据,使用开发人员分配的唯一密钥存储和检索每个对象
  • 身份验证机制
  • 访问接口使用基于标准的REST和SOAP接口,可以与任何Internet开发工具搭配使用

S3基本存储模型

两种存储单元:Bucket和Object,扁平化存储结构,可以横向增加Bucket和Object,理论上可以存储无数个Object。

  • 对象(Object)

S3存储的最小单位,数据不透明,元数据透明,数据和元数据一起存,还可以指定自定义元数据。在存储桶中,对象将由密钥(名称)和版本 ID 进行唯一地标识。

  • 存储桶(Bucket)

存储对象的容器,名称要全局唯一,并且命名需要符合英文国际域名的命名规则。对象名为mybucket组成的URL为http://mybucket.s3.cephbook.com

传统文件系统向S3的转变

  • 文件路径和数据存储
  • 文件元数据存储
解决文件路径和数据存储

  • 所有数据都存放在Bucket中,文件都是Object。

个人理解文件夹不需要管,在路径中直接用”/“区分就行了(这个分割符可以指定),因此也没有了文件夹的元数据信息。目录样式演示是模拟出来的对象的层次结构。删除目录可以理解为删除具有该前缀的所有对象。

1
2
3
4
5
6
lihongbo01@cld-unknown212867:~/workspace/s3_workspace$ s3cmd ls s3://mybucket/in
DIR s3://mybucket/in/
lihongbo01@cld-unknown212867:~/workspace/s3_workspace$ s3cmd ls s3://mybucket/in/mybucket
DIR s3://mybucket/in/mybucket/
lihongbo01@cld-unknown212867:~/workspace/s3_workspace$ s3cmd ls s3://mybucket/in/mybucket/s3sdk.py
2019-06-17 07:05 1094 s3://mybucket/in/mybucket/s3sdk.py
  • 在key name中加上”/”来区分“文件夹”。
  • 文件数据内容作为Content存储在Object内。
解决文件元数据存储

两种存储的元数据对应关系:

  • key name -> 文件路径
  • etag -> 文件md5
  • metadata(File size, Last mode, MIME type) -> 文件的size/x-time这些
  • ACL -> 文件的acl/uid/gid这些
  • Content-Type -> MIME

MIME用于设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。

S3的使用

s3cmd 命令行形式访问(连接到其他第三方S3服务为例)

安装
pip install s3cmd

默认s3cmd会读取当前用户的$HOME/.s3cfg,可以使用-c参数手工指定配置文件路径。

配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[default]
access_key = XXXXXXX # 填写access_key
secret_key = XXXXXXX # 填写secret_key
default_mime_type = binary/octet-stream
enable_multipart = True # 启动分块上传
encoding = UTF-8
encrypt = False
host_base = s3dev.nie.netease.com # 接入点
host_bucket = %(bucket)s.s3dev.nie.netease.com
multipart_chunk_size_mb = 15 # 分块上传大小
socket_timeout = 300 # 超时时长
stop_on_error = False
use_https = False # 是否使用HTTPs
use_mime_magic = True
verbosity = WARNING
signature_v2 = True # 强制使用AWS2签名认证
使用实例

s3cmd –help 查看帮助

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
lihongbo01@cld-unknown212867:~/workspace$ s3cmd ls
lihongbo01@cld-unknown212867:~/workspace$ s3cmd mb s3://mybucket
Bucket 's3://mybucket/' created
lihongbo01@cld-unknown212867:~/workspace$ s3cmd rb s3://mybucket
Bucket 's3://mybucket/' removed
lihongbo01@cld-unknown212867:~/workspace$ s3cmd mb s3://mybucket
Bucket 's3://mybucket/' created
lihongbo01@cld-unknown212867:~/workspace$ s3cmd put hello.lua s3://mybucket
upload: 'hello.lua' -> 's3://mybucket/hello.lua' [1 of 1]
15 of 15 100% in 0s 120.37 B/s done
lihongbo01@cld-unknown212867:~/workspace$ s3cmd rb s3://mybucket
ERROR: S3 error: 409 (BucketNotEmpty) # rb是删除空bucket,加--force可以删除(未启用版本控制)
lihongbo01@cld-unknown212867:~/workspace$ s3cmd del s3://mybucket
ERROR: Parameter problem: File name required, not only the bucket name. Alternatively use --recursive
lihongbo01@cld-unknown212867:~/workspace$ s3cmd del s3://mybucket/hello.lua
delete: 's3://mybucket/hello.lua'
lihongbo01@cld-unknown212867:~/workspace$ s3cmd ls s3://mybucket
lihongbo01@cld-unknown212867:~/workspace$

其他常用命令如:

s3cmd get s3://new_bucket/file # 下载file到本地
s3cmd setacl s3://new_bucket/file --acl-public # 开启file的匿名访问权限,注意权限控制
s3cmd info s3://new_bucket/file # 查看object属性信息
s3cmd del s3://new_bucket --recursive --force # 递归删除bucket内的所有内容,慎用!
s3cmd signurl s3://new_bucket/file +30 # 生成临时的url访问链接(30s有效时长)。
s3cmd du s3://new_bucket # 查看bucket的信息
s3cmd cp src dst # 复制
s3cmd mv src dst # 移动

Python SDK使用S3

安装
pip install boto

boto 适用于Python 2.6 and 2.7环境,python 3.x推荐使用boto3

新建、删除bucket实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# -*- coding: utf-8 -*-
from boto.s3.connection import S3Connection
import boto
import os

# 开启下面则启用AWS4认证,默认使用AWS2
# os.environ['S3_USE_SIGV4'] = 'True'

endpoint = 's3dev.nie.netease.com' #S3服务的endpoint地址
bucket_name = 'mk_by_python' #bucket名称
access_key = 'XXXXXXX' #access-key
secret_key = 'XXXXXXX' #secret key

conn = boto.connect_s3(
aws_access_key_id=access_key,
aws_secret_access_key=secret_key,
host=endpoint,
is_secure=False, #不使用HTTPS
calling_format=boto.s3.connection.SubdomainCallingFormat(), #使用virtual-hosted-style,推荐使用
# calling_format=boto.s3.connection.OrdinaryCallingFormat(), #使用path-style
validate_certs=True,
)

buckets = conn.get_all_buckets() #获取当前bucket列表
print buckets
bucket = conn.create_bucket(bucket_name) #新建bucket
buckets = conn.get_all_buckets() #获取当前bucket列表
print buckets
conn.delete_bucket(bucket_name) #删除bucket
buckets = conn.get_all_buckets()
print buckets

输出

1
2
3
4
5
lihongbo01@cld-unknown212867:~/workspace/s3_workspace$ python s3sdk.py 
[<Bucket: mybucket>]
[<Bucket: mk_by_python>, <Bucket: mybucket>]
[<Bucket: mybucket>]
lihongbo01@cld-unknown212867:~/workspace/s3_workspace$
Python接口

bucket相关

1
2
3
4
5
6
7
8
conn.create_bucket(bucket_name)  # 新建bucket
conn.get_all_buckets() # 获取当前bucket列表
conn.delete_bucket(bucket_name) # 删除bucket
bucket.get_acl() # 获取bucket ACL
bucket.get_xml_acl() # 获取bucket ACL的xml格式描述
bucket.set_acl('private') # 设置bucket ACL,可以选:private,public-read,public-read-write,authenticated-read这些
bucket.set_xml_acl(xml_acl) # 以XML格式进行设置
bucket.add_user_grant('WRITE','test1') # 对‘test1’这个用户赋予‘WRITE’权限 # bucket新增用户ACL,可选:READ, WRITE, READ_ACP, WRITE_ACP, FULL_CONTROL

object相关

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
key_ = bucket.new_key(key_name)  # 生成一个key
key_.set_contents_from_filename(local_file) # 上传文件 [与上一条命令一起用]
# 两种删除方式
key_.delete()
bucket.delete_key(key_name)
bucket.get_all_keys(prefix='user1_23695/') # 按指定prefix查询bucket中对应的Object列表,注意默认最多返回1000条记录
bucket.delete_keys(file_list) # 批量删除Object
key_.get_xml_acl() # 获取XML格式的Object的ACL信息
key_.get_acl() # 获取Object的ACL
key_.set_acl('public-read') # 方式1,设置Object的ACL
key_.set_canned_acl('public-read') # 方式2,设置Object的ACL
key_.set_xml_acl(acl_xml) # 方式3,设置Object的ACL
key_.add_user_grant('READ','test1') # 对‘test1’这个用户添加READ权限。 #添加用户授权,可选权限有:READ, WRITE, READ_ACP, WRITE_ACP, FULL_CONTROL
key_.set_metadata('key','value') # 设置Object的metadata,注意必须在上传Object之前做好初始化设置
#获取Object的metadata
key_ = bucket.get_key(key_name)
print key_.get_metadata('key')
key_.get_contents_to_filename(down_file) # 下载Object,保存为本地的‘/tmp/download.file’