2010年3月

昕昕语录

1. 一天,昕昕拿着妈妈的呼啦圈给妈妈看,说:


“妈妈,你看,椭圆形~”


昕昕妈一看,人家把一个圆形的呼啦圈给压瘪了


可不就成了椭圆形了吗?


2. 他玩完卡片,弄了一地都是小卡片


于是,我就让他自己把卡片给装到袋子里


刚开始,他还能自己一点一点装


后来,发现还有很多,他就说:


“爸爸帮我装”,我想让他自己给装完


于是,就说“爸爸不会装“


这小子来了一句”我教爸爸装“


开始示范给我看,并扶着我的手,往里面装


我故意每次都装不进去,都掉到袋子外面


开始他还是一遍一遍的教我


但我仍旧是给掉到了外面


后来,他实在是忍无可忍了


用手指着我说:”爸爸笨蛋!“

Nginx的nginx_http_push_module模块测试

Nginx的nginx_http_push_module模块,可以使nginx服务器成为一个comet服务器


可以接受Client端的一个长连接请求,当server端有消息push时,则返回消息给Client


1. 编译很简单:


--add-module=../slact-nginx_http_push_module


2.配置如下:



折叠复制代码




  1. push_max_reserved_memory 20M;

  2. push_authorized_channels_only on;


  3. server{

  4. listen 80;

  5. server_name localhost test.ysz.com;

  6. access_log /opt/work/log/nginx_access_ysz.log main;

  7. error_log /opt/work/log/nginx_error_ysz.log error;


  8. location /publish {

  9. set $push_channel_id $arg_id;

  10. push_publisher;

  11. push_store_messages on;

  12. push_message_timeout 2h;

  13. push_max_message_buffer_length 10;

  14. }

  15. location /activity {

  16. push_subscriber;

  17. set $push_channel_id $arg_id;

  18. push_subscriber_concurrency broadcast;

  19. default_type text/plain;

  20. }

  21. }




3.测试:


浏览器端访问http://localhost/activity?id=10000,则请求会被堵塞


用python写一个简单的post程序,向http://localhost//publish?id=10000上post数据,则浏览器端会马上得到该消息


注意:请求publish时,如果要发布消息,则必须得是POST请求,而且对应的Content-Type会被转发给长连接的Client。Get请求会返回当前是否有存在的channel_id。具体的Http Push协议细节,可参考http://pushmodule.slact.net/protocol.html


 


4.一些问题:



  • 如果push模块放在后端的nginx上,而前段nginx反响代理到后端,当Client发送长连接请求时,
    默认1分钟会直接断掉连接,返回504,不过可以设置proxy_read_timeout时间足够长来解决


  • 设置push_subscriber_concurrency broadcast,可以将push消息同时发送给同一个用户开启的多个浏览器窗口,但我在一个浏览器里开多个tab也来请求,却只有一个能得到消息,另外一个请求仍旧没有返回。当设置成first时,对应同一个channel_id,如果有多个长连接请求,则只有第一个会等待返回,其它的都返回409。设置成last时,我的测试结果是所有请求都会断掉,似乎是一个Bug?


  • 设置push_store_messages on,当没有对应的长连接请求时,可以暂时把msg缓存起来

  • 设置push_authorized_channels_only on可以打开认证功能,只有当publisher给对应的
    channel_id发送过消息后,Client端才可以发起一个长连接请求,否则会返回403 Forbidden错误


  • 当client发起一个长连接请求时,accesslog和后端应用是无法知道其发送请求。不过,通过向publish发送一个Get请求来判断是否有对应channel_id的长连接请求.


5.部分协议细节:




  • 订阅者:
    The server MUST accept all valid HTTP GET requests to the subscriber location. All other request methods SHOULD be responded to with a 405 Method Not Allowedstatus code.

    Subscriber requests are considered notifications of intent to receive some message. Subscribers may request existing messages, messages that are not yet available, and messages that are no longer available. The requested message is identified using the If-Modified-Since and If-None-Match request headers. A request with no If-Modified-Since header MUST be assumed to be requesting the oldest available message in a channel. Each 200 OK response containing a message MUST have itsLast-Modified and Etag headers set so that a request using those headers will be interpreted as a request for the next available message. Additionally, said 200 OKMUST contain the Content-Type header of the message publisher request, unless no Content-Type header had been provided or it is explicitly overridden by server configuration.


    There are several common mechanisms for performing an HTTP server push. The rest of the behavior of the server in response to a subscriber request SHOULD be configurable and MUST be selected from the following list of mechanisms:



    Long-Polling

    Requests for existing messages will be responded to immediately; responses to requests for messages not yet available MUST be delayed until the message becomes available. Delayed responses MUST satisfy all of the following conditions:

    • 200 OK response containing the message (and its Content-Type) MUST be sent immediately after the message becomes available
      . The entire response must be indistinguishable from a response to a request for an existing message.

    • If the channel the subscriber is waiting on is deleted or for some reason becomes unavailable, the server MUST immediately send a 410 Gone response.

    • If another subscriber has conflicted with this request, the server MUST immediately send a 409 Conflict response.



    Interval-Polling

    All requests will be responded to immediately. Requests for messages not yet available MUST produce a 304 Not Modified response code.


    In addition, when the server receives more than one concurrent subscriber request on the same channel, it MUST do one of the following:



    Broadcast

    No additional actions are performed

    Last-in, first-out

    All but the most recent long-held subscriber request on the channel are sent a 409 Conflict response.

    First-in, last-out

    All but the oldest request will be sent a 409 Conflict



    The server SHOULD make this selection configurable, and MUST default to broadcast behavior.



  • 发送者:

    The server MUST accept all valid HTTP requests to the publisher location. The server, when sent a publisher request, MUST satisfy all of the following conditions:



    • GET requests receive a 200 OK response for existing channels and a 404 Not Found otherwise.

    • PUT requests receive a 200 OK response. The request creates a channel if no channel with the given channel id exists.

    • DELETE requests receive a 200 OK if the channel identified by the channel id exists and has been completely deleted. All subscribers MUST have been sent a410 Gone response. Requests for nonexistent channels MUST be responded to with a 404 Not Found.


    • POST requests are used to send messages. The request MAY contain a body in any encoding representing a message to be sent over the channel. Themessage MUST be immediately delivered to all currently long-held subscriber requests. Additionally, the message MAY be stored for future retrieval and the oldest message stored for the channel MAY be deleted.


      A POST request MUST be replied to with a 201 Created if there were any long-held subscribers that have been sent this message, and with a 202 Acceptedotherwise.


      The Content-Type header of the request MUST be forwarded with the message.




     




 

使用Java java_memcached client的陷阱

这2天,才发现之前我们的某个开发人员使用java_memcached-release_2.0.1.jar是有问题的


在我们的某个模块里,需要2个memcached,分别提供不同的服务


于是,开发的人员就从网上粘贴来如下的码,分别生成2个MemcacheUtil类



折叠复制代码




  1. static {   

  2.     mcc = new MemCachedClient();   

  3.     SockIOPool pool = SockIOPool.getInstance();   

  4.     String[] servers = { "192.168.1.1:11122" };   

  5.     pool.setServers(servers);   

  6.     pool.setInitConn(5);   

  7.     pool.setMinConn(5);   

  8.     pool.setMaxConn(20);   

  9.     pool.setMaxIdle(1000 * 60 * 60 * 6);   

  10.     pool.setMaintSleep(30);   

  11.     pool.setNagle(false);   

  12.     pool.setSocketTO(3000);   

  13.     pool.setSocketConnectTO(0);   

  14.     pool.initialize();   

  15.   

  16.     mcc.setCompressEnable(true);   

  17.     mcc.setCompressThreshold(64 * 1024);   

  18. }  






在2个类里,分别初始化2个不同的mcc,这样做其实是有很大问题的


因为,在初始化MemCachedClient和SockIOPool时,均没有指定对应的name


这样,memcached client会默认生成一个name为default的pool


也就是说,即使你初始化了2个不同server对应的mcc,但实际上只有一个default的pool


这个pool里对应的memcache server完全取决于这2个类的初始化顺序


最后初始化的class,会覆盖掉第一次所用的server


因此,用这样的方式,实际上最后使用的还是其中的某一个memcache server


造成memcache中的数据全部乱掉


正确的方法应该是



折叠复制代码




  1. SockIOPool pool = SockIOPool.getInstance(poolName);   

  2. ....   

  3. MemCachedClient mcc = new MemCachedClient(poolName);  






初始化时,需要指定唯一的一个poolname,这样就能避免刚才的问题了


另外一个问题就是,用python或其它方式写入memcache中的数据,使用java client无法获取到


再查看了memcache client的源码后,发现了以下2点:


1. 它会默认对要存储的key进行URLEncoder的编码,如会把@给编码成%40


2. 在get调用时,如果没有传递参数asString,则它默认会对取到的value进行它自己的decode


所以,如果要想client能正确的取到没有编码过的数据,则需要



折叠复制代码




  1. //设置不对key做编码   

  2. mcc.setSanitizeKeys(false);   

  3. //最后一个参数true,表明get时直接返回String,而不进行解码   

  4. mcc.get("aaaaaaa@sohu.com",null,true);  




scrip:0112t>

Apache启动错误No space left on device的处理

以前的某次重启apache时,就遇到过这个问题,并解决了


没想到,昨天又碰到了此问题,第一反映还是用df查看空间


结果各个区的空间都正常,没有满


实在想不起来是怎么处理的了,于是又Google了一把如下:


系统的信号量可能用完了,造成apache启动时无法获取相应的信号量


貌似apache是使用信号量同它的子进程通信的


使用如下命令查看当前的系统已经使用的信号量



折叠复制代码




  1. ipcs -s

  2. ------ Semaphore Arrays --------

  3. key semid owner perms nsems

  4. 0x00000000 6684672 daemon 600 1

  5. 0x00000000 6750209 daemon 600 1

  6. 0x00000000 6782978 daemon 600 1

  7. ......




使用如下命令来查看当前内核支持的最大信号量



折叠复制代码




  1. ipcs -l

  2. ------ Semaphore Limits --------

  3. max number ofarrays=128

  4. max semaphores perarray=250

  5. max semaphores systemwide=32000

  6. max ops per semopcall=32

  7. semaphore maxvalue=32767




如下脚本来清除当前被占用的信号量,其中daemon是apache启动时对应的owner



折叠复制代码




  1. for i in `ipcs -s | awk '/daemon/ {print $2}'`; do (ipcrm -s $i); done




然后,再重启apache就可以了


通过编辑/etc/sysctl.conf文件,可以修改系统的信号量



折叠复制代码




  1. kernel.msgmni=1024

  2. kernel.sem=2503200032 128




其中,250为每个信号集中的最大信号量数目,32000为系统范围内的最大信号量总数目


32为每个信号发生时的最大系统操作数目,128为系统范围内的最大信号集总数目


然后,使用sysctl -p命令来使修改的参数生效

Oracle和Mysql的中文字段排序

Oracle中可以按照按照拼音、部首、笔画排序,可以通过设置NLS_SORT值来完成对应的排序:


SCHINESE_RADICAL_M 按照部首(第一顺序)、笔划(第二顺序)排序

SCHINESE_STROKE_M 按照笔划(第一顺序)、部首(第二顺序)排序

SCHINESE_PINYIN_M 按照拼音排序,系统的默认排序方式为拼音排序


以下为按照拼音进行排序的SQL:


select * from user_folder order by nlssort(foldername,'NLS_SORT=SCHINESE_PINYIN_M') desc;


在Mysql中,如果table的字符集是gbk,则默认的排序就是按照拼音来排的:


select * from user_folder order by foldername desc;


如果table的字符集是utf-8的,则默认的排序对中文来说是乱的,我们可以用convert来实现中文排序:


select * from test_utf8 order by convert(foldername using gbk);

郁闷的mongoexport导出工具

MongoDB提供了mongoexport工具,可以把一个collection导出成json格式或csv格式的文件

 

原以为,这个工具会像mysql中的select into out file那样,导出比较方便

 

没想到,测试之后,结果很郁闷

 

测试环境如下:

 

Linux 2.6.18-128.el5 x86_64

 

8G内存,2个4核cpu

 

mongodb中6000多万条数据,data和共占用40G空间

 

在一个建立索引的字段上,条件执行mongoexport后,似乎它并没有用到索引特性

 

导出花费的时间很长,而且占用的cpu和内存巨高,尤其是内存,最高时达到了7.6G

 

把我的心整的一闪一闪的,别把服务器给整成内存溢出了

 

还好,最好结果还是出来了,不过Mongod占的内存空间却一直没有释放

 

一直维持在7.6G左右,无奈,只好重启mongod了...

 

所用的命令如下:

 


折叠复制代码





  1. mongoexport -h 127.0.0.1:27017 -d mail_addr -c user_addr -u addr -p 'test' -q {'uid':'aaaaaa@sohu.com'}


 

显然,mongoexport没用使用索引,因为uid我建立的有索引

 

直接用mongo的client执行,结果返回很快

 


折叠复制代码





  1. db.user_addr.find({'uid':'aaaaaa@sohu.com'})


 

不知道是我命令用的有问题,还是说是mongoexport实现的有问题?

 

使用Jprofiler来监控jvm的运行

最近几天,线上的积分服务器不停的报警重启


看了resin的log信息,既没有OutofMemory,也没有其它的异常


偶尔有几个“Too many open files”的异常


通过ulimit -a查看最大打开文件数,发现是1024,于是执行


ulimit -SHn 65536


调大打开文件数目,但还是没有作用,用lsof -p来查看对应的进程


有1000多个打开的文件,而且有很多sock文件,一直处于ESTAB状态,似乎没有释放


于是,开始怀疑是程序的某个地方有问题,造成resin的Thread堵塞


由于从resin的log里无法定位到具体的位置,所以就想到了用Jprofiler来调试


在Jprofiler里建立一个remote application后,就能监控服务器上resin的各种状态了


可以查看内存状态,cpu状态,线程状态,虚拟机的状态等


由于我怀疑是线程堵塞,所以就直接到Thread Views里查看线程情况


使用Thread Dump,Dump出某个时刻的所有线程


看到有很多如下的Thread:



折叠复制代码




  1. Thread resin-tcp-connection-127.0.0.1:6837-373:   

  2.   at sun.misc.Unsafe.park(boolean, long)  

  3.   at java.util.concurrent.locks.LockSupport.park()  

  4.   at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt()  

  5.   at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(int)  

  6.   at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(int)  

  7.   at java.util.concurrent.Semaphore.acquire()  

  8.   at com.sohu.score.common.SubScoreSocketPool.subScore(java.lang.String, int)  






很明显,是方法subScore出问题了,造成一堆的Thread堵在那个地方,不释放资源,把resin给堵死了


然后,在对应的方法里加上debug log,最终很快就找出了错误所在


原来的程序使用了信号量semaphore来获取连接,对于socket结果正常,会release对应的信号量


但当socket返回错误信息时,程序没有release对应的semaphore就直接return了,导致semaphore很快被用完了


很多thread堵塞在了Semaphore.acquire() 地方


修改了程序后,Resin就运行正常了...


对于程序中的内存泄露,使用Jprofiler也能很容易的查出来


只要我们把某个时刻的heap给dump出来,就能很快看出占用内存过大的方法


内存泄露基本上就是对应的方法造成的

Jprofiler的安装配置

JProfiler 是一个用于 java 系统监控分析的软件,功能很强大


它可以监控普通的 java application, application server 等


除了可以监控本地的程序,还可以对远程服务器上跑的应用进行监控


如果需要对远程服务器上的webserver进行监控,需要下载windows版本和linux版本



  1. 下载jprofiler_windows_6_0_3.zip,解压后,直接运行bin/jprofiler.exe即可开始安装

  2. 下载jprofiler_linux_6_0_3.sh,执行:


  3. 折叠复制代码




    1. chmod a+x jprofiler_linux_6_0_3.sh

    2. ./jprofiler_linux_6_0_3.sh

    3. vi /etc/profile

    4. export LD_LIBRARY_PATH=/opt/jprofiler6/bin/linux-x86:$LD_LIBRARY_PATH





  4. 在webserver中配置jprofiler,加入以下内容:对于Resin2.x和Resin3.0,将以上内容配置在resin/bin/wrapper.pl中的$JAVA_ARGS中,对于Resin3.1.x,则配置在resin.conf中 的<jvm-arg>中即可



折叠复制代码




  1. -agentpath:/opt/jprofiler6/bin/linux-x86/libjprofilerti.so=port=8849




       4. 在windows上启动jprofiler,新建一个remote application session,一步一步的走下去


注意:如果新建session的时候,采用的是默认的wait for a conectin from the JProfiler GUI,那么在resin 里配置好Jprofiler后,resin的进程并不会马上启动,只有当Jprofiler的客户端连接上8849端口后,resin才会真正的启动


 

昕昕发烧了

 据昕昕奶奶说,昨天下午昕昕就有些不舒服


睡觉也不好好睡,睡觉前还和奶奶说:


我不舒服,要吃药...


奶奶一摸头,有些发烧了,就给他吃了一包感冒药


6点多钟,昕昕妈妈给家打电话时


昕昕听到了,就开始哭,哭了一阵子,就又自己睡了


等我回去后,他还没醒...


后来给他量量体温,37.5度,稍微有一点高


就给昕昕妈打了电话,买了一盒美林预备着


昨晚上睡觉中,他还有些烧


早上起来一量,38度,就给他吃了点美林


中午打电话,据昕昕奶奶说,今天上午一直没烧


玩的也挺好的,希望能赶紧好吧......

Git clone远程分支

git clone默认会把远程仓库整个给clone下来


但只会在本地默认创建一个master分支


如果远程还有其他的分支,此时用git branch -a查看所有分支:



折叠复制代码




  1. * master   

  2. remotes/origin/HEAD -> origin/master   

  3. remotes/origin/master   

  4. remotes/origin/python_mail.skin   

  5. remotes/origin/udisk   

  6. remotes/origin/vip






 能看到远程的所有的分支,如remotes/origin/python_mail.skin


可以使用checkout命令来把远程分支取到本地,并自动建立tracking



折叠复制代码




  1. $ git checkout -b python_mail.skin origin/python_mail.skin   

  2. Branch python_mail.skin set up to track remote branch python_mail.skin from origin.   

  3. Switched to a new branch 'python_mail.skin'




或者使用-t参数,它默认会在本地建立一个和远程分支名字一样的分支



折叠复制代码




  1. $ git checkout -t origin/python_mail.skin




 也可以使用fetch来做:



折叠复制代码




  1. $ git fetch origin python_mail.skin:python_mail.skin





 不过通过fetch命令来建立的本地分支不是一个track branch,而且成功后不会自动切换到该分支上


注意:不要在本地采用如下方法:



折叠复制代码




  1. $ git branch python_mail.skin   

  2. $ git checkout python_mail.skin   

  3. $ git pull origin python_mail.skin:python_mail.skin





因为,这样建立的branch是以master为基础建立的,再pull下来的话,会和master的内容进行合并,有可能会发生冲突...

最新文章

最近回复

  • feifei435:这两个URI实际是不一样的
  • zsy: git push origin 分支 -f 给力!
  • 冼敏兵:简单易懂,good fit
  • Jack:无需改配置文件,看着累! # gluster volume se...
  • Mr.j:按照你的方法凑效了,折腾死了。。。。
  • zheyemaster:补充一句:我的网站路径:D:\wamp\www ~~菜鸟站长, ...
  • zheyemaster:wamp2.5(apache2.4.9)下局域网访问403错误的...
  • Git中pull对比fetch和merge | 炼似春秋:[…] 首先,我搜索了git pull和git fe...
  • higkoo:总结一下吧, 性能调优示例: gluster volume s...
  • knowaeap:请问一下博主,你维护的openyoudao支持opensuse吗

分类

归档

其它