博客vps故障及恢复处理

[| 不指定 2012/07/22 23:06]
    周四上午查看博客统计的时候发现居然一个访问量都没有。由于监控没有报警,所以心想统计坏了。

    中午的时候准备看看日志确认下,结果发现真的一个访问都没有。。蛋疼了,发现凌晨5点后一点日志都没了,奇怪,心想网络没有断,为啥呢,访问了下页面,发现数据库挂掉了,无法更新。一查文件系统,原来只读了。发ticket说磁盘坏了,正在更换。等了一个多小时没好,等不及了,开始切换。

    刚准备好切换,机器down掉了,还好博客数据和程序都有备份,从代码仓库里check出来代码。备份里恢复出来数据库,恢复数据库的时候有个插曲,由于是全量备份,所以导入的时候会把目标库里的mysql库等信息都覆盖,会使目标数据库错乱,所幸没有flush,于是把目标库的备份重新覆盖了下。

    然后dns切换,由于主dns挂掉,只有从dns服务器还能工作,手动修改了数据文件指向新机器。修改ttl为300s,以便切回的时候能快速切回。

    周五机器更换磁盘起来了,但是没数据,客服说等磁盘寄回来后才知道数据能不能恢复。虽然自己有备份,但很多软件配置没备份,自己重新配比较麻烦。还是等数据。
   今天告诉我数据取出来了,给了个ftp取数据,搞到数据后恢复了一下环境,dns切换回来了。


    看来冷门数据也要做长周期备份了。
Tags:
    今天需要临时展示一个样例站点,上传程序太麻烦,修改起来也不方便,而电信宽带没有公网ip,只能先在电脑上用ssh连接到服务器,在服务器开个端口映射到电脑上。

    运行了ssh -Ng -R "*:2222:*:3333" server

    发现在服务器端映射端口是成功了,但只是监听在本地。改了半天也不行,百思不得其解。因为之前用过都是成功的。


    后来发现某些版本的sshd因为安全性考虑,默认只允许监听在本地。

    需要在/etc/ssh/sshd_config里面加一句:
    GatewayPorts clientspecified


    即可
Tags: ,

lighttpd中CONST_STR_LEN的用法

[| 不指定 2012/07/05 19:49]
    今天遇到一个问题,在获取http头的时候怎么也获取不到,手动core出来和gdb上去调试发现都是空的,应该是开了O2优化的缘故,于是在程序中打印http头,正常。

    不得已,单步gdb进匹配函数里,发现一个四字符的key值长度被判定为8,很奇怪,查代码原来是用了个CONST_STR_LEN来代替了本来应该填ptr, strlen(ptr)的位置。而CONST_STR_LEN是一个宏,内容为:x, x ? sizeof(x) - 1 : 0。显然,如果传一个指针进去的话,sizeof指针的结果是8(字节,x64),这个宏只能在内容是字符串常量的时候用,不可以用在指针上。当时用的时候看lighttpd代码中一些地方用了这个宏,于是想当然认为到处都可用。。看来还是要注意一些。









Tags:
   最近研究了一下pptp vpn的插件编写。刚开始的时候以为身份认证等信息是pptpd服务进程做的,后来看了代码后发现并非如此,是在pppd那里做的,也就是ppp软件包。

    下载了ppp源码看了下,当前版本是2.4.5,项目居然在samba域名下,不知道这个跟samba有啥联系。

    在代码的pppd/plugins里面有一些插件,比如radius的,看了下源码。大致了解了下思路:

    一个插件即是一个标准的动态链接库。pppd使用dlopen()库调用来加载。pppd使用plugin选项来加载插件,只有一个参数:插件文件名。如果指定的文件名没有斜线,pppd会到/usr/lib/pppd/目前下面查找该文件,这里面version是pppd的版本,比如2.4.5。也可以设置全路径,在使用自己编写的插件时比较方便。

    插件可以做的事:
    使用add_options(),传入option_t 。最后一项是NULL,跟lighttpd配置是一样的。这个作用应该是时ppp支持相应配置。

    指定hook。pppd会在处理过程中调用各个钩子。插件可以任意设置自己的过程到这些hook。
    
    插件可以用add_notifier消息回调。

引用

#include "pppd.h"
#include "chap-new.h"

char pppd_version[] = VERSION;


static int pppd_chap_check(void) {
        return 1;
}
static int pppd_chap_verify(char *user, char *ourname, int id, struct chap_digest_type *digest, unsigned char *challenge, unsigned char *response, char *message, int message_space) {
        if(digest->verify_response(id, user, "a", strlen("a"), challenge, response, message, message_space)) {
                return 1;
        } else {
                return 0;
        }
}

static int check_address_allowed(int addr) {
        return 1;
}
void plugin_init(void) {
        chap_check_hook = pppd_chap_check;
        chap_verify_hook = pppd_chap_verify;
        allowed_address_hook = check_address_allowed;
}


这是一个简单的插件源码,如果用户密码是a就通过。可以进行扩充就可以让pppd支持多种不同的权限认证,并且可以支持各种计数操作。该插件支持chap认证,包括mschap,mschap-v2,chap方式,至于pap,由于安全性不行,不支持也无所谓。

    这里需要注意allowed_address_hook 需要实现,表示同意使用分配的该ip,没有实现时会在注册网络时失败。

    char pppd_version[]                  = VERSION;
    表示支持的ppp版本。

    plugin_init,就是插件被载入时执行的操作,执行hook注册等等操作。

    chap_check_hook 表示该插件是否可以进行chap认证。
    chap_verify_hook 是身份认证的过程,一般使用digest->verify_response来进行校验。

以下是一篇资料里贴出的函数及消息列表:
  
插件钩子函数列表

int (*idle_time_hook)(struct ppp_idle *idlep);

idle_time_hook在这个连接第一次开始的时候被调用(比如,第一个网络协议开始的时候),那之后被定时调用。在第一次调用的时候,idlep参数是NULL,返回值则是pppd检查连接活跃前的秒数,或者0表示没有超时。

在后来的调用中,idlep指令一个指向最包被发送、接收秒数的结构体。如果返回的值大于0,pppd会在再次检查之前等一些的秒数。如果小于等于0,就是说该连接在不活跃的情况下应该被终结。



int (*holdoff_hook)(void);

当尝试拌连接失败或是连接被终结的时候,holdoff_hook被调用,persist或是demand选项被使用。它返回PPTP重新建立连接应该等待的秒数(0表示立即)。



int (*chap_check_hook)(void);

int (*chap_passwd_hook)(char *user, char *passwd);

int (*chap_auth_hook)(char *user, u_char *remmd, int remmd_len, chap_state *cstate);

这些hook被设计用来在插件里面替换常规的CHAP密码处理过程(比如外部服务器的认证)。

chap_check_hook被调用来检查对端是否有必要向我们认证其自身。如果返回1,pppd将询问询问其自身,否则返回0(如果该认证被要求了,在网络协议协商之前pppd会退出或是终结当前连接)。如果返回-1,pppd将查找chap-secrets文件使用常规方式处理。



chap_passwd_hook决定pppd应该使用什么密码来使用CHAP来向对端认证自身。user字符串使用’user’选项或者’name’选项、主机名进行初始化,有必须可以进行修改。这个钩子只有当ppdp是客户客户端而非服务的时候被调用。passwd可以容纳最多MAXSECRETLEN 字节。如果钩子返回0,PPPD使用 *passwd,如果返回 -1,pppd认证失败。



chap_auth_hook 钩子确定由对应提供的CHAP挑战响应是否有效。user指向一个包含对端提供用户名的非NULL结束的字符串。remmd向向对端提供的响应,由remmd_len表示其长度 。cstate是PPTP维护的内部CHAP状态结构体。chap_auth_hook应该返回CHAP_SUCCESS 或者CHAP_FAILURE。



int (*null_auth_hook)(struct wordlist **paddrs, struct wordlist **popts);

这个钩子允许插件确定当请求的认证被对端拒绝的时候应该采取的策略。 如果返回0,连接被终结;1,连接被允许处理,这种情况下 *paddrs和*popts可像pap_auth_hook一样被设置,以指定被允许的IP地址列表和任意扩展属性。如果返回-1,pppd查找pap-secret文件按常规处理。

void (*ip_choose_hook)(u_int32_t *addrp);

该钩子在IPCP协商开始的时候调用。它使得插件有机会设置对端的IP地址。地方应该保存在*addrp。如果*addrp里什么也没有存储的庆,pppd使用常规方式决定对端的地址。

int (*allowed_address_hook)(u_int32_t addr)

这个钩子确认对端是否可以使用指定的IP地址。如果钩子返回1,地址可以接受,返回0为拒绝。如果返回-1,将使用常规方式查找适当的选项和secrets文件来决定。

void (*snoop_recv_hook)(unsigned char *p, int len)

void (*snoop_send_hook)(unsigned char *p, int len)

这些钩子在接受或是发送数据包的时候被调用。数据包在p里同,长度由 len表式。使得插件可以检查pppd的会话。这些钩子在实现L2TP的时候将会起到很大的作用。

可注册的消息列表

插件可以使用notifier注册自身,通过申明一个下面形式的过程:

void my_notify_proc(void *opaque, int arg);

然后使用适当的notifier,以下面形式调用来注册这个过程。

add_notifier(&interesting_notifier, my_notify_proc, opaque);

add_notifier 中的’opaque’参数每次调用notifier的时候传递给my_notify_proc 。传递的’arg’参数决定于notifier一个nofify过程可以使用下面的方式从当前的notifier列表中被移除。

remove_notifier(&interesting_notifier, my_notify_proc, opaque);



下面是目前pppd实现的notifier列表。

pidchange 由其父进程在pppd已经forked并且子进程在继续pppd’s处理时调用,比如pppd从其控制终端中分离出来的时候。参数就是这个子进程的pid。

phasechange 当pppd从一个阶段操作转移到另一个的时候调用。参数是新阶段的编号。

exitnotify 在pppd退出前调用。参数是pppd退出的状态。(比如exit()的参数)。

sigreceived 在收到信号的时候调用,存在于signal handle里面。参数是signal的编号。

ip_up_notifier 在IPCP发生的时候调用。

ip_down_notifier 在IPCP关闭的时候调用。

auth_up_notifier 在对端认证自身成功的时候调用。

link_down_notifier 在连接关闭的时候调用。




参考资料:http://liaoweiqiang.info/?p=411
Tags: ,
    前几天百度开放云支持绑定自有域名了,在应用列表里有很明显的绑定域名链接,点击后会提示将要绑定的域名cname到应用主域名上,一般是*.duapp.com,然后点击确定即可绑定成功。

    需要注意的一点是,一定要在域名设置生效后再点击绑定按钮,否则由于dns缓存问题,可能需要等待最长24小时才能成功。

    修改域名指向的过程也比较简单,进入dns管理页面(一般域名注册商提供),添加cname记录(如该条记录已存在且不是cname记录,则修改为cname记录),目标设为应用主域名,点确认即可。尽量不要在设置成功前访问或nslookup该域名,这样会使域名生效时间延后,无法绑定后立即体验效果。





Tags: ,
    买过一些空间,有时候有的朋友要放个小博客,于是就手动开通一些账号和绑定域名给他们,但总是不太方便,很麻烦,于是就有搞一个面板来实现这个功能。
    现在使用最多的主机面板就是cpanel,而cpanel恰好有很多api。
    于是搞了一个面板,可以将一个普通的cpanel用户账号多人共享,互不干扰。这样方便了主机合租和账号分享。朋友们共享主机时不再需要购买多个主机或reseller账号了。
    不过面板的账户间共享资源,所以隔离性上还是不如reseller账号的。所以建议还是朋友或熟悉的人之间使用。

    项目地址:http://code.google.com/p/cp-share/
    本文地址:http://www.snooda.com/read/307
    第一版实现了域名,数据库,ftp账号的管理,功能和界面都比较简陋。不过已经可以满足基本的需求了。后续慢慢完善。

    附截图一张:
点击在新窗口中浏览此图片


Tags:
    有一个问题,是在一个环境上的lighttpd一打日志就出core,很奇怪,看堆栈信息是出在mod_accesslog里,今天看了下,发现原来是试图打印%i导致的。
    lighttpd支持在日志中打印请求头中的字段,方法是%{key}i,这样就能在请求头中的key字段打印到日志里,打印referer等东西的时候比较方便。

    但如果直接写%i的话,由于没有指定key,导致NULL指针,lighttpd没有校验导致出core。

    恰好%I是打印请求长度,大写I还是比较容易误按成小写的。所以有了这个问题



Tags: ,

redis的性能初测

[| 不指定 2012/06/12 12:13]
    最近准备用用redis,于是做了下性能测试,在一台虚拟机上跑了下,发现add命令大概1s可以执行3-5w条,使用redis官方推荐的php客户端:Predis ,使用pipe功能批量插入1w条数据的话大概要0.3-0.5s,感觉速度有些慢,仔细研究了下,发现时php库在生成那个1w条的redis命令是非常慢,一个请求要耗费掉1s的cpu时间,实在是性能杀手,考虑后续使用c实现。







Tags:
    今天有同学希望将webserver与后端fcgi换成长连接以提高性能,于是在lighttpd里直接配置proxy-core.max-keep-alive-requests即可,为了做测试,后端只启动了一个fcgi进程。然后发现了奇怪的问题,每隔几个请求就会有一个非常非常慢的连接,需要等待10s左右。

    后来决定开strace看看,由于lighttpd配了多进程,不好搞,于是改成单worker,结果问题解决了。


    这样问题就豁然开朗了,原来多个请求落到了不同的lighttpd工作进程上,而唯一的一个fcgi进程被处理第一个请求的worker起长连接占用了,结果导致其他lighttpd无法连接到后端。


    这是一个启用长连接后比较隐蔽的坑,可能会导致各个webserver的worker进程间负载不一致。需要小心了。




Tags:

mysql5.5禁用innodb引擎方法

[| 不指定 2012/05/30 13:44]
    今天发现有一个备份的mysql数据文件夹异常变大,一查发现是多了三个文件:ibdata1      ib_logfile0  ib_logfile1,前者18m,后两个各5m,原来是迁移的时候从mysql5.0迁移到了5.5,而5.5关闭innodb启动不起来,于是我就开启了innodb,由于innodb会默认增加这几个数据文件和日志文件,导致变大。尝试设置数据文件的大小,结果告诉我最小10m,还是太大,于是探索关闭innodb的方法。
    看日志发现说由于mysql程序升级了,需要运行mysql_upgrade升级一下mysql里面的数据库,这个比较简单,和mysql命令用法是一样的,运行一遍就ok了。然后发现还是无法关闭innodb,很奇怪,查了下发现原来mysql5.5默认使用innodb了,所以无法简单的关闭掉,还要设置一下默认使用的引擎为myisam才可以,在my.cnf里加上如下两句:

default-storage-engine=MYISAM
innodb=OFF

重启mysql,然后删掉那三个讨厌的文件即可。





Tags:
分页: 4/33 第一页 上页 1 2 3 4 5 6 7 8 9 10 下页 最后页 [ 显示模式: 摘要 | 列表 ]