OSS数据卷是使用ossfs文件进行挂载的FUSE文件系统,适合于读文件场景。OSS为共享存储,支持ReadOnlyMany和ReadWriteMany两种访问模式。ossfs适用于并发读场景,建议您配置PVC和PV的访问模式为ReadOnlyMany。本文介绍在读多写少场景下如何通过OSS SDK、ossutil工具等方式实现数据的读写分离。
前提条件
- 说明
若Bucket和ECS实例位于相同地域,请选择私网域名。
使用场景
OSS存储常见的使用场景包含只读和读写。对于读多写少的场景,建议您将OSS数据的读写操作进行分离,然后通过配置缓存参数优化数据读取速度,并通过SDK等方式写入数据。
只读
在大数据业务的推断过程、数据分析、数据查询等场景中使用时,为避免数据被误删除和误修改,建议您将OSS存储卷的访问模式配置为ReadOnlyMany。具体操作,请参见使用OSS静态存储卷。
您还可以通过配置缓存参数优化数据的读取速度。
参数 | 说明 |
kernel_cache | 开启后,通过内核缓存优化读性能。适用于不需要实时访问最新内容的场景。 缓存命中时,ossfs重复读取文件时,将通过内核缓冲区高速缓存处理,仅使用未被其他进程使用的可用内存。 |
parallel_count | 以分片模式上传或下载大文件时,分片的并发数,默认值为20。 |
max_multireq | 列举文件时,访问文件元信息的最大并发数。此处需大于等于parallel_count的值,默认值为20。 |
max_stat_cache_size | 用于指定文件元数据的缓存空间可缓存多少个文件的元数据。单位为个,默认值为1000。如需禁止使用元数据缓存,可设置为0。 在不需要实时访问最新内容的场景下,当目录下文件比较多时,可以根据实例规格增加支持的缓存个数,加快ls的速度。 |
通过OSS控制台、SDK、ossutil工具等其他方式上传的文件及目录,在ossfs中默认权限为640。您可以根据实际业务需求,通过配置-o gid=xxx -o uid=xxx
或-o mask=022
参数,避免OSS挂载的目录及子目录不可读的问题。更多信息,请参见OSS存储挂载权限问题。更多ossfs配置项,请参见ossfs/README-CN.md。
读写
在读写场景中,您需要将OSS存储卷的访问模式配置为ReadWriteMany。通过ossfs进行写操作时,注意事项如下。
并发写场景中,OSSFS无法保证数据写入的一致性。
挂载状态下,登录应用Pod或宿主机,在挂载路径下删除或变更文件,都会直接删除或变更OSS Bucket中对应的源文件。您可以通过开启OSS Bucket的版本控制,避免误删除重要数据,请参见版本控制概述。
在读多写少、尤其是读写路径分离的场景中,例如,在大数据业务的训练过程中,建议您将OSS数据的读写操作进行分离,即将OSS存储卷的访问模式配置为ReadOnlyMany,然后通过配置缓存参数优化数据读取速度,并通过SDK等方式写入数据。具体操作,请参见使用示例。
使用示例
本文以手写图像识别训练应用为例,介绍如何实现OSS存储的读写分离。该示例为一个简单的深度学习模型训练,业务通过只读OSS存储卷从OSS的/data-dir目录中读取训练集,并通过OSS SDK将checkpoint写入OSS的/log-dir目录。
通过ossfs实现读写
参考以下模板部署手写图像识别训练应用。该应用使用简单的Python编写,并挂载使用OSS静态存储卷。关于OSS存储卷配置,请参见使用OSS静态存储卷。
以下示例中,应用将OSS Bucket的子路径
/tf-train
挂载至Pod的/mnt
目录,在/tf-train/train/data
目录中存放了MNIST手写图像训练集,供应用读取。目录如下图所示。训练开始前,
trainning_logs
目录为空。在训练过程中,中间文件将写入Pod的/mnt/training_logs
目录中,由ossfs上传至OSS Bucket的/tf-train/trainning_logs
目录中。验证数据正常读写。
执行以下命令,查看Pod的状态。
kubectl get pod tf-mnist
等待Pod状态从Running转换至Completed,约需要数分钟,预期输出为:
NAME READY STATUS RESTARTS AGE tf-mnist 1/1 Completed 0 2m
执行以下命令,查看Pod运行日志。
通过Pod运行日志查询数据加载所需的时间,该时间包含从OSS下载文件及TensorFlow加载的时间。
kubectl logs pod tf-mnist | grep dataload
预期输出:
dataload cost time: 1.54191803932
实际查询的时间与实例的性能和网络状态相关。
登录OSS管理控制台。查看OSS Bucket的
/tf-train/trainning_logs
目录中已出现相关文件,表明数据可以正常从OSS中读写。
通过读写分离优化ossfs数据读取速度
下文以手写图像识别训练应用和OSS SDK为例,介绍如何改造应用实现读写分离。
在容器环境中安装SDK,可在构建镜像时,增加以下内容。具体操作,请参见Python安装。
RUN pip install oss2
参考OSS的官方文档Python SDK demo修改源代码。
以上述手写图像识别训练应用为例,源镜像的相关源代码如下。
def train(): ... saver = tf.train.Saver(max_to_keep=0) for i in range(FLAGS.max_steps): if i % 10 == 0: # Record summaries and test-set accuracy summary, acc = sess.run([merged, accuracy], feed_dict=feed_dict(False)) print('Accuracy at step %s: %s' % (i, acc)) if i % 100 == 0: print('Save checkpoint at step %s: %s' % (i, acc)) saver.save(sess, FLAGS.log_dir + '/model.ckpt', global_step=i)
以上代码中,每进行100次迭代,会将中间文件(checkpoint)存入指定的log_dir目录,即Pod的
/mnt/training_logs
目录。由于Saver的max_to_keep
参数为0,将维护所有的中间文件。如果迭代1000次,则存放10组checkpoint文件在OSS端。通过修改代码,实现通过OSS SDK上传中间文件,修改要求如下:
配置访问凭证,从环境变量中读取AccessKey和Bucket信息。具体操作,请参见Python配置访问凭证。
为减少容器内存的使用,可将
max_to_keep
设置为1,即总是只保存最新一组训练中间文件。每次保存中间文件时,通过put_object_from_file函数上传至对应Bucket目录。
说明在读写目录分离的场景中,使用SDK时,还可以通过异步读写进一步提升训练效率。
import oss2 from oss2.credentials import EnvironmentVariableCredentialsProvider auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider()) url = os.getenv('URL','<default-url>') bucketname = os.getenv('BUCKET','<default-bucket-name>') bucket = oss2.Bucket(auth, url, bucket) ... def train(): ... saver = tf.train.Saver(max_to_keep=1) for i in range(FLAGS.max_steps): if i % 10 == 0: # Record summaries and test-set accuracy summary, acc = sess.run([merged, accuracy], feed_dict=feed_dict(False)) print('Accuracy at step %s: %s' % (i, acc)) if i % 100 == 0: print('Save checkpoint at step %s: %s' % (i, acc)) saver.save(sess, FLAGS.log_dir + '/model.ckpt', global_step=i) # FLAGS.log_dir = os.path.join(os.getenv('TEST_TMPDIR', '/mnt'),'training_logs') for path,_,file_list in os.walk(FLAGS.log_dir) : for file_name in file_list: bucket.put_object_from_file(os.path.join('tf-train/training_logs', file_name), os.path.join(path, file_name))
修改后的容器镜像为
registry.cn-beijing.aliyuncs.com/tool-sys/tf-train-demo:ro
。修改部分应用模板,使其通过只读方式访问OSS。
将PV和PVC的
accessModes
均修改为ReadOnlyMany
,Bucket的挂载路径可缩小至/tf-train/train/data
。在
otherOpts
中增加-o kernel_cache -o max_stat_cache_size=10000 -oumask=022
选项,使ossfs在读取数据时能使用内存高速缓冲区加速处理,并增加元数据支持的缓存个数(10000个元数据缓存大约占40M的内存,可根据实例规格及读取的数据量多少进行调整),以及通过umask使容器进程以非root用户运行时也有读权限。更多信息,请参见使用场景。在Pod模板中增加OSS_ACCESS_KEY_ID、OSS_ACCESS_KEY_SECRET环境变量,其值可从oss-secret中获取,与配置OSS存储卷中的信息保持一致。
验证数据正常读写。
执行以下命令,查看Pod状态。
kubectl get pod tf-mnist
等待Pod状态从Running转换至Completed,约需要数分钟,预期输出为:
NAME READY STATUS RESTARTS AGE tf-mnist 1/1 Completed 0 2m
执行以下命令,查看Pod运行日志。
通过Pod运行日志查询数据加载所需的时间,该时间包含从OSS下载文件及TensorFlow加载的时间。
kubectl logs pod tf-mnist | grep dataload
预期输出:
dataload cost time: 0.843528985977
预期输出表明,在只读模式中合理利用缓存,可提升数据读取的速度。在大规模训练或其他持续加载数据的场景中,优化效果更加明显。
登录OSS管理控制台。查看OSS Bucket的
/tf-train/trainning_logs
目录中已出现相关文件,表明数据可以正常从OSS中读写。
阿里云官方OSS SDK参考代码
阿里云官方OSS SDK部分参考代码如下。更多支持语言PHP、Node.js、Browser.js、.NET、Android、iOS、Ruby,请参见SDK参考。
编程语言 | 参考代码 |
JAVA | |
Python | |
GO | |
C++ | |
C |
实现OSS读写分离的其他工具
工具 | 相关文档 |
OpenAPI | |
ossutil命令行工具 | |
ossbrowser图形化管理工具 |