关于柔性服务的一些实践和思考
最近花了大力气在做openapi的优化,使其尽量柔性可用,借此也有些想法想和大家分享一下。
柔性服务,google一下,在网上并没有这样一个标准的概念,所以应该是公司自己取的一个名字。但是这种概念,相信大家都应该很容易能明白,即:
最大程度的保证关键服务的可用性
通俗点来说,一个人不能走路了,他起码可以说话,不能说话了,起码可以点头,头都不能点了,起码得能活着,即心脏还在跳动。这就是柔性。
对应互联网服务来说就是要实现两点:
1.要尽可能成功返回关键数据 2.要尽可能正常接收请求,不能堵死
笔者总结了一下,只要CGI满足其中一个或几个特点,就可以考虑使用柔性服务:
1.在整个CGI的执行过程中,存在关键路径和非关键路径 2.CGI中存在循环调用接口,导致执行时间不确定
我们分上面两种特点来看:
对于第一种,我们举一个简单的例子,比如有一个CGI,做了两件事情分别是:
1.验证登录态 2.获取用户信息
很明显可以看出,验证登录态这个接口是关键路径,而获取用户信息这个接口是非关键的。所以按照柔性服务的定义,当获取用户信息接口失败时,起码还应该返回登录成功。
但是这个时候毕竟还是要区分出完全成功和部分成功的,所以我们可以定义返回码如下(目前腾讯社区开放平台的openapi就是如下定义):
ret==0:完全成功 0<ret<1000:部分成功 ret>=1000:完全失败
这样就很明白了,我们在调用获取个人信息接口失败是,返回ret=1即可。
但是这样是否足够了呢?
考虑一下,如果获取个人信息接口此时是超时,那么会导致整个CGI的返回变慢,从而导致接收进程挂死。此时虽然我们做了所谓的柔性服务,但是仍然是无法正常提供服务的。
怎么解决呢?我们需要一个能够动态调整超时时间的算法,当接口的响应时间远大于平常的平均值时,分配给接口的超时时间也要响应的调小。
伪编码如下:
以下是代码片段: EMA g_CGITimeoutMng;//超时时间管理 class CCGI { public: CCGI () { m_TrueRet=0; g_CGITimeoutMng.start(); } virtual ~CCGI () { g_CGITimeoutMng.stop(); } int HandleInput() { int ret = check_login(g_CGITimeoutMng.remainTime()); if (ret!=0) { return 1000; } ret = get_profile(g_CGITimeoutMng.remainTime()); if (ret!=0) { m_TrueRet++; } return m_TrueRet; } private: int m_TrueRet;//容错返回码 }; |
那这里的动态调整算法使用什么呢?目前使用的是EMA来估算出下一时间点应当分配的超时时间,EMA一开始是用于股票的,后来公司的某大牛将其引入进来动态计算超时时间,大家可以google一下EMA的定义。
现在看来问题是解决了,但是这里会有一个比较大的限制,即:
关键路径和非关键路径要有明确的分割,即不可以颠倒顺序,或者互相穿插
但是万一就是有出现不符合这种限制的情况,该怎么办呢?其实也是有解决方法的,之前我们是只定义了一个g_CGITimeoutMng,他负责分配CGI的总处理时间,但是我们还可以再定义一个g_InterfaceTimeoutMng1,来动态调整某个接口的超时时间。
一般情况下我们仅需要对非关键接口加上这种单独的调整,并且取g_CGITimeoutMng.remainTime()和g_InterfaceTimeoutMng1.remainTime()中的较小值。
示例代码如下:
以下是代码片段:
EMA g_CGITimeoutMng;//超时时间管理
EMA g_InterfaceTimeoutMng1;//超时时间管理
class CCGI
{
public:
CCGI ()
{
m_TrueRet=0;
g_CGITimeoutMng.start();
}
virtual ~CCGI ()
{
g_CGITimeoutMng.stop();
}
int HandleInput()
{
int ret = check_login(g_CGITimeoutMng.remainTime());
if (ret!=0)
{
return 1000;
}
g_InterfaceTimeoutMng1.start()
timeout = g_CGITimeoutMng.remainTime()<g_InterfaceTimeoutMng1.remainTime()?g_CGITimeoutMng.remainTime():g_InterfaceTimeoutMng1.remainTime()
ret = get_profile(timeout);
g_InterfaceTimeoutMng1.stop();
if (ret!=0)
{
m_TrueRet++;
}
ret = check_right(g_CGITimeoutMng.remainTime());
if (ret!=0)
{
return 1001;
}
return m_TrueRet;
}
private:
int m_TrueRet;//容错返回码
};
这样的话,基本就可以完美解决了。
再回来说一下第二种,即有循环调用的问题,其实要做柔性的主要原因也是因为如果不计算使用的时间而直接容错的话,会导致时间很长。
示例代码如下:
以下是代码片段:
EMA g_CGITimeoutMng;//超时时间管理
class CCGI
{
public:
CCGI ()
{
m_TrueRet=0;
g_CGITimeoutMng.start();
}
virtual ~CCGI ()
{
g_CGITimeoutMng.stop();
}
int HandleInput()
{
int ret;
for (i = 0; i < count; i++)
{
ret = get_somedata(g_CGITimeoutMng.remainTime());
if (ret!=0)
{
m_TrueRet++;
continue;
}
//做取到数据之后该做的事情
}
return m_TrueRet;
}
private:
int m_TrueRet;//容错返回码
};
PS:
以下是引用片段: 上面的代码在调用接口接口之前并没有判断g_CGITimeoutMng.remainTime()<=0,这是因为我们假定接口内部对timeout<=0都是直接返回错误的。如果不是这样的话,需要在调用接口前进行判断。 |
建议继续学习:
- 可用性测试好助手——Morae软件的应用 (阅读:5456)
- 可用性测试的权衡之道(二) (阅读:4788)
- 那么明显,为什么用户看不见? (阅读:3362)
- 简单快速的可用性测试 (阅读:1988)
- 可用性案例分析 (阅读:1994)
- 如何快速解除用户防备?――浅谈可用性测试中沟通的技巧 (阅读:1902)
- 可用性测试的权衡之道(一) (阅读:1764)
- 可用性测试中的任务设计方法 (阅读:1584)
- 儿童网站的可用性问题 (阅读:1119)
- 产品的可用性、易用性、高效性 (阅读:1168)
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:Dante 来源: Vimer
- 标签: openapi 可用性 柔性服务
- 发布时间:2011-01-12 23:09:07
- [66] Oracle MTS模式下 进程地址与会话信
- [65] 如何拿下简短的域名
- [65] Go Reflect 性能
- [59] 【社会化设计】自我(self)部分――欢迎区
- [59] IOS安全–浅谈关于IOS加固的几种方法
- [59] 图书馆的世界纪录
- [59] android 开发入门
- [53] 视觉调整-设计师 vs. 逻辑
- [47] 界面设计速成
- [47] 读书笔记-壹百度:百度十年千倍的29条法则