本文分析ceph的10.X版本的配额功能。主要以存储池配额为例,分析一下配额功能的完备性。
现状
功能和配置:
通过设置存储池的最大对象数和最大字节数,当达到限额时,则不允许写入。
ceph osd pool set-quota <poolname> max_objects|max_bytes <val>
ceph osd pool get-quota <poolname>
原理和实现:
通过定时检测,条件满足时通过设置osdmap的CEPH_OSDMAP_FULL标志来共享池空间满的信息。
在osd的prepare_transaction处判断标志,并根据需要返回错误码。
对于配额功能一般返回-EDQUOT或-ENOSPC错误码
对于暂时无法处理需要丢弃的操作,则返回-EAGAIN错误码。
问题分析:
从实现上可以看出,由于客户端和osd缺乏完备的通信机制,对于存储池满的情况,ceph只是简单的放在了服务后端osd层面进行处理并返回预期的EDQUOT错误码。
但是这样处理有一些问题。比如在ceph kclient中,存在使用页面缓存的情况,用户的io先写入缓存,再异步通过系统自动sync向osd发起同步请求。这时如果是pool full,osd如果返回eagain错误码,则会造成不断重试,并造成io阻塞。如果返回edquot,则数据实质上没有写入成功,但是用户层面的操作却是成功的,造成数据不一致和数据丢失。
优化
从问题分析得出,可以把判断配额限制的处理前移到客户端,由客户端收集满足配额条件,比如存储池配额满的情况,当配额条件触发后,返回EDQUOT错误码。
同时,对于一些不会造成系统重大影响的软性配额,osd层面应该适当放开pool full的检测,允许业务正常处理,这样当一些客户端的异步io请求触发时,不会被丢弃掉。这样的错误会导致配额功能有一定的误差,但是在检测周期内,一般也是允许的,没有什么大影响。