存储API请求数据库与memcached

时间:2017-01-07 10:55:27

标签: php database laravel memcached

我处在一种我无法下定决心的境地。我有一个客户管理系统(Whmcs),我们公司用它来销售网络托管,vps,......目前我正在编写一个新的独立客户端界面,它使用WHMCS的API来检索客户端的详细信息,发票,支持,门票和产品。所有其他逻辑都发生在新应用程序中(配置产品,支付发票,......)

这些API请求发生在专用网络上,速度不是问题。但是,我想将它们存储在Memcached或单独的数据库中,以将这些请求减少到最低限度。

如果我使用数据库,我会使用WHMCS将调用的某种webhook,例如,当用户有新发票时。这将被发送到webhook,只有在WHMCS中发生了某些变化时才会更新数据库。我在这里看到的唯一缺点是一些数据出现在两个系统上,为了达到这个目的,必须编写很多事件和webhook。

另一个解决方案是使用我们的memcached集群并在那里存储所需的API请求,如果用户登录,则返回所需的数据然后存储在memcached中。这样,只有一个API请求,直到某些内容发生了变化。这种方式相对容易实现,例如:

    public function getInvoices($status = null)
    {
        if (!Cache::has('invoices_' . $status . $this->id)){
            $data = $this->fetchInvoices($this->id, $status);
            Cache::put('invoices_' . $status . $this->id, $data, 30);
        }

        $data = Cache::get('invoices_' . $status . $this->id);

        //Check if user owns the invoices
        if (Gate::denies('owns-data', $this->id)){
            abort(401);
        }

        return $data;
    }

最好的方法是什么?

2 个答案:

答案 0 :(得分:0)

有趣的想法是在WHMCS上创建一个新的客户端界面!

我不会使用钩子并在两个系统中拥有数据的第一条路线。感觉是迟早系统会不同步,你不能信任数据库中的数据。

在开始优化和缓存之前,您是否一直尝试使用API​​来实现“真相来源”?即使您每次需要数据时都使用API​​,您的应用程序也可能足够快?

在这种情况下,您的应用程序将非常简单,并且永远不必担心缓存和使缓存数据无效。例如,如果您在30分钟内缓存了有关发票的信息,会发生什么情况。然后由WHMCS内的管理员或系统自己更改发票。现在,您的应用程序将在30分钟内不同步,因为它不知道发票已更改。

答案 1 :(得分:0)

最终,我提出了一个解决方案。我们的想法是将客户数据和应用程序数据保存在不同的数据库中。应用程序数据库包含一些基本的用户信息,博客文章,论坛数据,......第二个数据库是WHMCS数据库本身,我在其中提取发票,产品,支持票据所需的所有数据......

需要发送给WHMCS的任何更新(发票付款,升级产品......)都通过API进行。这样WHMCS就可以使用传入数据执行自己的逻辑。

我实施的第二部分是一个强大的自定义缓存系统,它限制了对我们的基础架构进行的API查询。 (Openstack,cPanel,...)这个想法非常简单:应用程序的后端使用__call方法侦听包含在函数名称中的Create,Update,Read和Delete。

例如:

$data = array(
    'hostname'  => $r['host'],
    'username'  => $r['username'],
);

Cpanel::listAddonDomain($data);

这会列出用户已添加到cPanel中托管帐户的所有插件域。减少请求数量这需要在用户进行更改或注销之前进行缓存。

首先,有一些逻辑可以检查用户是否拥有cPanel帐户然后将listAddondomains拆分为数组,如果第一个键等于list, read or get,则数据会被标记为高速缓存定义数据所属的用户:

public function __call($name, $arguments)
{
    // Check if the user owns the account
    if(Gate::denies('owns-data', $this->search($this->getProducts(), 'username', $arguments['username'])[0]['clientid']))
    {
        if ($request == 'api'){
            return Api::respondNotAllowed('Not Allowed!');
        }

        abort(404);
    }

    $nameSplit = preg_split('/(?=\p{Lu})/u', $name);

    // Check for arguments to flush the cache
    if($nameSplit[0] == 'create' || $nameSplit[0] == 'delete' || $nameSplit[0] == 'add' || $nameSplit[0] == 'install')
    {
        Cache::tags(['cpanel', $arguments['username']])
            ->flush();
    }

    // If is already present in cache
    if(Cache::tags(['cpanel', $arguments['username']])->get($name . '_' . Auth::user()->id))
    {
        return Cache::tags(['cpanel', $arguments['username']])
            ->get($name . '_' . Auth::user()->id);
    }

    // Do the query
    try{

        $data = $this->send($arguments, $this->getClass($nameSplit), $name);
        $response = Api::respondSuccess($data);

    }catch (Exception $e){
        return Api::respondInternalError($e);
    }

    Cache::tags(['cpanel', $arguments['username']])
        ->put($name . '_' . Auth::user()->id, $response, $this->cacheTime);

    return $response;
}

private function send($arguments, $className, $functionName)
{
    $do = new $className($arguments);
    return $do->$functionName();
}

上面的代码减少到最低限度。在这里发帖会太长,但你会得到这张照片。

现在如何在正确的时间清除缓存?假设用户创建了一个新的插件域,需要清除现有的缓存。

$data = array(
    'hostname'  => $r['host'],
    'username'  => $r['username'],
    'domain'    => $r['domain']
);

Cpanel::createAddonDomain($data);

$nameSplit = preg_split('/(?=\p{Lu})/u', 'createAddonDomain');

if($nameSplit[0] == 'create' || $nameSplit[0] == 'delete' || $nameSplit[0] == 'add' || $nameSplit[0] == 'install')
{
    Cache::tags(['cpanel', $arguments['username']])
        ->flush();
}

如果插件域创建成功,则会为该cPanel帐户刷新缓存。

我已经测试了一个星期了,它就像一个魅力。我已经看到,在启用缓存并直接从WHMCS数据库获取数据时,页面加载时间会大幅下降。

接下来停止,将所有laravel视图重写为独立的Angular应用程序。