类别归档:Web开发

RSS feed of Web开发

最后更新于 .

最近因为项目上的需要开始大量使用nginx,因此也想趁机将以前常用的django+apache的架构换成django+nginx+fastcgi,此文是整个搭建的步骤,主要留作备忘,也希望对大家有所帮助。

注意:虽然本文成功的搭建了django运行fastcgi的实例,但是在实际运行中发现了很多问题,比如程序执行异常,进程在每次请求之后退出之类的。可能是我机器的问题,也可能是程序本身bug,大家如果用来搭建外网环境,请务必多多测试。

一.编译nginx

在网上买了一本《实战nginx-取代Apache的高性能服务器》,写的比较浅,主要是些配置方面的东西,不过却正是目前我所需要的。

由于需要支持https和rewrite,所以除了nginx的源码之外,又下载了 openssl-0.9.8r.tar.gz 和 pcre-8.12.tar.gz,把他们和nginx-1.0.4.tar.gz放到同一个目录。

为了方便编译,笔者写了一个脚本,代码如下:

#!/bin/bash

#=============================================================================
#脚本所在绝对目录
abs_path(){
    local path=$1
    local basename=$( basename ...

最后更新于 .

2011年,各大平台相继开放,相信关注的朋友都应该知道,6月15日,腾讯也召开了开发者大会,在这里笔者不想就开放本身做太多讨论,作为一个技术博客,我们还是专注讨论技术架构吧。 笔者在腾讯主要负责腾讯开放openapi的开发,也确实见到了不少应用由于架构不当,导致开发维护成本非常高的例子,更重要的是接入成本非常高导致落在了别的应用后面,所以,笔者在这里会结合腾讯开放的一些特点,给应用开发者一点建议。 如果有朋友致力于应用的开放,希望能有所帮助。 我们就从最基本的地方开始说起吧。 开放平台都会提供一个openid,一个openid对应平台上面的一个真实帐号,在腾讯当然就代表的是QQ号。通过openid就可以或者某个人的个人信息,他的好友关系链等等信息。 那么,怎么让openid与应用自身的数据关联起来呢? 这是我所见到的第一种架构:

一.openid直接作为主键

openid 主键
名称  
性别  
地点  
头像  
应用内部数据  

应用直接将平台的openid来做主键,即应用没有自身的id。 这种方式有什么问题呢?假设说你做的是一个有发展前景的应用,你的应用以后可能会接入facebook,人人,等等开放平台,而每个开放平台的openid格式又都不一样,那么你的数据库表设计将会每个平台的都有一部分不一样,而大部分业务逻辑又都一样,严重违反了“DRY”原则,增加了开发和维护的成本。 所以这种方式不好。

二.有自己的id ...

最后更新于 .

博客这几天由于服务器的问题打不开,在这里跟大家抱歉啦 老读者应该都知道,笔者有两个开源项目,分别是: fuload: 性能测试工具,可以用来给服务器做压力测试 bayonet: 基于两层状态机的epoll服务器框架 对于fuload的介绍,请看这里: fuload开源压力测试框架完成! 对于bayonet的介绍,请看这里: 有限状态机的C++实现(1)-epoll状态机 有限状态机的C++实现(2)-bayonet开源网络服务器框架 之前由于工作等原因,bayonet一直被搁置,最近有时间,所以就抓紧把bayonet完成了,目前功能上基本已经OK了,我简单列一下功能点:

  1. 接管了网络,调用方只需要关心业务逻辑
  2. 配置的方式,快速切换TCP-UDP
  3. 快速的增加加状态机的状态,业务可以无限拓展

代码编写中,也用到了很多技术,如引用计数来保证野指针不被访问(通过引用计数解决野指针的问题(C&C++)),延迟析构对象,等等。 由于详细介绍是个很庞大的工作,所以这里就直接放出一个基于bayonet写的http代理,我们来看一下,只需要多少代码:

#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include ...

最后更新于 .

C/C++代码中,野指针问题历来已久,当然,大家都知道new/delete要成对出现:

A *p = new A();
delete p;
p = NULL;

然而现实中却并不是总是如此简单,考虑如下例子:

class A
{
public:
    C() {}
    virtual ~C() {}
};
class B
{
public:
    B() {
        m_pA = NULL;
    }
    virtual ~B() {}

    void SetA(A* p)
    {
        m_pA = p;
    }

private:
    A* m_pA;
};

A* pA = new A();
B* pB = new B();
pB->SetA(pA);

delete pA;
pA = NULL;
//此时B中的m_pA已经无效 ...

最后更新于 .

由于公司业务需要,花两周时间实现了一个小型的支付系统,麻雀虽小五脏俱全,各种必须的模块如账户加锁,事务性保证,流水对帐等都是有完整实现的,整个开发过程中有很多经验积累,再加上在网上搜索了一下,大部分都是些研究性的论文,对实际使用价值不大,所以这次特意拿出来和大家分享一下。

这个系统可以用作小型支付系统,也可以用做第三方应用接入开放平台时的支付流水系统。

原来的需求比较负责,我简化一点说:

  1. 对每个应用,对外需要提供 获取余额,支付设备,充值 等接口
  2. 后台有程序,每月一号进行清算
  3. 账户可以被冻结
  4. 需要记录每一次操作的流水,每天的流水都要和发起方进行对账

针对上面的需求,我们设置如下数据库:

CREATE TABLE `app_margin`.`tb_status` (
    `appid` int(10) unsigned NOT NULL,
    `freeze` int(10) NOT NULL DEFAULT 0,
    `create_time` datetime NOT NULL,
    `change_time` datetime NOT NULL,
    
    PRIMARY KEY ...

最后更新于 .

用php有两个月了,说实话用惯了django,再用php开发真的有点郁闷,简单列一下,并非批评,仅为入门的同学少走弯路:

  1. 取不到post的数据 当url为如下形式:
    xx.com/?mod=x&act=y
    
    而method又为post的时候,post的数据会取不到;必须改成如下形式:
    xx.com?mod=x&act=y
    
  2. 字符串连接 这么写代码是会报错滴:
    echo 1."xx";
    
    必须这么写才行:
    echo 1 ."xx";
    
  3. require之后,不知道自己引入了些什么 这个地方,如果和C或者C++来比确实也没啥问题,关键是python的from x import y 的方式实在是让人赏心悦目,所以忍不住抱怨下。

OK,抱怨完了,言归正传。 其实这些问题都还好,仔细点都能解决,最让我不爽的是php的所有框架(不排除我孤陋寡闻,欢迎大家指教)居然都没有提供一个类似于django的form类。 心灰意冷之时,突然想起来之前看到过一个仿django的php框架,虽然整个框架还有很多问题,不过form类这部分应该完成了吧。 pluf ...

最后更新于 .

这次还是把遇到的几个问题整理一下,希望再遇到的同学能轻松解决。另外最近博客的feeds延迟更新的原因也会一起说明一下。

1.linux下创建线程导致内存泄漏

今天在外网发布了一个server之后,用top发现virt的使用量一直在涨,而且一次涨8m。于是可以断定有内存泄漏了,经过排查,最终确定原因出在多线程的问题上: 代码如下:

pthread_t thread_id;
int ret=pthread_create(&thread_id, NULL, flush_thread_work, (void*)&m_sql_client);
if(ret!=0){
    APPSCORE_ERROR("Thread creation failed:%d",ret);
    return ret;
} 

在flush_thread_work函数内部:

void* flush_thread_work(void* args)
{
    //....do something
    return NULL;
}

代码中启动了一个线程之后,主进程就继续执行,任由新线程自生自灭了(没有调用thread_join),而主进程每隔一段时间就会拉起这样一个线程来做一些数据落地的事情。 这样的写法实际上是会造成内存泄漏的. Linux man page 里有已经说明了这个问题:

When a joinable ...

最后更新于 .

公司还是不推荐用python,只好屈服使用php,不过用python习惯了,真是发现有些地方不适应,今天写了一段代码,语法检查怎么都通不过,特地放在这里,希望有朋友能指点一下。 代码如下:

function get()
{
    $arr = array(
        1,2,3
    );
    return $arr;
}
$y = get()[1];
echo $y;

执行会报如下错误:

Parse error: syntax error, unexpected '['

一开始我还以为又是少写';'之类的问题,仔细检查未果,所以把代码拆成两行,变成:

$y = get();
$y = $y[1];

居然执行成功了! 于是我不解了,为什么连c++都支持的语法,而php里面却不肯支持? c++的代码如下:

vector<int> foo()
{
    vector<int> vec;
    vec.push_back(1 ...

最后更新于 .

好吧,我知道是大半夜……,但我还是觉得赶紧花上半个小时,把这最新的想法分享出来是值得的~直接进入正题~ 我们来模拟一个场景,需要你去抓去一个页面,然后这个页面有好多url也要分别去抓取,而进入这些子url后,还有数据要抓取。简单点,我们就按照三层来看,那我们的代码就是如下:

def func_top(url):
    data_dict= {}

    #在页面上获取到子url
    sub_urls = xxxx

    data_list = []
    for it in sub_urls:
        data_list.append(func_sub(it))

    data_dict['data'] = data_list

    return data_dict

def func_sub(url):
    data_dict= {}

    #在页面上获取到子url
    bottom_urls = xxxx

    data_list = []
    for it in bottom_urls:
        data_list.append(func_bottom(it))

    data_dict['data'] = data_list

    return data_dict ...

最后更新于 .

上一篇文章《更简洁的C++数据库访问框架-soci》介绍了soci,但也同时提到了一个缺点---insert/update/delete操作的时候,没有返回影响了多少行。 另外还有一个隐性的原因,soci的代码大量使用了异常,而项目中要求底层代码是严禁抛出异常的(其实google也是有这个要求的)。 基于以上两个原因,所以最终没有把soci用在生产环境。 但是又不想每次都重复去调用那些繁琐的MySQL API,所以这次又重新对MySQL API做了一层C++的封装。 其实相信每个和mysql打过交道的程序员都应该会尝试去封装一套mysql的接口,这一次的封装已经记不清是我第几次了,但是每一次我希望都能做的比上次更好,更容易使用。 先来说一下这次的封装,遵守了几个原则,其中部分思想是从python借鉴过来的:

  • 1.简单
  • 简单,意味着不为了微小的效率提升,而去把接口搞的复杂。因为本身数据库存储效率的瓶颈并不是那一两次内存copy,代码中随处可以看到以这个为依据的设计。
  • 2.低学习成本
  • 使用一套新库通常意味着投入学习成本,而这次的封装并没有像django那样实现一套完整的模型系统,也没有做soci那样的语法分析器,我选择最简单易懂的方式:做sql语句拼接器,所以对习惯了使用原生mysql api的朋友,学习成本很低
  • 3.模块化
  • 代码实际包括了两个模块,一个是mysql client端的封装,一个是sql的拼接器,这两个模块是完全独立的,调用者可以任意组合或者独立使用。
  • 4.尽量使用STL以及模板,简化代码编写
  • 最大的特点就是大量使用了stringstream进行类型转化 ...