casbin / node-casbin

An authorization library that supports access control models like ACL, RBAC, ABAC in Node.js and Browser
https://casbin.org
Apache License 2.0
2.58k stars 216 forks source link

Enforcing with domains and 100k+ policies causing performance issues #471

Closed jimcamut closed 6 months ago

jimcamut commented 6 months ago

We're experiencing CPU issues with over 100K+ policies/roles. Our setup is MongoDB with the suggested Typeorm adapter.

According to @hsluoyz, "... you should keep cache (subset rules) in memory, this is how Casbin is designed to use." https://github.com/casbin/node-casbin/issues/392#issuecomment-1259549016

When using domains/tenants, how are we supposed to leverage Casbin in a more performant way? There aren't many examples. loadFilteredPolicy() seems like it would be the solution, but it's not clear how this should be used?

Any suggestions? Much thanks!

casbin-bot commented 6 months ago

@nodece @Shivansh-yadav13

hsluoyz commented 6 months ago

@jimcamut see performance optimization docs: https://casbin.org/docs/performance

jimcamut commented 6 months ago

@jimcamut see performance optimization docs: https://casbin.org/docs/performance

@hsluoyz I've essentially done 2 and 3 of the suggestions. I'm also attempting policy subset loading. In other words something like this:


const workspaceEnforcerPromise: { [workspaceId: string]: Promise<Enforcer> } = {};

export async function getWorkspaceEnforcer(workspaceId: string) {
  if (!workspaceEnforcerPromise[workspaceId]) {
    workspaceEnforcerPromise[workspaceId] = getAdapter()
      .then(async adapter => {
        const enforcer = await newEnforcer(casbinModel, adapter);

        logger.info(`Casbin enforcer initialized with workspace filter ${workspaceId}`);

        await enforcer.loadFilteredPolicy({
          $or: [
            { ptype: 'p', v1: workspaceId },
            { ptype: 'g', v2: workspaceId },
          ],
        });

        return enforcer;
      })
      .catch(error => {
        logger.error(error, `Error initializing Casbin enforcer: ${error.message}`);
        workspaceEnforcerPromise[workspaceId] = null;
        throw error;
      });
  }

  return workspaceEnforcerPromise[workspaceId];
}

// Using the subset example

async function enforce(...args) {
  const enforcer = await getWorkspaceEnforcer(workspaceId);
  return enforcer.enforce(...args)
}

Is this the intended usage? I'm seeing a delay of about 13 seconds on my main thread when first loading - and is that expected?

hsluoyz commented 6 months ago

@jimcamut you mean you are loading rules from DB for 13 seconds? Then you need to consider it like reading DB slow. Like loading smaller size data, or make your DB near to your application, etc.