聊聊更为高效的ACL认证方式

前言


在存储系统中,为了保证数据的安全性,凡是需要访问数据的用户,都是需要被验证其是否有足够权限访问的。这个认证过程可以是传统UGO(user, group, other,rwx)的方式,当然也可以是另一种ACL的方式。ACL是为每个需要被访问的资源指定了可允许用户的列表,每个用户还被声明了能够允许的权限操作。假设现在我们使用的是ACL的方式来做访问控制,这意味着每次用户发起资源(如果是存储系统,就是数据)请求时,系统都会经过一次ACL的验证。那么此时ACL的check动作将会是一个高频的行为,按照传统方式我们将ACL信息保存到元数据存储中,这势必会带来高频的元数据查询。对此,我们可以做哪些优化处理使之行为更加高效呢?本文笔者结合最近Hadoop Ozone的原生ACL设计,来聊聊这个主题。

传统ACL认证模式的缺点


我们要想提高现有ACL认证模式的效率,那我们必不可少需要去了解目前传统资源ACL的认证原理,大致过程如下所示。
在这里插入图片描述
按照上图所示,过程主要如下:

1)系统在创建资源时,会将设置的ACL信息作为资源元数据信息的一个属性信息,和元数据信息一起被序列化保存到外部存储中去。当然有些系统也可能将ACL信息单拎出来进行保存。
2)当用户访问目标资源时,系统从元数据存储中读取该资源对象信息,提取其ACL属性信息,进行ACL的用户验证,权限验证。如果验证通过,系统允许用户当前访问行。如果验证不通过,则抛出权限验证错误。

看似上述过程中规中矩,并没有明显的弊端毛病,但是如果我们往系统未来的扩展性等方向考虑的话,这里面还是会暴露出不少的缺陷。主要有以下几点不足之处:

  • 元数据的ACL信息的高频访问。高频访问意味着高频的访问元数据外部存储的行为,这里假设元数据存储还仅仅是在本地的情况时,这意味着系统将会有高频的IO行为。
  • 当系统的元数据规模大幅度扩张时,这些资源所需要存储的ACL信息也将会变多。换句话说,ACL需要的存储空间也会膨胀。

综上所述两点。分别代表的是效率和空间2个维度的问题。下面我们来聊聊有哪些好的改进措施。

基于比特位的ACL存储方式


我们首先来看系统ACL信息的存储。这里我们不能觉得系统资源信息它只会占据一点点字节,我们就可以忽略其占有量。但是当这点空间按照亿万级规模衡量的话,对此的优化还是非常重要的。况且在分布式存储系统中,亿万级规模文件对象存储还是可能的。

现今比较常规的ACL的保存形式是用数字来表明权限信息的,比如下面这种:

0,代表READ权限
1,代表WRITE权限
2,代表READ AND WRITE权限
<userA: 2> 代表的意思就是userA对资源拥有可读,可写的访问权限

上述用数字方式表示权限确实已经比用字符保存的方式节省了不少空间了,但是它还可以进一步的优化处理。我们知道一个int类型,32位,long类型64位,如果我们只用到了012这个数量级,完全用不到这个类型的最大值。进一步来说,如果我们按照最小粒度bit位来说,它只需要3位。因为3个比特分别对应3个权限类型,已经可以涵盖上面提及的全部权限类型了。按照位来存储的话,ACL信息可以从32位减小到3位,有着10倍的缩小了。

以下是通过按照比特位来存储权限信息的方式:

001,代表READ权限(二进制存储格式,此为2个bit位)
010,代表WRITE权限
100,代表READ AND WRITE权限
<userA: 001> 代表的意思就是userA对资源只拥有可读权限

不过按照位来做权限信息的存储时,它的ACL信息的更新会变得稍微复杂一些,因为这里面会涉及到位运算了。对一个资源进行某个权限的添加语义就变为了将在某个比特位上进行赋值为1的操作,而收回权限的语义则变为了比特位重置为0的操作。

基于比特位的ACL更新过程如下图所示:

在这里插入图片描述

Radix Tree的ACL构建访问


下面我们来谈论ACL关于访问效率的问题。当然我们不希望系统每次验证ACL的时候都进行一次真实元数据Store的查询,所以一种自然联想到的优化方式是load到内存中。然后系统在内存中进行快速地读取,同时针对ACL的更改行为,我们也不仅仅将更改apply到元数据存储中,同时我们也应该在memory的ACL信息中进行相应地更新。

所以笔者这里谈论的优化点就转化为了如何构建更高效的ACL内存结构。一般来说ACL是针对存储系统来说的,而存储系统对于用户来说,较广为使用的形式是文件系统的模式。而在文件系统模式中,它的一个典型的组织形式是树状组织模式,从根节点一路往下按照目录,文件进行组织、串联。

如果按照纯元数据ACL键值对load到内存的话,每个路径Key的entry项都是完全独立存储的。但因为树状组织的路径形式有其特殊性,这里会有许多公共的前缀路径,对于这部分公共路径,我们完全可以进行复用只存储一份。基于这个思路,Radix Tree能够很好的适用于这个场景。在Radix Tree中,最终叶子节点保存的信息对象即是ACL最终的信息内容,往上父亲节点为其分叉路径。当系统进行ACL进行读取时,只需从Radix Tree根节点从上往下依次查找即可。

基于Radix Tree构建的ACL树结构图如下所示(有关Radix Tree的相关文章:Radix Tree的相关):

在这里插入图片描述

新的ACL组织结构既利用了内存的访问高效性,又借助于Radix Tree的空间节省特点,无疑是一个高效的选择。

以上就是本文所要关于高效ACL认证方式的全部内容,参考自Hadoop Ozone原生ACL设计的思路,感兴趣的同学可阅读引用链接处进行更为深入的了解学习。

引用


[1].https://blog.csdn.net/Androidlushangderen/article/details/91660880
[2].https://issues.apache.org/jira/browse/HDDS-1303. Support native ACL for Ozone

原文地址:https://www.cnblogs.com/bianqi/p/12183533.html