类别归档:Web开发

RSS feed of Web开发

最后更新于 .

前言:这是我最近在公司内部分享的一篇文章,大家反响比较强烈,所以也分享到博客里来。 一转眼,来公司已经三年多了。 这三年里,所属部门在变,地理位置在变,技术也日新月异,但是有很多设计原则却是一直不曾改变的,而这次就是我用自身的实践来谈谈我对其中的一个的理解---有损服务。 记得当年qwang用一个很形象的比喻来解释有损(原话记不太清楚了): 比如一个人在沙漠里迷失了寻找水源,那么在他还能走的时候,就尽量走;实在走不动了,用爬的;最后爬也爬不了了,起码要保证自己活着。 所以我们从这个比喻中起码可以获得如下几个信息:

  1. 问题时,优先保证关键功能
  2. 非关键功能不可以影响关键功能
  3. 在条件允许的情况下,损失越少越好

接下来就从自己印象比较深刻的有损服务项目讲起吧。

一、空间应用列表有损服务优化

想当年,苍井空还是处女,玛利亚还姓圣母。好吧,扯远了,想当年第一款国民级应用《QQ农场》横空出世,其空前的火爆导致空间个人中心应用列表的农场图标变得如此重要。 然而由于各种网络等各种原因,这个列表的展现总是会有一定的失败率,而且只要稍微失败就会招来大批用户的投诉。 我们分析一下这个模块的功能:

  • 正常功能:正常展示用户已经安装的应用列表
  • 关键功能:正常展示用户最关心的基础应用(如日志)、火爆游戏(农场)等的应用列表

于是优化开始了……

Step1. 应用信息本地cache

由于应用列表第一个要获取的就是应用自身的信息 ...

最后更新于 .

我这几天在微博上写了一句话: 回归简单,即便开始反而会变得更加复杂。 回想起当年刚用Django写素材管理系统还历历在目,最近却已经逐渐脱离Django了。 成长总是分阶段的吧,勇敢的抛弃一些东西,接纳新的东西,也许就是成长了。 至于原因呢,也是我一直在总结的,大家可以一起看一下。 Django适合做中型项目,但却不适合小型和大型项目 为什么这么说呢?

  • 对于中型项目来说,Django可以说提供了你需要用到的一切,session,orm,admin等等,只要你按照Django规定的思路来,你会发现开发和维护是如此顺手。
  • 但是如果是小型项目呢? 我可能不需要session,我也不需要数据库,但是我却要为Django那些繁琐的东西配置半天。当我被这些繁琐而无用的东西搞晕的时候,我感觉更像是在搭积木,而不是在创造一个伟大的东西。
  • 而对于大型项目来说,Django默认带的组件又满足不了需求,甚至连架构都可能要被替换,所以Django所自带的很多特性都将无法使用。 由于工作的关系,在大型项目中,有一类不得不说的服务,那就是SNS应用。 SNS应用的特点是什么?注册用户量极大,活跃很少。大批的用户蜂拥进入可能只是看一眼就再没回来,但是你的数据却因为这些无用的用户变得庞大无比。进而导致Django默认的那些Model,admin全部都形同虚设,Django的那些所谓的优势荡然无存。 博友反馈这里没说清楚,我再描述一下:
    1. 互联网的数据模型与关系数据模型不匹配。互联网数据更适合NoSQL,所以Admin对关系(外键、关联)的处理就没有任何用处了,而直接展示一个blob字段也并没有比用sql语句直观多少。(BTW ...

最后更新于 .

C++的模板其实是个挺纠结的东西,用的不好的话,编译的一堆错误够你调到崩溃,但要是用的好呢,又确实非常方便,我们来看看

一.获取数组长度

比如

int arr[10];

怎么获取 arr 的长度呢? 最简单的代码:

uint32_t count = sizeof(arr) / sizeof(arr[0]);

但是这样也带来一个问题,万一是个新手程序员:

int *p = arr;
uint32_t count = sizeof(p) / sizeof(p[0]);

就有问题了…… 那么有没有办法,有一种安全的方法,当发现传入的是指针的时候,自动编译报错呢? 有的,模板里面可以推导出数组的长度。 所以我们可以使用如下代码

template <typename T, size_t N> 
size_t arrarysize(T (&array)[N]) { return ...

最后更新于 .

用C++越久,越是觉得C++太多陷阱,真是防不胜防。 我们看这样一段代码:

#include <stdio.h>
using namespace std;
class C
{
public:
    C(int a) {
        printf("%d\n", __LINE__);
    }
    virtual ~C() {}
    
};
int main(int argc, char **argv)
{
    C x1(1);
    return 0;
}

编译执行正常,结果是:

7

然后我们改一下,把构造函数变成无参数的:

#include <stdio.h>
using namespace std;
class C
{
public:
    C() {
        printf("%d\n", __LINE__);
    }
    virtual ...

最后更新于 .

各位C、C++开发的朋友们,有没有想过小小的printf也会有陷阱呢?这篇文章,我们就深入来探究一下(代码均在suse10 32位系统下编译测试通过)。 废话不多说,直接上代码:

int64_t a = 1;
printf("%d\n", a); 

结果是多少呢?当然是1,你可能会说。 我们来看一下结果:

1

果然是1!但是你会不会以为是 a 首先被自动转化成了 int 类型,然后输入为 1的呢? 如果真这么简单,本文到此也该结束了。我们换一个写法:

int64_t a = 1;
int b = 2;
printf("%d, %d\n", a, b);

这次的结果是多少呢?1 和 2?真的吗?我们来看一下结果:

1, 0 ...

最后更新于 .

在日常的前后台联调中,我们都习惯用host的方式来使某个域名的cgi都访问测试环境,然而这有一个显而易见的问题: 如果一个域名下有十几个CGI,而这次提测的只有其中的一个,那么要想整个环境可用,你除了要保证这个CGI可用之外,和你完全无关的十几个CGI也要全部调通。 很纠结,不是吗? 其实我们有更好的方式,那就是用反向代理,我们可以用nginx来实现。 以 appsupport.qq.com 这个域名举例,比如本次提测的cgi路径是:

/cgi-bin/appstage/send_topic.cgi

这个cgi要访问测试环境: 172.16.197.186;而这个域名上的其他cgi都要访问正式的外网环境(如10.137.148.124)。 到http://nginx.org/en/download.html下载windows版本的nginx,解压到C盘,然后修改他的nginx.conf文件如下:

#测试环境
upstream test_env {
    server 10.6.207.119;
}

#预发布环境
upstream pre_env ...

最后更新于 .

相信对于这个标题,用过lisp的朋友一定不陌生,本来也是准备了一大堆理论要讲,想了想还是直接举例子比较好。 就举最近产品提的一个产品需求吧,简单描述一下:

  1. 对于不同的第三方应用,有不同的频率限制。没有配置则使用默认值
  2. 对于不同的第三方应用,在不同的时间段,有不同的频率限制。没有配置则使用默认值

公司内部都是用C++,当时第一点想到的肯定是配置一个xml文件,里面配置上这些参数,在进程启动的时候,用tinnyxml或者其他xml解析器把xml解析成C++可以辨识的数据结构。

我们来看一下这个xml配置有多复杂:

<freq_config interval="60" pt_relevant="1">
    <app_list>
        <app appid="0" max_day_load="360000">
            <time_range_list>
                <time_range begin_time="1" end_time="5" load_perc="0.1" />
                <time_range begin_time="17" end_time="20" load_perc="0.5" />
            </time_range_list>
            <pt_config ...

最后更新于 .

之前已经已经写过一篇《从开放平台建设者角度对应用开发者的一点架构建议(1)》,主要是介绍了最基本的openid、平台数据、应用内部数据的存储建议,这一次我们更深入一点。 对之前的文章,我们提到了三种数据:

  • openid-id
  • id-平台数据
  • id-应用数据

相信大部分个人开发者的第一反应是,上面每份数据建一张表,之间建立很多外键关系。这样的确会有很大的好处,很多数据查询操作都可以直接通过sql语句完成,比如:

  1. 通过openid查询id
  2. 通过id查询openid
  3. 通过用户名查询openid/id
  4. 通过应用数据查询openid/id

上面的架构都很好的,并且开发成本非常低,但是这一切的前提是你的应用的用户量有多少。 100w是个坎,100w之前没有任何问题,100w之后,这种架构就是垃圾 很多人会说,对于一个小应用,考虑那么大量用户干嘛?你这是过度设计了吧。 有这种思想的人不少,没错,当年facebook过100w用户的时候,已经是一家有很多职员的公司了。那你会不会觉得,当我们的小应用成长为100w用户的时候,我们已经有了足够的资金,足够的职员,可以考虑重构了? 然而事实是,zynga新推出的游戏《帝国与同盟》在facebook上上线一周,日活跃就达到3000w,更别说注册用户量。而就国内的情况来说,在朋友网上面的任何一款应用,只要不是太差,1~2个月 ...

最后更新于 .

之前的文章已经提到了 django+fastcgi的运行并不如意(web.py+spawn-fcgi却正常很多……),所以特意抽时间研究了一下uwsgi,试了一下,运行的很好,也很快,哈哈。 所以笔者的所有之前用apache+django搭建的项目(如fuload等)都已经替换成了nginx+django+uwsgi。 一.安装uwsgi

  1. http://projects.unbit.it/uwsgi/wiki/WikiStart#Getit 下载最新版本的uwsg。
  2. 解压后,如果没有安装libxml2,又不想安装的话,那么编辑文件 buildconf/default.ini, 把
    xml_implementation = libxml2
    
    改成
    xml_implementation = false
    
  3. 执行编译
    python uwsgiconfig.py --build
    
  4. 执行安装
    python setup.py install
    

这样 ...

最后更新于 .

在上一篇文章linux下nginx+python+fastcgi部署总结(django版)中,我们部署了nginx+django+fastcgi的环境,这次我们来部署一下nginx+web.py+fastcgi。 其实web.py上的官方网站已经说的比较清楚了,原文如下: http://webpy.org/cookbook/fastcgi-nginx 这里主要讲一下一些原文没有照顾到的地方。

一.安装依赖

spawn-cgi

lup

二.配置nginx

在server配置项下增加

location / {
    #这两种方法都可以,只不过spawn-cgi启动的方法不同
    #fastcgi_pass 127.0.0.1:9002;
    fastcgi_pass unix:webpy.sock;

    fastcgi_param REQUEST_METHOD $request_method;
    fastcgi_param QUERY_STRING $query_string;
    fastcgi_param CONTENT_TYPE $content_type;
    fastcgi_param CONTENT_LENGTH $content_length;
    fastcgi_param ...