我处在一种我无法下定决心的境地。我有一个客户管理系统(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;
}
最好的方法是什么?
答案 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应用程序。