MobileFirst 8:存储数据时遇到意外错误

MobileFirst 8 : Unexpected error encountered while storing data

我们正在使用 UserAuthenticationSecurityCheck 对用户进行身份验证。

如果验证成功,MFP服务器将存储用户属性。

public class AuthSecurityCheck extends UserAuthenticationSecurityCheck {

    static Logger logger = Logger.getLogger(AuthSecurityCheck.class.getName());

    private String userId, displayName;
    private JSONObject attrObject;

    private String errorMessage;

    @Override
    protected AuthenticatedUser createUser() {
        Map<String, Object> userAttrsMap = new HashMap<String, Object>();
        userAttrsMap.put("attributes",attrObject); 
        return new AuthenticatedUser(userId, displayName, this.getName(), userAttrsMap);
    }
...
}

但是如果我们存储更大的数据(当 userAttrsMap 足够大时),我们将得到 500 错误。

errorMsg: Unexpected error encountered while storing data

错误如下图:

完整源代码已打开 Github:https://github.com/DannyYang/PMR_CreateUserStoredLargeData

多功能一体机版本:

出现此问题的原因是您在 AuthenticatedUser 对象中保存的数据大小以及安全检查的状态。

MFP 运行时将安全检查的状态与所有属性一起保存到属性存储中。这涉及序列化安全检查状态并将其持久保存到数据库。对于大对象(您拥有的自定义地图),此持久性操作失败并以事务回滚结束。发生这种情况是因为您尝试保留的数据太大并且超出了分配的大小。

SecurityCheck 的设计考虑是将其用于安全检查(验证)并创建身份对象。在您的安全检查实施中,您有以下内容:

//Here the large data is assigned to the variable.
attrObject = JSONObject.parse(largeJSONString);

//This data is set into the AuthenticatedUser object.
Map<String, Object> userAttrsMap = new HashMap<String, Object>();
userAttrsMap.put("attributes",attrObject);
return new AuthenticatedUser(userId, displayName, this.getName(), userAttrsMap);

在这种情况下,这个大数据成为 Securitycheck 本身的一部分,并将被序列化并尝试持久化到属性存储中。当此数据不适合该列时,事务将回滚并将错误情况传播给最终用户。因此,您会看到错误消息 - “存储数据时发生意外错误”。启用详细跟踪将在服务器跟踪日志中指出问题的实际原因。

无论如何,在生产系统中根本不推荐这种方法,因为:

a) 客户端到达服务器的每个请求都经过安全内省,这将涉及服务器加载、检查和更新安全检查的状态。在承受重负载(生产)的系统上,这可能并且将会产生性能成本。该过程涉及序列化数据并在以后反序列化。在分布式拓扑(集群或农场)中,请求可能会在任何节点中结束,这些节点将必须加载并稍后将安全检查的状态保存到存储中。所有这些都会影响系统的性能。

b) 在成功验证结束时,AuthenticatedUser 对象会传播到客户端应用程序,指示登录流程已完成。即使 SecurityCheck 状态成功存储在属性存储(具有大量数据)中,通过网络传输大量有效负载只是为了指示成功登录也会适得其反。对于最终用户来说,自从他们输入凭据后,似乎什么也没发生,而指示成功的数据仍在下载中。

c) 在重负载下,服务器会因上面的 a) 和 b) 而紧张。

您应该考虑减少在 authenticateduser 对象中传播到客户端的数据。使 AuthenticatedUser 对象中的数据最少。相反,您应该将获取大数据的任务卸载到可以访问的资源适配器 post 成功登录。