blogjava-凯发k8网页登录

blogjava-凯发k8网页登录http://www.blogjava.net/xiaomage234/category/41065.html生命本就是一次凄美的漂流,记忆中放不下的,永远是孩提时代的那一份浪漫与纯真!zh-cnfri, 15 apr 2016 08:14:29 gmtfri, 15 apr 2016 08:14:29 gmt60elasticsearch安装和配置head、bigdesk、ikanalyzerhttp://www.blogjava.net/xiaomage234/archive/2016/04/15/430105.html小马歌小马歌fri, 15 apr 2016 06:03:00 gmthttp://www.blogjava.net/xiaomage234/archive/2016/04/15/430105.htmlhttp://www.blogjava.net/xiaomage234/comments/430105.htmlhttp://www.blogjava.net/xiaomage234/archive/2016/04/15/430105.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/430105.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/430105.html阅读全文

小马歌 2016-04-15 14:03
]]>
为最佳性能调优 nginx[转]http://www.blogjava.net/xiaomage234/archive/2015/07/10/426144.html小马歌小马歌fri, 10 jul 2015 02:23:00 gmthttp://www.blogjava.net/xiaomage234/archive/2015/07/10/426144.htmlhttp://www.blogjava.net/xiaomage234/comments/426144.htmlhttp://www.blogjava.net/xiaomage234/archive/2015/07/10/426144.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/426144.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/426144.html阅读全文

小马歌 2015-07-10 10:23
]]>
tomcat使用apr提高性能[转]http://www.blogjava.net/xiaomage234/archive/2015/03/16/423496.html小马歌小马歌mon, 16 mar 2015 10:59:00 gmthttp://www.blogjava.net/xiaomage234/archive/2015/03/16/423496.htmlhttp://www.blogjava.net/xiaomage234/comments/423496.htmlhttp://www.blogjava.net/xiaomage234/archive/2015/03/16/423496.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/423496.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/423496.html

操作系统:centos6.3
tomcat:7.0.42
jdk:1.6.0_45
配置:8g,4核.

最近tomcat负载比较高,默认的配置和bio的处理方式已经无力支撑.据说apr能提升50%~60%的性能,所以尝试下apr优化.
apr介绍:

tomcat可以使用apr来提供超强的可伸缩性和性能,更好地集成本地服务器技术。  apr(apache portable runtime)是一个高可移植库,它是apache http server 2.x的核心。  apr有很多用途,包括访问高级io功能(例如sendfile,epoll和openssl),os级别功能(随机数生成,系统状态等等),本地进程管理(共享内存,nt管道和unix sockets)。这些功能可以使tomcat作为一个通常的前台web服务器,能更好地和其它本地web技术集成,总体上让java更有效率作为一个高性能web服务器平台而不是简单作为后台容器。  在产品环境中,特别是直接使用tomcat做web服务器的时候,应该使用tomcat native来提高其性能。

1. 服务器安装gcc

客户服务器连不上外网,服务器也没有gcc,所以先使用代理连接外网,修改/etc/yum.conf,加入代理配置:

proxy=http://10.103.0.46:808

如果需要验证加入用户名密码:

proxy_username=代理服务器用户名 proxy_password=代理服务器密码 

yum使用163的centos源:参考
先备份

mv /etc/yum.repos.d/centos-base.repo /etc/yum.repos.d/centos-base.repo.backup 

然后下载 放入到/etc/yum.repos.d/(操作前请做好相应备份)

运行以下命令生成缓存:

yum clean all yum makecache 

然后安装gcc:

yum -y install gcc 

2. 安装apr

从下载apr,apr-util,apr-iconv. 因为服务器没有配置全局的http代理,只是yum代理,所以下载之后传到服务器即可.

传输完安装apr:

tar zxvf apr-1.5.1.tar.gz cd apr-1.5.1 ./configure --prefix=/usr/local/apr make make install 

安装apr-iconv:

tar zxvf apr-iconv-1.2.1.tar.gz cd apr-iconv-1.2.1 ./configure --prefix=/usr/local/apr-iconv --with-apr=/usr/local/apr make make install 

安装apr-util:

tar zxvf apr-util-1.5.3.tar.gz cd apr-util-1.5.3 ./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr --with-apr-iconv=/usr/local/apr-iconv/bin/apriconv make   make install 

安装tomcat-native:首先到tomcat/bin目录下,找到对应的tar文件.

tar zxvf tomcat-native.tar.gz cd tomcat-native-1.1.27-src/jni/native/ ./configure --with-apr=/usr/local/apr --with-java-home=/usr/lib/jdk1.6.0_45 make make install 

安装完成之后 会出现如下提示信息

libraries have been installed in: /usr/local/apr/lib 

添加环境变量: vi /etc/profile在文件末尾处添加下面的变量

export ld_library_path=/usr/local/apr/lib 

然后执行下面命令,使环境变量即时生效

source /etc/profile 

以下为完整安装脚本:

#setup apr tar zxvf apr-1.5.1.tar.gz cd apr-1.5.1 ./configure --prefix=/usr/local/apr make && make install cd ../ #setup apr-iconv tar zxvf apr-iconv-1.2.1.tar.gz cd apr-iconv-1.2.1/ ./configure --prefix=/usr/local/apr-iconv --with-apr=/usr/local/apr make && make install cd ../ #setup apr-util tar zxvf apr-util-1.5.3.tar.gz cd apr-util-1.5.3 ./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr --with-apr-iconv=/usr/local/apr-iconv/bin/apriconv make && make install #setup tomcat-native cd /app/apache-tomcat-7.0.42/bin tar zxvf tomcat-native.tar.gz cd tomcat-native-1.1.27-src/jni/native ./configure --with-apr=/usr/local/apr --with-java-home=/usr/lib/jdk1.6.0_45 make && make install cd / #ld_library_path echo -e 'export ld_library_path=/usr/local/apr/lib' >> /etc/profile export ld_library_path=/usr/local/apr/lib source /etc/profile 

3. 配置tomcat

修改tomcat配置conf/server.xml:

      name="tomcatthreadpool" nameprefix="catalina-exec-"         maxthreads="800" minsparethreads="400"/>              port="80" executor="tomcatthreadpool" protocol="org.apache.coyote.http11.http11aprprotocol"                connectiontimeout="20000"                redirectport="8443" enablelookups="false" acceptcount="1000"/> 

修改为http11aprprotocol 协议.

之后启动tomcat即可.

遇到问题:

severe: failed to initialize the sslengine. org.apache.tomcat.jni.error: 70023: this function has not been implemented on this platform 

请关闭ssl侦听,除非你有使用ssl,修改conf/server.xml

 classname="org.apache.catalina.core.aprlifecyclelistener" sslengine="off" /> 

压测结果:

webbench -c 4000 -t 30 http://10.103.10.140/workbench/index.jsp webbench - simple web benchmark 1.5 凯发天生赢家一触即发官网 copyright (c) radim kolar 1997-2004, gpl open source software.  benchmarking: get http://10.103.10.140/workbench/index.jsp 4000 clients, running 30 sec.  speed=484340 pages/min, 2441573 bytes/sec. requests: 242170 susceed, 0 failed. 

参考:



小马歌 2015-03-16 18:59
]]>
13 款开源的全文搜索引擎[转]http://www.blogjava.net/xiaomage234/archive/2015/03/16/423495.html小马歌小马歌mon, 16 mar 2015 10:37:00 gmthttp://www.blogjava.net/xiaomage234/archive/2015/03/16/423495.htmlhttp://www.blogjava.net/xiaomage234/comments/423495.htmlhttp://www.blogjava.net/xiaomage234/archive/2015/03/16/423495.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/423495.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/423495.html

本文转载自,主要介绍13款现有的开源搜索引擎,你可以将它们用在你的项目中以实现检索功能。 


1.  lucene 

lucene的开发语言是java,也是java家族中最为出名的一个开源搜索引擎,在java世界中已经是标准的全文检索程序,它提供了完整的查询引擎和索引引擎,没有中文分词引擎,需要自己去实现,因此用lucene去做一个搜素引擎需要自己去架构.另外它不支持实时搜索,但linkedin和twitter有分别对lucene改进的实时搜素. 其中lucene有一个c 移植版本叫clucene,clucene因为使用c 编写,所以理论上要比lucene快. 

官方凯发k8网页登录主页: 

clucene官方凯发k8网页登录主页: 

2.  sphinx 

sphinx是一个用c 语言写的开源搜索引擎,也是现在比较主流的搜索引擎之一,在建立索引的事件方面比lucene快50%,但是索引文件比lucene要大一倍,因此sphinx在索引的建立方面是空间换取事件的策略,在检索速度上,和lucene相差不大,但检索精准度方面lucene要优于sphinx,另外在加入中文分词引擎难度方面,lucene要优于sphinx.其中sphinx支持实时搜索,使用起来比较简单方便. 

官方凯发k8网页登录主页: 

3.  xapian 

xapian是一个用c 编写的全文检索程序,它的api和检索原理和lucene在很多方面都很相似,算是填补了lucene在c 中的一个空缺. 

官方凯发k8网页登录主页: 

4.  nutch 

nutch是一个用java实现的开源的web搜索引擎,包括爬虫crawler,索引引擎,查询引擎. 其中nutch是基于lucene的,lucene为nutch提供了文本索引和搜索的api. 

对于应该使用lucene还是使用nutch,应该是如果你不需要抓取数据的话,应该使用lucene,最常见的应用是:你有数据源,需要为这些数据提供一个搜索页面,在这种情况下,最好的方式是直接从数据库中取出数据,并用lucene api建立索引. 

官方凯发k8网页登录主页: 

5.  dataparksearch 

dataparksearch是一个用c语言实现的开源的搜索引擎. 其中网页排序是采用神经网络模型.  其中支持http,https,ftp,nntp等下载网页.包括索引引擎,检索引擎和中文分词引擎(这个也是唯一的一个开源的搜索引擎里有中文分词引擎).能个性化定制搜索结果,拥有完整的日志记录. 

官方凯发k8网页登录主页: 

6.  zettair 

zettair是根据justin zobel的研究成果为基础的全文检索实验系统.它是用c语言实现的. 其中justin zobel在全文检索领域很有名气,是业界第一个系统提出倒排序索引差分压缩算法的人,倒排列表的压缩大大提高了检索和加载的性能,同时空间膨胀率也缩小到相当优秀的水平. 由于zettair是源于学术界,代码是由rmit university的搜索引擎组织写的,因此它的代码简洁精炼,算法高效,是学习倒排索引经典算法的非常好的实例. 其中支持linux,windows,mac os等系统. 

官方凯发k8网页登录主页: 

7.  indri 

indri是一个用c语言和c 语言写的全文检索引擎系统,是由university of massachusetts和carnegie mellon university合作推出的一个开源项目. 特点是跨平台,api接口支持java,php,c . 

官方凯发k8网页登录主页: 

8.  terrier 

terrier是由school of computing science,universityof glasgow用java开发的一个全文检索系统. 

官方凯发k8网页登录主页: 

9.  galago 

galago是一个用java语言写的关于文本搜索的工具集. 其中包括索引引擎和查询引擎,还包括一个叫tupleflow的分布式计算框架(和google的mapreduce很像).这个检索系统支持很多indri查询语言. 

官方凯发k8网页登录主页: 

10.  zebra 

zebra是一个用c语言实现的检索程序,特点是对大数据的支持,支持email,xml,marc等格式的数据. 

官方凯发k8网页登录主页: 

11.  solr 

solr是一个用java开发的独立的企业级搜索应用服务器,它提供了类似于web-service的api接口,它是基于lucene的全文检索服务器,也算是lucene的一个变种,很多一线互联网公司都在使用solr,也算是一种成熟的凯发天生赢家一触即发官网的解决方案. 

官方凯发k8网页登录主页: 

12.  elasticsearch 

elasticsearch是一个采用java语言开发的,基于lucene构造的开源,分布式的搜索引擎. 设计用于云计算中,能够达到实时搜索,稳定可靠. elasticsearch的数据模型是json. 

官方凯发k8网页登录主页: 

13.  whoosh 

whoosh是一个用纯python写的开源搜索引擎. 

官方凯发k8网页登录主页:  
发布在[ 技术 ]  by 
  1.  
    不错
  1. 增加一个,solrcloud是基于solr和zookeeper的分布式搜索方案,是正在开发中的solr4.0的核心组件之一,它的主要思想是使用zookeeper作为集群的配置信息中心。它有几个特色功能:1)集中式的配置信息 2)自动容错 3)近实时搜索 4)查询时自动负载均衡


小马歌 2015-03-16 18:37
]]>
redis学习手册(set数据类型)http://www.blogjava.net/xiaomage234/archive/2014/12/01/420889.html小马歌小马歌mon, 01 dec 2014 11:45:00 gmthttp://www.blogjava.net/xiaomage234/archive/2014/12/01/420889.htmlhttp://www.blogjava.net/xiaomage234/comments/420889.htmlhttp://www.blogjava.net/xiaomage234/archive/2014/12/01/420889.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/420889.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/420889.html

一、概述:

      在redis中,我们可以将set类型看作为没有排序的字符集合,和list类型一样,我们也可以在该类型的数据值上执行添加、删除或判断某一元素是否存在等操作。需要说明的是,这些操作的时间复杂度为o(1),即常量时间内完成次操作。set可包含的最大元素数量是4294967295。
      和list类型不同的是,set集合中不允许出现重复的元素,这一点和c 标准库中的set容器是完全相同的。换句话说,如果多次添加相同元素,set中将仅保留该元素的一份拷贝。和list类型相比,set类型在功能上还存在着一个非常重要的特性,即在服务器端完成多个sets之间的聚合计算操作,如unions、intersections和differences。由于这些操作均在服务端完成,因此效率极高,而且也节省了大量的网络io开销。

二、相关命令列表:

命令原型时间复杂度命令描述返回值
sadd key member [member ...]o(n)时间复杂度中的n表示操作的成员数量。如果在插入的过程用,参数中有的成员在set中已经存在,该成员将被忽略,而其它成员仍将会被正常插入。如果执行该命令之前,该key并不存在,该命令将会创建一个新的set,此后再将参数中的成员陆续插入。如果该key的value不是set类型,该命令将返回相关的错误信息。本次操作实际插入的成员数量。
scard keyo(1)获取set中成员的数量。返回set中成员的数量,如果该key并不存在,返回0。
sismemberkey membero(1)判断参数中指定成员是否已经存在于与key相关联的set集合中。1表示已经存在,0表示不存在,或该key本身并不存在。
smembers keyo(n)时间复杂度中的n表示set中已经存在的成员数量。获取与该key关联的set中所有的成员。

返回set中所有的成员。

spop key o(1) 随机的移除并返回set中的某一成员。 由于set中元素的布局不受外部控制,因此无法像list那样确定哪个元素位于set的头部或者尾部。返回移除的成员,如果该key并不存在,则返回nil。
srem key member [member ...]o(n) 时间复杂度中的n表示被删除的成员数量。从与key关联的set中删除参数中指定的成员,不存在的参数成员将被忽略,如果该key并不存在,将视为空set处理。从set中实际移除的成员数量,如果没有则返回0。
srandmemberkey o(1) 和spop一样,随机的返回set中的一个成员,不同的是该命令并不会删除返回的成员。返回随机位置的成员,如果key不存在则返回nil。
smove source destination membero(1) 原子性的将参数中的成员从source键移入到destination键所关联的set中。因此在某一时刻,该成员或者出现在source中,或者出现在destination中。如果该成员在source中并不存在,该命令将不会再执行任何操作并返回0,否则,该成员将从source移入到destination。如果此时该成员已经在destination中存在,那么该命令仅是将该成员从source中移出。如果和key关联的value不是set,将返回相关的错误信息。1表示正常移动,0表示source中并不包含参数成员。
sdiff key [key ...]o(n) 时间复杂度中的n表示所有sets中成员的总数量。返回参数中第一个key所关联的set和其后所有keys所关联的sets中成员的差异。如果key不存在,则视为空set。差异结果成员的集合。
sdiffstoredestination key [key ...] o(n) 该命令和sdiff命令在功能上完全相同,两者之间唯一的差别是sdiff返回差异的结果成员,而该命令将差异成员存储在destination关联的set中。如果destination键已经存在,该操作将覆盖它的成员。返回差异成员的数量。
sinter key [key ...] o(n*m) 时间复杂度中的n表示最小set中元素的数量,m则表示参数中sets的数量。该命令将返回参数中所有keys关联的sets中成员的交集。因此如果参数中任何一个key关联的set为空,或某一key不存在,那么该命令的结果将为空集。交集结果成员的集合。
sinterstoredestination key [key ...]o(n*m) 该命令和sinter命令在功能上完全相同,两者之间唯一的差别是sinter返回交集的结果成员,而该命令将交集成员存储在destination关联的set中。如果destination键已经存在,该操作将覆盖它的成员。返回交集成员的数量。 
sunion key [key ...] o(n)时间复杂度中的n表示所有sets中成员的总数量。该命令将返回参数中所有keys关联的sets中成员的并集。并集结果成员的集合。
sunionstoredestination key [key ...] o(n) 该命令和sunion命令在功能上完全相同,两者之间唯一的差别是sunion返回并集的结果成员,而该命令将并集成员存储在destination关联的set中。如果destination键已经存在,该操作将覆盖它的成员。 返回并集成员的数量。

三、命令示例:

   1. sadd/smembers/scard/sismember:
    #在shell命令行下启动redis的客户端程序。
    /> redis-cli
    #插入测试数据,由于该键myset之前并不存在,因此参数中的三个成员都被正常插入。
    redis 127.0.0.1:6379> sadd myset a b c
    (integer) 3
    #由于参数中的a在myset中已经存在,因此本次操作仅仅插入了d和e两个新成员。
    redis 127.0.0.1:6379> sadd myset a d e
    (integer) 2
    #判断a是否已经存在,返回值为1表示存在。
    redis 127.0.0.1:6379> sismember myset a
    (integer) 1
    #判断f是否已经存在,返回值为0表示不存在。
    redis 127.0.0.1:6379> sismember myset f
    (integer) 0
    #通过smembers命令查看插入的结果,从结果可以,输出的顺序和插入顺序无关。
    redis 127.0.0.1:6379> smembers myset
    1) "c"
    2) "d"
    3) "a"
    4) "b"
    5) "e"
    #获取set集合中元素的数量。
    redis 127.0.0.1:6379> scard myset
    (integer) 5

    2. spop/srem/srandmember/smove:
    #删除该键,便于后面的测试。
    redis 127.0.0.1:6379> del myset
    (integer) 1
    #为后面的示例准备测试数据。
    redis 127.0.0.1:6379> sadd myset a b c d
    (integer) 4
    #查看set中成员的位置。
    redis 127.0.0.1:6379> smembers myset
    1) "c"
    2) "d"
    3) "a"
    4) "b"
    #从结果可以看出,该命令确实是随机的返回了某一成员。
    redis 127.0.0.1:6379> srandmember myset
    "c"
    #set中尾部的成员b被移出并返回,事实上b并不是之前插入的第一个或最后一个成员。
    redis 127.0.0.1:6379> spop myset
    "b"
    #查看移出后set的成员信息。
    redis 127.0.0.1:6379> smembers myset
    1) "c"
    2) "d"
    3) "a"
    #从set中移出a、d和f三个成员,其中f并不存在,因此只有a和d两个成员被移出,返回为2。
    redis 127.0.0.1:6379> srem myset a d f
    (integer) 2
    #查看移出后的输出结果。
    redis 127.0.0.1:6379> smembers myset
    1) "c"
    #为后面的smove命令准备数据。
    redis 127.0.0.1:6379> sadd myset a b
    (integer) 2
    redis 127.0.0.1:6379> sadd myset2 c d
    (integer) 2
    #将a从myset移到myset2,从结果可以看出移动成功。
    redis 127.0.0.1:6379> smove myset myset2 a
    (integer) 1
    #再次将a从myset移到myset2,由于此时a已经不是myset的成员了,因此移动失败并返回0。
    redis 127.0.0.1:6379> smove myset myset2 a
    (integer) 0
    #分别查看myset和myset2的成员,确认移动是否真的成功。
    redis 127.0.0.1:6379> smembers myset
    1) "b"
    redis 127.0.0.1:6379> smembers myset2
    1) "c"
    2) "d"
    3) "a"

   3. sdiff/sdiffstore/sinter/sinterstore:
    #为后面的命令准备测试数据。
    redis 127.0.0.1:6379> sadd myset a b c d
    (integer) 4
    redis 127.0.0.1:6379> sadd myset2 c
    (integer) 1
    redis 127.0.0.1:6379> sadd myset3 a c e
    (integer) 3
    #myset和myset2相比,a、b和d三个成员是两者之间的差异成员。再用这个结果继续和myset3进行差异比较,b和d是myset3不存在的成员。
    redis 127.0.0.1:6379> sdiff myset myset2 myset3
    1) "d"
    2) "b"
    #将3个集合的差异成员存在在diffkey关联的set中,并返回插入的成员数量。
    redis 127.0.0.1:6379> sdiffstore diffkey myset myset2 myset3
    (integer) 2
    #查看一下sdiffstore的操作结果。
    redis 127.0.0.1:6379> smembers diffkey
    1) "d"
    2) "b"
    #从之前准备的数据就可以看出,这三个set的成员交集只有c。
    redis 127.0.0.1:6379> sinter myset myset2 myset3
    1) "c"
    #将3个集合中的交集成员存储到与interkey关联的set中,并返回交集成员的数量。
    redis 127.0.0.1:6379> sinterstore interkey myset myset2 myset3
    (integer) 1
    #查看一下sinterstore的操作结果。
    redis 127.0.0.1:6379> smembers interkey
    1) "c"
    #获取3个集合中的成员的并集。    
    redis 127.0.0.1:6379> sunion myset myset2 myset3
    1) "b"
    2) "c"
    3) "d"
    4) "e"
    5) "a"
    #将3个集合中成员的并集存储到unionkey关联的set中,并返回并集成员的数量。
    redis 127.0.0.1:6379> sunionstore unionkey myset myset2 myset3
    (integer) 5
    #查看一下suiionstore的操作结果。
    redis 127.0.0.1:6379> smembers unionkey
    1) "b"
    2) "c"
    3) "d"
    4) "e"
    5) "a"

四、应用范围:

      1). 可以使用redis的set数据类型跟踪一些唯一性数据,比如访问某一博客的唯一ip地址信息。对于此场景,我们仅需在每次访问该博客时将访问者的ip存入redis中,set数据类型会自动保证ip地址的唯一性。
      2). 充分利用set类型的服务端聚合操作方便、高效的特性,可以用于维护数据对象之间的关联关系。比如所有购买某一电子设备的客户id被存储在一个指定的set中,而购买另外一种电子产品的客户id被存储在另外一个set中,如果此时我们想获取有哪些客户同时购买了这两种商品时,set的intersections命令就可以充分发挥它的方便和效率的优势了。

分类: 


小马歌 2014-12-01 19:45
]]>
redis学习手册(hashes数据类型)http://www.blogjava.net/xiaomage234/archive/2014/12/01/420888.html小马歌小马歌mon, 01 dec 2014 11:44:00 gmthttp://www.blogjava.net/xiaomage234/archive/2014/12/01/420888.htmlhttp://www.blogjava.net/xiaomage234/comments/420888.htmlhttp://www.blogjava.net/xiaomage234/archive/2014/12/01/420888.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/420888.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/420888.html

一、概述:

      我们可以将redis中的hashes类型看成具有string key和string value的map容器。所以该类型非常适合于存储值对象的信息。如username、password和age等。如果hash中包含很少的字段,那么该类型的数据也将仅占用很少的磁盘空间。每一个hash可以存储4294967295个键值对。

二、相关命令列表:

命令原型时间复杂度命令描述返回值
hset key field valueo(1)为指定的key设定field/value对,如果key不存在,该命令将创建新key以参数中的field/value对,如果参数中的field在该key中已经存在,则用新值覆盖其原有值。 1表示新的field被设置了新值,0表示field已经存在,用新值覆盖原有值。 
hget key field o(1) 返回指定key中指定field的关联值。返回参数中field的关联值,如果参数中的key或field不存,返回nil。
hexistskey field o(1) 判断指定key中的指定field是否存在。1表示存在,0表示参数中的field或key不存在。
hlen key o(1)获取该key所包含的field的数量。返回key包含的field数量,如果key不存在,返回0。
hdel key field [field ...] o(n)时间复杂度中的n表示参数中待删除的字段数量。从指定key的hashes value中删除参数中指定的多个字段,如果不存在的字段将被忽略。如果key不存在,则将其视为空hashes,并返回0.实际删除的field数量。
hsetnxkey field valueo(1)只有当参数中的key或field不存在的情况下,为指定的key设定field/value对,否则该命令不会进行任何操作。 1表示新的field被设置了新值,0表示key或field已经存在,该命令没有进行任何操作。
hincrbykey field increment o(1)增加指定key中指定field关联的value的值。如果key或field不存在,该命令将会创建一个新key或新field,并将其关联的value初始化为0,之后再指定数字增加的操作。该命令支持的数字是64位有符号整型,即increment可以负数。 返回运算后的值。
hgetallkeyo(n) 时间复杂度中的n表示key包含的field数量。获取该键包含的所有field/value。其返回格式为一个field、一个value,并以此类推。field/value的列表。
hkeyskey o(n)时间复杂度中的n表示key包含的field数量。返回指定key的所有fields名。field的列表。
hvalskey o(n)时间复杂度中的n表示key包含的field数量。返回指定key的所有values名。 value的列表。 
hmgetkey field [field ...] o(n) 时间复杂度中的n表示请求的field数量。获取和参数中指定fields关联的一组values。如果请求的field不存在,其值返回nil。如果key不存在,该命令将其视为空hash,因此返回一组nil。返回和请求fields关联的一组values,其返回顺序等同于fields的请求顺序。
hmset key field value [field value ...]o(n)时间复杂度中的n表示被设置的field数量。逐对依次设置参数中给出的field/value对。如果其中某个field已经存在,则用新值覆盖原有值。如果key不存在,则创建新key,同时设定参数中的field/value。   

三、命令示例:

    1. hset/hget/hdel/hexists/hlen/hsetnx:
    #在shell命令行启动redis客户端程序
    /> redis-cli
    #给键值为myhash的键设置字段为field1,值为stephen。
    redis 127.0.0.1:6379> hset myhash field1 "stephen"
    (integer) 1
    #获取键值为myhash,字段为field1的值。
    redis 127.0.0.1:6379> hget myhash field1
    "stephen"
    #myhash键中不存在field2字段,因此返回nil。
    redis 127.0.0.1:6379> hget myhash field2
    (nil)
    #给myhash关联的hashes值添加一个新的字段field2,其值为liu。
    redis 127.0.0.1:6379> hset myhash field2 "liu"
    (integer) 1
    #获取myhash键的字段数量。
    redis 127.0.0.1:6379> hlen myhash
    (integer) 2
    #判断myhash键中是否存在字段名为field1的字段,由于存在,返回值为1。
    redis 127.0.0.1:6379> hexists myhash field1
    (integer) 1
    #删除myhash键中字段名为field1的字段,删除成功返回1。
    redis 127.0.0.1:6379> hdel myhash field1
    (integer) 1
    #再次删除myhash键中字段名为field1的字段,由于上一条命令已经将其删除,因为没有删除,返回0。
    redis 127.0.0.1:6379> hdel myhash field1
    (integer) 0
    #判断myhash键中是否存在field1字段,由于上一条命令已经将其删除,因为返回0。
    redis 127.0.0.1:6379> hexists myhash field1
    (integer) 0
    #通过hsetnx命令给myhash添加新字段field1,其值为stephen,因为该字段已经被删除,所以该命令添加成功并返回1。
    redis 127.0.0.1:6379> hsetnx myhash field1 stephen
    (integer) 1
    #由于myhash的field1字段已经通过上一条命令添加成功,因为本条命令不做任何操作后返回0。
    redis 127.0.0.1:6379> hsetnx myhash field1 stephen
    (integer) 0

   2. hincrby:
    #删除该键,便于后面示例的测试。
    redis 127.0.0.1:6379> del myhash
    (integer) 1
    #准备测试数据,该myhash的field字段设定值1。
    redis 127.0.0.1:6379> hset myhash field 5
    (integer) 1
    #给myhash的field字段的值加1,返回加后的结果。
    redis 127.0.0.1:6379> hincrby myhash field 1
    (integer) 6
    #给myhash的field字段的值加-1,返回加后的结果。
    redis 127.0.0.1:6379> hincrby myhash field -1
    (integer) 5
    #给myhash的field字段的值加-10,返回加后的结果。
    redis 127.0.0.1:6379> hincrby myhash field -10
    (integer) -5   

    3. hgetall/hkeys/hvals/hmget/hmset:
    #删除该键,便于后面示例测试。
    redis 127.0.0.1:6379> del myhash
    (integer) 1
    #为该键myhash,一次性设置多个字段,分别是field1 = "hello", field2 = "world"。
    redis 127.0.0.1:6379> hmset myhash field1 "hello" field2 "world"
    ok
    #获取myhash键的多个字段,其中field3并不存在,因为在返回结果中与该字段对应的值为nil。
    redis 127.0.0.1:6379> hmget myhash field1 field2 field3
    1) "hello"
    2) "world"
    3) (nil)
    #返回myhash键的所有字段及其值,从结果中可以看出,他们是逐对列出的。
    redis 127.0.0.1:6379> hgetall myhash
    1) "field1"
    2) "hello"
    3) "field2"
    4) "world"
    #仅获取myhash键中所有字段的名字。
    redis 127.0.0.1:6379> hkeys myhash
    1) "field1"
    2) "field2"
    #仅获取myhash键中所有字段的值。
    redis 127.0.0.1:6379> hvals myhash
    1) "hello"
    2) "world" 

分类: 


小马歌 2014-12-01 19:44
]]>
redis学习手册(list数据类型)http://www.blogjava.net/xiaomage234/archive/2014/12/01/420887.html小马歌小马歌mon, 01 dec 2014 11:43:00 gmthttp://www.blogjava.net/xiaomage234/archive/2014/12/01/420887.htmlhttp://www.blogjava.net/xiaomage234/comments/420887.htmlhttp://www.blogjava.net/xiaomage234/archive/2014/12/01/420887.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/420887.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/420887.html

一、概述:

      在redis中,list类型是按照插入顺序排序的字符串链表。和数据结构中的普通链表一样,我们可以在其头部(left)和尾部(right)添加新的元素。在插入时,如果该键并不存在,redis将为该键创建一个新的链表。与此相反,如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除。list中可以包含的最大元素数量是4294967295。
      从元素插入和删除的效率视角来看,如果我们是在链表的两头插入或删除元素,这将会是非常高效的操作,即使链表中已经存储了百万条记录,该操作也可以在常量时间内完成。然而需要说明的是,如果元素插入或删除操作是作用于链表中间,那将会是非常低效的。相信对于有良好数据结构基础的开发者而言,这一点并不难理解。

二、相关命令列表:

命令原型时间复杂度命令描述返回值
lpush key value [value ...] o(1)在指定key所关联的list value的头部插入参数中给出的所有values。如果该key不存在,该命令将在插入之前创建一个与该key关联的空链表,之后再将数据从链表的头部插入。如果该键的value不是链表类型,该命令将返回相关的错误信息。 插入后链表中元素的数量。
lpushx key value o(1)  仅有当参数中指定的key存在时,该命令才会在其所关联的list value的头部插入参数中给出的value,否则将不会有任何操作发生。插入后链表中元素的数量。 
lrange key start stop o(s n)时间复杂度中的s为start参数表示的偏移量,n表示元素的数量。该命令的参数start和end都是0-based。即0表示链表头部(leftmost)的第一个元素。其中start的值也可以为负值,-1将表示链表中的最后一个元素,即尾部元素,-2表示倒数第二个并以此类推。该命令在获取元素时,start和end位置上的元素也会被取出。如果start的值大于链表中元素的数量,空链表将会被返回。如果end的值大于元素的数量,该命令则获取从start(包括start)开始,链表中剩余的所有元素。返回指定范围内元素的列表。
lpop key o(1) 返回并弹出指定key关联的链表中的第一个元素,即头部元素,。如果该key不存,返回nil。链表头部的元素。
llen keyo(1) 返回指定key关联的链表中元素的数量,如果该key不存在,则返回0。如果与该key关联的value的类型不是链表,则返回相关的错误信息。链表中元素的数量。
lrem key count value o(n) 时间复杂度中n表示链表中元素的数量。在指定key关联的链表中,删除前count个值等于value的元素。如果count大于0,从头向尾遍历并删除,如果count小于0,则从尾向头遍历并删除。如果count等于0,则删除链表中所有等于value的元素。如果指定的key不存在,则直接返回0。返回被删除的元素数量。
lset key index value o(n) 时间复杂度中n表示链表中元素的数量。但是设定头部或尾部的元素时,其时间复杂度为o(1)。设定链表中指定位置的值为新值,其中0表示第一个元素,即头部元素,-1表示尾部元素。如果索引值index超出了链表中元素的数量范围,该命令将返回相关的错误信息。 
lindex key index o(n) 时间复杂度中n表示在找到该元素时需要遍历的元素数量。对于头部或尾部元素,其时间复杂度为o(1)。该命令将返回链表中指定位置(index)的元素,index是0-based,表示头部元素,如果index为-1,表示尾部元素。如果与该key关联的不是链表,该命令将返回相关的错误信息。返回请求的元素,如果index超出范围,则返回nil。
ltrim key start stop o(n) n表示被删除的元素数量。该命令将仅保留指定范围内的元素,从而保证链接中的元素数量相对恒定。start和stop参数都是0-based,0表示头部元素。和其他命令一样,start和stop也可以为负值,-1表示尾部元素。如果start大于链表的尾部,或start大于stop,该命令不错报错,而是返回一个空的链表,与此同时该key也将被删除。如果stop大于元素的数量,则保留从start开始剩余的所有元素。 
linsert key before|after pivot value o(n) 时间复杂度中n表示在找到该元素pivot之前需要遍历的元素数量。这样意味着如果pivot位于链表的头部或尾部时,该命令的时间复杂度为o(1)。该命令的功能是在pivot元素的前面或后面插入参数中的元素value。如果key不存在,该命令将不执行任何操作。如果与key关联的value类型不是链表,相关的错误信息将被返回。成功插入后链表中元素的数量,如果没有找到pivot,返回-1,如果key不存在,返回0。
rpush key value [value ...] o(1) 在指定key所关联的list value的尾部插入参数中给出的所有values。如果该key不存在,该命令将在插入之前创建一个与该key关联的空链表,之后再将数据从链表的尾部插入。如果该键的value不是链表类型,该命令将返回相关的错误信息。 插入后链表中元素的数量。 
rpushx key value o(1) 仅有当参数中指定的key存在时,该命令才会在其所关联的list value的尾部插入参数中给出的value,否则将不会有任何操作发生。 插入后链表中元素的数量。 
rpop key o(1) 返回并弹出指定key关联的链表中的最后一个元素,即尾部元素,。如果该key不存,返回nil。 链表尾部的元素。 
rpoplpushsource destination o(1) 原子性的从与source键关联的链表尾部弹出一个元素,同时再将弹出的元素插入到与destination键关联的链表的头部。如果source键不存在,该命令将返回nil,同时不再做任何其它的操作了。如果source和destination是同一个键,则相当于原子性的将其关联链表中的尾部元素移到该链表的头部。返回弹出和插入的元素。

三、命令示例:

    1. lpush/lpushx/lrange:
    /> redis-cli    #在shell提示符下启动redis客户端工具。
    redis 127.0.0.1:6379> del mykey
    (integer) 1
    #mykey键并不存在,该命令会创建该键及与其关联的list,之后在将参数中的values从左到右依次插入。
    redis 127.0.0.1:6379> lpush mykey a b c d
    (integer) 4
    #取从位置0开始到位置2结束的3个元素。
    redis 127.0.0.1:6379> lrange mykey 0 2
    1) "d"
    2) "c"
    3) "b"
    #取链表中的全部元素,其中0表示第一个元素,-1表示最后一个元素。
    redis 127.0.0.1:6379> lrange mykey 0 -1
    1) "d"
    2) "c"
    3) "b"
    4) "a"
    #mykey2键此时并不存在,因此该命令将不会进行任何操作,其返回值为0。
    redis 127.0.0.1:6379> lpushx mykey2 e
    (integer) 0
    #可以看到mykey2没有关联任何list value。
    redis 127.0.0.1:6379> lrange mykey2 0 -1
    (empty list or set)
    #mykey键此时已经存在,所以该命令插入成功,并返回链表中当前元素的数量。
    redis 127.0.0.1:6379> lpushx mykey e
    (integer) 5
    #获取该键的list value的头部元素。
    redis 127.0.0.1:6379> lrange mykey 0 0
    1) "e"

    2. lpop/llen:
    redis 127.0.0.1:6379> lpush mykey a b c d
    (integer) 4
    redis 127.0.0.1:6379> lpop mykey
    "d"
    redis 127.0.0.1:6379> lpop mykey
    "c"
    #在执行lpop命令两次后,链表头部的两个元素已经被弹出,此时链表中元素的数量是2
    redis 127.0.0.1:6379> llen mykey
    (integer) 2

   3. lrem/lset/lindex/ltrim:
    #为后面的示例准备测试数据。
    redis 127.0.0.1:6379> lpush mykey a b c d a c
    (integer) 6
    #从头部(left)向尾部(right)变量链表,删除2个值等于a的元素,返回值为实际删除的数量。
    redis 127.0.0.1:6379> lrem mykey 2 a
    (integer) 2
    #看出删除后链表中的全部元素。
    redis 127.0.0.1:6379> lrange mykey 0 -1
    1) "c"
    2) "d"
    3) "c"
    4) "b"
    #获取索引值为1(头部的第二个元素)的元素值。
    redis 127.0.0.1:6379> lindex mykey 1
    "d"
    #将索引值为1(头部的第二个元素)的元素值设置为新值e。
    redis 127.0.0.1:6379> lset mykey 1 e
    ok
    #查看是否设置成功。
    redis 127.0.0.1:6379> lindex mykey 1
    "e"
    #索引值6超过了链表中元素的数量,该命令返回nil。
    redis 127.0.0.1:6379> lindex mykey 6
    (nil)
    #设置的索引值6超过了链表中元素的数量,设置失败,该命令返回错误信息。
    redis 127.0.0.1:6379> lset mykey 6 hh
    (error) err index out of range
    #仅保留索引值0到2之间的3个元素,注意第0个和第2个元素均被保留。
    redis 127.0.0.1:6379> ltrim mykey 0 2
    ok
    #查看trim后的结果。
    redis 127.0.0.1:6379> lrange mykey 0 -1
    1) "c"
    2) "e"
    3) "c"

    4. linsert:
    #删除该键便于后面的测试。
    redis 127.0.0.1:6379> del mykey
    (integer) 1
    #为后面的示例准备测试数据。
    redis 127.0.0.1:6379> lpush mykey a b c d e
    (integer) 5
    #在a的前面插入新元素a1。
    redis 127.0.0.1:6379> linsert mykey before a a1
    (integer) 6
    #查看是否插入成功,从结果看已经插入。注意lindex的index值是0-based。
    redis 127.0.0.1:6379> lindex mykey 0
    "e"
    #在e的后面插入新元素e2,从返回结果看已经插入成功。
    redis 127.0.0.1:6379> linsert mykey after e e2
    (integer) 7
    #再次查看是否插入成功。
    redis 127.0.0.1:6379> lindex mykey 1
    "e2"
    #在不存在的元素之前或之后插入新元素,该命令操作失败,并返回-1。
    redis 127.0.0.1:6379> linsert mykey after k a
    (integer) -1
    #为不存在的key插入新元素,该命令操作失败,返回0。
    redis 127.0.0.1:6379> linsert mykey1 after a a2
    (integer) 0

    5. rpush/rpushx/rpop/rpoplpush:
    #删除该键,以便于后面的测试。
    redis 127.0.0.1:6379> del mykey
    (integer) 1
    #从链表的尾部插入参数中给出的values,插入顺序是从左到右依次插入。
    redis 127.0.0.1:6379> rpush mykey a b c d
    (integer) 4
    #通过lrange的可以获悉rpush在插入多值时的插入顺序。
    redis 127.0.0.1:6379> lrange mykey 0 -1
    1) "a"
    2) "b"
    3) "c"
    4) "d"
    #该键已经存在并且包含4个元素,rpushx命令将执行成功,并将元素e插入到链表的尾部。
    redis 127.0.0.1:6379> rpushx mykey e
    (integer) 5
    #通过lindex命令可以看出之前的rpushx命令确实执行成功,因为索引值为4的元素已经是新元素了。
    redis 127.0.0.1:6379> lindex mykey 4
    "e"
    #由于mykey2键并不存在,因此该命令不会插入数据,其返回值为0。
    redis 127.0.0.1:6379> rpushx mykey2 e
    (integer) 0
    #在执行rpoplpush命令前,先看一下mykey中链表的元素有哪些,注意他们的位置关系。
    redis 127.0.0.1:6379> lrange mykey 0 -1
    1) "a"
    2) "b"
    3) "c"
    4) "d"
    5) "e"
    #将mykey的尾部元素e弹出,同时再插入到mykey2的头部(原子性的完成这两步操作)。
    redis 127.0.0.1:6379> rpoplpush mykey mykey2
    "e"
    #通过lrange命令查看mykey在弹出尾部元素后的结果。
    redis 127.0.0.1:6379> lrange mykey 0 -1
    1) "a"
    2) "b"
    3) "c"
    4) "d"
    #通过lrange命令查看mykey2在插入元素后的结果。
    redis 127.0.0.1:6379> lrange mykey2 0 -1
    1) "e"
    #将source和destination设为同一键,将mykey中的尾部元素移到其头部。
    redis 127.0.0.1:6379> rpoplpush mykey mykey
    "d"
    #查看移动结果。
    redis 127.0.0.1:6379> lrange mykey 0 -1
    1) "d"
    2) "a"
    3) "b"
    4) "c"

四、链表结构的小技巧:

      针对链表结构的value,redis在其官方文档中给出了一些实用技巧,如rpoplpush命令,下面给出具体的解释。
      redis链表经常会被用于消息队列的服务,以完成多程序之间的消息交换。假设一个应用程序正在执行lpush操作向链表中添加新的元素,我们通常将这样的程序称之为"生产者(producer)",而另外一个应用程序正在执行rpop操作从链表中取出元素,我们称这样的程序为"消费者(consumer)"。如果此时,消费者程序在取出消息元素后立刻崩溃,由于该消息已经被取出且没有被正常处理,那么我们就可以认为该消息已经丢失,由此可能会导致业务数据丢失,或业务状态的不一致等现象的发生。然而通过使用rpoplpush命令,消费者程序在从主消息队列中取出消息之后再将其插入到备份队列中,直到消费者程序完成正常的处理逻辑后再将该消息从备份队列中删除。同时我们还可以提供一个守护进程,当发现备份队列中的消息过期时,可以重新将其再放回到主消息队列中,以便其它的消费者程序继续处理。

分类: 


小马歌 2014-12-01 19:43
]]>
zookeeper 集群安装(单点与分布式成功安装)摘录http://www.blogjava.net/xiaomage234/archive/2014/07/23/416123.html小马歌小马歌wed, 23 jul 2014 03:57:00 gmthttp://www.blogjava.net/xiaomage234/archive/2014/07/23/416123.htmlhttp://www.blogjava.net/xiaomage234/comments/416123.htmlhttp://www.blogjava.net/xiaomage234/archive/2014/07/23/416123.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/416123.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/416123.html阅读全文

小马歌 2014-07-23 11:57
]]>
http post get 本质区别详解http://www.blogjava.net/xiaomage234/archive/2014/07/15/415848.html小马歌小马歌tue, 15 jul 2014 09:22:00 gmthttp://www.blogjava.net/xiaomage234/archive/2014/07/15/415848.htmlhttp://www.blogjava.net/xiaomage234/comments/415848.htmlhttp://www.blogjava.net/xiaomage234/archive/2014/07/15/415848.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/415848.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/415848.html阅读全文

小马歌 2014-07-15 17:22
]]>
使用redis的五个注意事项http://www.blogjava.net/xiaomage234/archive/2014/06/18/414878.html小马歌小马歌wed, 18 jun 2014 03:17:00 gmthttp://www.blogjava.net/xiaomage234/archive/2014/06/18/414878.htmlhttp://www.blogjava.net/xiaomage234/comments/414878.htmlhttp://www.blogjava.net/xiaomage234/archive/2014/06/18/414878.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/414878.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/414878.html下面内容来源于quora上的,问题是使用需要避免的五个问题。而回答中超出了五个问题的范畴,描述了五个使用redis的注意事项。如果你在使用或者考虑使用redis,可能你可以学习一下下面的一些建议,避免一下提到的问题。

1.使用key值前缀来作命名空间

虽然说redis支持多个数据库(默认32个,可以配置更多),但是除了默认的0号库以外,其它的都需要通过一个额外请求才能使用。所以用前缀作为命名空间可能会更明智一点。

另外,在使用前缀作为命名空间区隔不同key的时候,最好在程序中使用全局配置来实现,直接在代码里写前缀的做法要严格避免,这样可维护性实在太差了。

2.创建一个类似 ”registry” 的key用于标记key使用情况

为了更好的管理你的key值的使用,比如哪一类key值是属于哪个业务的,你通常会在内部wiki或者什么地方创建一个文档,通过查询这个文档,我们能够知道redis中的key都是什么作用。

与之结合,一个推荐的做法是,在redis里面保存一个registry值,这个值的名字可以类似于 __key_registry__ 这样的,这个key对应的value就是你文档的位置,这样我们在使用redis的时候,就能通过直接查询这个值获取到当前redis的使用情况了。

3.注意垃圾回收

redis是一个提供持久化功能的内存数据库,如果你不指定上面值的过期时间,并且也不进行定期的清理工作,那么你的redis内存占用会越来越大,当有一天它超过了系统可用内存,那么swap上场,离性能陡降的时间就不远了。所以在redis中保存数据时,一定要预先考虑好数据的生命周期,这有很多方法可以实现。

比如你可以采用redis自带的过期时间为你的数据设定过期时间。但是自动过期有一个问题,很有可能导致你还有大量内存可用时,就让key过期去释放内存,或者是内存已经不足了key还没有过期。

如果你想更精准的控制你的数据过期,你可以用一个zset来维护你的数据更新程度,你可以用时间戳作为score值,每次更新操作时更新一下score,这样你就得到了一个按更新时间排序序列串,你可以轻松地找到最老的数据,并且从最老的数据开始进行删除,一直删除到你的空间足够为止。

4.设计好你的sharding机制

redis目前并不支持sharding,但是当你的数据量超过单机内存时,你不得不考虑sharding的事(注意:slave不是用来做sharding操作的,只是数据的一个备份和读写分离而已)。

所以你可能需要考虑好数据量大了后的分片问题,比如你可以在只有一台机器的时候就在程序上设定一致性hash机制,虽然刚开始所有数据都hash到一台机器,但是当你机器越加越多的时候,你就只需要迁移少量的数据就能完成了。

5.不要有个锤子看哪都是钉子

当你使用redis构建你的服务的时候,一定要记住,你只是找了一个合适的工具来实现你需要的功能。而不是说你在用redis构建一个服务,这是很不同的,你把redis当作你很多工具中的一个,只在合适使用的时候再使用它,在不合适的时候选择其它的方法。

来源:



小马歌 2014-06-18 11:17
]]>
redis内存使用优化与存储http://www.blogjava.net/xiaomage234/archive/2014/05/09/413469.html小马歌小马歌fri, 09 may 2014 09:00:00 gmthttp://www.blogjava.net/xiaomage234/archive/2014/05/09/413469.htmlhttp://www.blogjava.net/xiaomage234/comments/413469.htmlhttp://www.blogjava.net/xiaomage234/archive/2014/05/09/413469.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/413469.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/413469.htmlredis常用数据类型

redis最为常用的数据类型主要有以下五种:

  • string
  • hash
  • list
  • set
  • sorted set

在具体描述这几种数据类型之前,我们先通过一张图了解下redis内部内存管理中是如何描述这些不同数据类型的:

首先redis内部使用一个redisobject对象来表示所有的key和value,redisobject最主要的信息如上图所示:type代表一个value对象具体是何种数据类型,encoding是不同数据类型在redis内部的存储方式,比如:type=string代表value存储的是一个普通字符串,那么对应的encoding可以是raw或者是int,如果是int则代表实际redis内部是按数值型类存储和表示这个字符串的,当然前提是这个字符串本身可以用数值表示,比如:"123" "456"这样的字符串。

这里需要特殊说明一下vm字段,只有打开了redis的虚拟内存功能,此字段才会真正的分配内存,该功能默认是关闭状态的,该功能会在后面具体描述。通过上图我们可以发现redis使用redisobject来表示所有的key/value数据是比较浪费内存的,当然这些内存管理成本的付出主要也是为了给redis不同数据类型提供一个统一的管理接口,实际作者也提供了多种方法帮助我们尽量节省内存使用,我们随后会具体讨论。

下面我们先来逐一的分析下这五种数据类型的使用和内部实现方式:

  • string

    常用命令:

    set,get,decr,incr,mget 等。

    应用场景:

    string是最常用的一种数据类型,普通的key/value存储都可以归为此类,这里就不所做解释了。

    实现方式:

    string在redis内部存储默认就是一个字符串,被redisobject所引用,当遇到incr,decr等操作时会转成数值型进行计算,此时redisobject的encoding字段为int。

  • hash

    常用命令:

    hget,hset,hgetall 等。

    应用场景:

    我们简单举个实例来描述下hash的应用场景,比如我们要存储一个用户信息对象数据,包含以下信息:

    用户id为查找的key,存储的value用户对象包含姓名,年龄,生日等信息,如果用普通的key/value结构来存储,主要有以下2种存储方式:

    第一种方式将用户id作为查找key,把其他信息封装成一个对象以序列化的方式存储,这种方式的缺点是,增加了序列化/反序列化的开销,并且在需要修改其中一项信息时,需要把整个对象取回,并且修改操作需要对并发进行保护,引入cas等复杂问题。

    第二种方法是这个用户信息对象有多少成员就存成多少个key-value对儿,用用户id 对应属性的名称作为唯一标识来取得对应属性的值,虽然省去了序列化开销和并发问题,但是用户id为重复存储,如果存在大量这样的数据,内存浪费还是非常可观的。

    那么redis提供的hash很好的解决了这个问题,redis的hash实际是内部存储的value为一个hashmap,并提供了直接存取这个map成员的接口,如下图:

    也就是说,key仍然是用户id, value是一个map,这个map的key是成员的属性名,value是属性值,这样对数据的修改和存取都可以直接通过其内部map的key(redis里称内部map的key为field), 也就是通过 key(用户id) field(属性标签) 就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题。很好的解决了问题。

    这里同时需要注意,redis提供了接口(hgetall)可以直接取到全部的属性数据,但是如果内部map的成员很多,那么涉及到遍历整个内部map的操作,由于redis单线程模型的缘故,这个遍历操作可能会比较耗时,而另其它客户端的请求完全不响应,这点需要格外注意。

    实现方式:

    上面已经说到redis hash对应value内部实际就是一个hashmap,实际这里会有2种不同实现,这个hash的成员比较少时redis为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的hashmap结构,对应的value redisobject的encoding为zipmap,当成员数量增大时会自动转成真正的hashmap,此时encoding为ht。

  • list

    常用命令:

    lpush,rpush,lpop,rpop,lrange等。

    应用场景:

    redis list的应用场景非常多,也是redis最重要的数据结构之一,比如twitter的关注列表,粉丝列表等都可以用redis的list结构来实现,比较好理解,这里不再重复。

    实现方式:

    redis list的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销,redis内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构。

  • set

    常用命令:

    sadd,spop,smembers,sunion 等。

    应用场景:

    redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。

    实现方式:

    set 的内部实现是一个 value永远为null的hashmap,实际就是通过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因。

  • sorted set

    常用命令:

    zadd,zrange,zrem,zcard等

    使用场景:

    redis sorted set的使用场景与set类似,区别是set不是自动有序的,而sorted set可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。当你需要一个有序的并且不重复的集合列表,那么可以选择sorted set数据结构,比如twitter 的public timeline可以以发表时间作为score来存储,这样获取时就是自动按时间排好序的。

    实现方式:

    redis sorted set的内部使用hashmap和跳跃表(skiplist)来保证数据的存储和有序,hashmap里放的是成员到score的映射,而跳跃表里存放的是所有的成员,排序依据是hashmap里存的score,使用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。

常用内存优化手段与参数

通过我们上面的一些实现上的分析可以看出redis实际上的内存管理成本非常高,即占用了过多的内存,作者对这点也非常清楚,所以提供了一系列的参数和手段来控制和节省内存,我们分别来讨论下。

首先最重要的一点是不要开启redis的vm选项,即虚拟内存功能,这个本来是作为redis存储超出物理内存数据的一种数据在内存与磁盘换入换出的一个持久化策略,但是其内存管理成本也非常的高,并且我们后续会分析此种持久化策略并不成熟,所以要关闭vm功能,请检查你的redis.conf文件中 vm-enabled 为 no。

其次最好设置下redis.conf中的maxmemory选项,该选项是告诉redis当使用了多少物理内存后就开始拒绝后续的写入请求,该参数能很好的保护好你的redis不会因为使用了过多的物理内存而导致swap,最终严重影响性能甚至崩溃。

另外redis为不同数据类型分别提供了一组参数来控制内存使用,我们在前面详细分析过redis hash是value内部为一个hashmap,如果该map的成员数比较少,则会采用类似一维线性的紧凑格式来存储该map, 即省去了大量指针的内存开销,这个参数控制对应在redis.conf配置文件中下面2项:

hash-max-zipmap-entries 64  hash-max-zipmap-value 512  hash-max-zipmap-entries 

含义是当value这个map内部不超过多少个成员时会采用线性紧凑格式存储,默认是64,即value内部有64个以下的成员就是使用线性紧凑存储,超过该值自动转成真正的hashmap。

hash-max-zipmap-value 含义是当 value这个map内部的每个成员值长度不超过多少字节就会采用线性紧凑存储来节省空间。

以上2个条件任意一个条件超过设置值都会转换成真正的hashmap,也就不会再节省内存了,那么这个值是不是设置的越大越好呢,答案当然是否定的,hashmap的优势就是查找和操作的时间复杂度都是o(1)的,而放弃hash采用一维存储则是o(n)的时间复杂度,如果

成员数量很少,则影响不大,否则会严重影响性能,所以要权衡好这个值的设置,总体上还是最根本的时间成本和空间成本上的权衡。

同样类似的参数还有:

list-max-ziplist-entries 512

说明:list数据类型多少节点以下会采用去指针的紧凑存储格式。

list-max-ziplist-value 64 

说明:list数据类型节点值大小小于多少字节会采用紧凑存储格式。

set-max-intset-entries 512 

说明:set数据类型内部数据如果全部是数值型,且包含多少节点以下会采用紧凑格式存储。

最后想说的是redis内部实现没有对内存分配方面做过多的优化,在一定程度上会存在内存碎片,不过大多数情况下这个不会成为redis的性能瓶颈,不过如果在redis内部存储的大部分数据是数值型的话,redis内部采用了一个shared integer的方式来省去分配内存的开销,即在系统启动时先分配一个从1~n 那么多个数值对象放在一个池子中,如果存储的数据恰好是这个数值范围内的数据,则直接从池子里取出该对象,并且通过引用计数的方式来共享,这样在系统存储了大量数值下,也能一定程度上节省内存并且提高性能,这个参数值n的设置需要修改源代码中的一行宏定义redis_shared_integers,该值默认是10000,可以根据自己的需要进行修改,修改后重新编译就可以了。

redis的持久化机制

redis由于支持非常丰富的内存数据结构类型,如何把这些复杂的内存组织方式持久化到磁盘上是一个难题,所以redis的持久化方式与传统数据库的方式有比较多的差别,redis一共支持四种持久化方式,分别是:

  • 定时快照方式(snapshot)
  • 基于语句追加文件的方式(aof)
  • 虚拟内存(vm)
  • diskstore方式

在设计思路上,前两种是基于全部数据都在内存中,即小数据量下提供磁盘落地功能,而后两种方式则是作者在尝试存储数据超过物理内存时,即大数据量的数据存储,截止到本文,后两种持久化方式仍然是在实验阶段,并且vm方式基本已经被作者放弃,所以实际能在生产环境用的只有前两种,换句话说redis目前还只能作为小数据量存储(全部数据能够加载在内存中),海量数据存储方面并不是redis所擅长的领域。下面分别介绍下这几种持久化方式:

定时快照方式(snapshot):

该持久化方式实际是在redis内部一个定时器事件,每隔固定时间去检查当前数据发生的改变次数与时间是否满足配置的持久化触发的条件,如果满足则通过操作系统fork调用来创建出一个子进程,这个子进程默认会与父进程共享相同的地址空间,这时就可以通过子进程来遍历整个内存来进行存储操作,而主进程则仍然可以提供服务,当有写入时由操作系统按照内存页(page)为单位来进行copy-on-write保证父子进程之间不会互相影响。

该持久化的主要缺点是定时快照只是代表一段时间内的内存映像,所以系统重启会丢失上次快照与重启之间所有的数据。

基于语句追加方式(aof):

aof方式实际类似mysql的基于语句的binlog方式,即每条会使redis内存数据发生改变的命令都会追加到一个log文件中,也就是说这个log文件就是redis的持久化数据。

aof的方式的主要缺点是追加log文件可能导致体积过大,当系统重启恢复数据时如果是aof的方式则加载数据会非常慢,几十g的数据可能需要几小时才能加载完,当然这个耗时并不是因为磁盘文件读取速度慢,而是由于读取的所有命令都要在内存中执行一遍。另外由于每条命令都要写log,所以使用aof的方式,redis的读写性能也会有所下降。

虚拟内存方式:

虚拟内存方式是redis来进行用户空间的数据换入换出的一个策略,此种方式在实现的效果上比较差,主要问题是代码复杂,重启慢,复制慢等等,目前已经被作者放弃。

diskstore方式:

diskstore方式是作者放弃了虚拟内存方式后选择的一种新的实现方式,也就是传统的b-tree的方式,目前仍在实验阶段,后续是否可用我们可以拭目以待。

redis持久化磁盘io方式及其带来的问题

有redis线上运维经验的人会发现redis在物理内存使用比较多,但还没有超过实际物理内存总容量时就会发生不稳定甚至崩溃的问题,有人认为是基于快照方式持久化的fork系统调用造成内存占用加倍而导致的,这种观点是不准确的,因为fork 调用的copy-on-write机制是基于操作系统页这个单位的,也就是只有有写入的脏页会被复制,但是一般你的系统不会在短时间内所有的页都发生了写入而导致复制,那么是什么原因导致redis崩溃的呢?

答案是redis的持久化使用了buffer io造成的,所谓buffer io是指redis对持久化文件的写入和读取操作都会使用物理内存的page cache,而大多数数据库系统会使用direct io来绕过这层page cache并自行维护一个数据的cache,而当redis的持久化文件过大(尤其是快照文件),并对其进行读写时,磁盘文件中的数据都会被加载到物理内存中作为操作系统对该文件的一层cache,而这层cache的数据与redis内存中管理的数据实际是重复存储的,虽然内核在物理内存紧张时会做page cache的剔除工作,但内核很可能认为某块page cache更重要,而让你的进程开始swap ,这时你的系统就会开始出现不稳定或者崩溃了。我们的经验是当你的redis物理内存使用超过内存总容量的3/5时就会开始比较危险了。

下图是redis在读取或者写入快照文件dump.rdb后的内存数据图:

总结:

  1. 根据业务需要选择合适的数据类型,并为不同的应用场景设置相应的紧凑存储参数。
  2. 当业务场景不需要数据持久化时,关闭所有的持久化方式可以获得最佳的性能以及最大的内存使用量。
  3. 如果需要使用持久化,根据是否可以容忍重启丢失部分数据在快照方式与语句追加方式之间选择其一,不要使用虚拟内存以及diskstore方式。
  4. 不要让你的redis所在机器物理内存使用超过实际内存总量的3/5。

转载自:



小马歌 2014-05-09 17:00
]]>
jedis的publish/subscribe功能的运用http://www.blogjava.net/xiaomage234/archive/2014/05/09/413463.html小马歌小马歌fri, 09 may 2014 07:21:00 gmthttp://www.blogjava.net/xiaomage234/archive/2014/05/09/413463.htmlhttp://www.blogjava.net/xiaomage234/comments/413463.htmlhttp://www.blogjava.net/xiaomage234/archive/2014/05/09/413463.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/413463.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/413463.html阅读全文

小马歌 2014-05-09 15:21
]]>
websocket协议分析http://www.blogjava.net/xiaomage234/archive/2014/04/19/412684.html小马歌小马歌sat, 19 apr 2014 07:16:00 gmthttp://www.blogjava.net/xiaomage234/archive/2014/04/19/412684.htmlhttp://www.blogjava.net/xiaomage234/comments/412684.htmlhttp://www.blogjava.net/xiaomage234/archive/2014/04/19/412684.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/412684.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/412684.html

内容不断更新,目前包括协议中握手和数据帧的分析

 

1.1 背景

1.2 协议概览

协议包含两部分:握手,数据传输。

客户端的握手如下:
get /chat http/1.1
host: server.example.com
upgrade: websocket
connection: upgrade
sec-websocket-key: dghlihnhbxbszsbub25jzq==
origin: http://example.com
sec-websocket-protocol: chat, superchat
sec-websocket-version: 13

服务端的握手如下:
http/1.1 101 switching protocols upgrade: websocket connection: upgrade sec-websocket-accept: s3pplmbitxaq9kygzzhzrbk xoo= sec-websocket-protocol: chat
客户端和服务端都发送了握手,并且成功,数据传输即可开始。
 
1.3 发起握手
发起握手是为了兼容基于http的服务端程序,这样一个端口可以同时处理http客户端和websocket客户端
因此websocket客户端握手是一个http upgrade请求:
get /chat http/1.1 host: server.example.com upgrade: websocket connection: upgrade sec-websocket-key: dghlihnhbxbszsbub25jzq== origin: http://example.com sec-websocket-protocol: chat, superchat sec-websocket-version: 13
握手中的域的顺序是任意的。
 
5 数据帧
5.1 概述
webscoket协议中,数据以帧序列的形式传输。
考虑到数据安全性,客户端向服务器传输的数据帧必须进行掩码处理。服务器若接收到未经过掩码处理的数据帧,则必须主动关闭连接。
服务器向客户端传输的数据帧一定不能进行掩码处理。客户端若接收到经过掩码处理的数据帧,则必须主动关闭连接。
针对上情况,发现错误的一方可向对方发送close帧(状态码是1002,表示协议错误),以关闭连接。
5.2 帧协议
websocket数据帧结构如下图所示:
      0                   1                   2                   3       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1       - - - - ------- - ------------- -------------------------------       |f|r|r|r| opcode|m| payload len |    extended payload length    |      |i|s|s|s|  (4)  |a|     (7)     |             (16/64)           |      |n|v|v|v|       |s|             |   (if payload len==126/127)   |      | |1|2|3|       |k|             |                               |       - - - - ------- - -------------  - - - - - - - - - - - - - - -        |     extended payload length continued, if payload len == 127  |        - - - - - - - - - - - - - - -  -------------------------------       |                               |masking-key, if mask set to 1  |       ------------------------------- -------------------------------       | masking-key (continued)       |          payload data         |       -------------------------------- - - - - - - - - - - - - - - -        :                     payload data continued ...                :        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -        |                     payload data continued ...                |       --------------------------------------------------------------- 
 
fin:1位
表示这是消息的最后一帧(结束帧),一个消息由一个或多个数据帧构成。若消息由一帧构成,起始帧即结束帧。
 
rsv1,rsv2,rsv3:各1位
must be 0 unless an extension is negotiated that defines meanings for non-zero values. if a nonzero value is received and none of the negotiated extensions defines the meaning of such a nonzero value, the receiving endpoint must _fail the websocket connection_.
这里我翻译不好,大致意思是如果未定义扩展,各位是0;如果定义了扩展,即为非0值。如果接收的帧此处非0,扩展中却没有该值的定义,那么关闭连接。
 
opcode:4位
解释payloaddata,如果接收到未知的opcode,接收端必须关闭连接。
0x0表示附加数据帧
0x1表示文本数据帧
0x2表示二进制数据帧
0x3-7暂时无定义,为以后的非控制帧保留
0x8表示连接关闭
0x9表示ping
0xa表示pong
0xb-f暂时无定义,为以后的控制帧保留
 
mask:1位
用于标识payloaddata是否经过掩码处理。如果是1,masking-key域的数据即是掩码密钥,用于解码payloaddata。客户端发出的数据帧需要进行掩码处理,所以此位是1。
 
payload length:7位,7 16位,7 64位
payloaddata的长度(以字节为单位)。
如果其值在0-125,则是payload的真实长度。
如果值是126,则后面2个字节形成的16位无符号整型数的值是payload的真实长度。注意,网络字节序,需要转换。
如果值是127,则后面8个字节形成的64位无符号整型数的值是payload的真实长度。注意,网络字节序,需要转换。
长度表示遵循一个原则,用最少的字节表示长度(我理解是尽量减少不必要的传输)。举例说,payload真实长度是124,在0-125之间,必须用前7位表示;不允许长度1是126或127,然后长度2是124,这样违反原则。
payload长度是extensiondata长度与applicationdata长度之和。extensiondata长度可能是0,这种情况下,payload长度即是applicationdata长度。
 
 
websocket协议规定数据通过帧序列传输。
客户端必须对其发送到服务器的所有帧进行掩码处理。
服务器一旦收到无掩码帧,将关闭连接。服务器可能发送一个状态码是1002(表示协议错误)的close帧。
而服务器发送客户端的数据帧不做掩码处理,一旦客户端发现经过掩码处理的帧,将关闭连接。客户端可能使用状态码1002。
 

消息分片

分片目的是发送长度未知的消息。如果不分片发送,即一帧,就需要缓存整个消息,计算其长度,构建frame并发送;使用分片的话,可使用一个大小合适的buffer,用消息内容填充buffer,填满即发送出去。

分片规则:

1.一个未分片的消息只有一帧(fin为1,opcode非0)

2.一个分片的消息由起始帧(fin为0,opcode非0),若干(0个或多个)帧(fin为0,opcode为0),结束帧(fin为1,opcode为0)。

3.控制帧可以出现在分片消息中间,但控制帧本身不允许分片。

4.分片消息必须按次序逐帧发送。

5.如果未协商扩展的情况下,两个分片消息的帧之间不允许交错。

6.能够处理存在于分片消息帧之间的控制帧

7.发送端为非控制消息构建长度任意的分片

8.client和server兼容接收分片消息与非分片消息

9.控制帧不允许分片,中间媒介不允许改变分片结构(即为控制帧分片)

10.如果使用保留位,中间媒介不知道其值表示的含义,那么中间媒介不允许改变消息的分片结构

11.如果协商扩展,中间媒介不知道,那么中间媒介不允许改变消息的分片结构,同样地,如果中间媒介不了解一个连接的握手信息,也不允许改变该连接的消息的分片结构

12.由于上述规则,一个消息的所有分片是同一数据类型(由第一个分片的opcode定义)的数据。因为控制帧不允许分片,所以一个消息的所有分片的数据类型是文本、二进制、opcode保留类型中的一种。

需要注意的是,如果控制帧不允许夹杂在一个消息的分片之间,延迟会较大,比如说当前正在传输一个较大的消息,此时的ping必须等待消息传输完成,才能发送出去,会导致较大的延迟。为了避免类似问题,需要允许控制帧夹杂在消息分片之间。

控制帧

 

 

根据官方文档整理,官方文档参考

转载请注明出处 


小马歌 2014-04-19 15:16
]]>
websocket协议简介http://www.blogjava.net/xiaomage234/archive/2014/04/19/412683.html小马歌小马歌sat, 19 apr 2014 07:00:00 gmthttp://www.blogjava.net/xiaomage234/archive/2014/04/19/412683.htmlhttp://www.blogjava.net/xiaomage234/comments/412683.htmlhttp://www.blogjava.net/xiaomage234/archive/2014/04/19/412683.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/412683.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/412683.html
今天@julyclyde 在微博上问我websocket的细节。但是这个用70个字是无法说清楚的,所以就整理在这里吧。恰好我最近要重构年前写的websocket的代码。
众所周知,http是一种基于消息(message)的请求(request )/应答(response)协议。当我们在网页中点击一条链接(或者提交一个表单)的时候,浏览器给服务器发一个request message,然后服务器算啊算,答复一条response message。主动发起tcp连接的是client,接受tcp连接的是server。http消息只有两种:request和response。client只能发送request message,server只能发送response message。一问一答,因此按http协议本身的设计,服务器不能主动的把消息推给客户端。而像微博、网页聊天、网页游戏等都需要服务器主动给客户端推东西,现在只能用long polling等方式模拟,很不方便。
 
ok,来看看internet的另一边,网络游戏是怎么工作的?
我之前在一个游戏公司工作。我们做游戏的时候,普遍采用的模式是双向、异步消息模式。
首先通信的最基本单元是message。(这点和http一样)
其次,是双向的。client和server都可以给对方发消息(这点和http不一样)
最后,消息是异步的。我给服务器发一条消息出去,然后可能有一条答复,也可能有多条答复,也可能根本没有答复。无论如何,调用完send方法我就不管了,我不会傻乎乎的在这里等答复。服务器和客户端都会有一个线程专门负责read,以及一个大大的switch… case,根据message id做相应的action。
while( msg=myconnection.readmessage()){
switch(msg.id()){
case login: do_login(); break;
case talk: do_talk(); break;
}
}
websocket就是把这样一种模式,搬入到http/web的框架内。它主要解决两个问题:
从服务器给客户端主动推东西。
http协议传输效率低下的问题。这一点在web service中尤为突出。每个请求和应答都得带上很长的http header!
websocket协议在rfc 6455中定义,这个rfc在上个月(2011年12月)才终于定稿、提交。所以目前没有任何一个浏览器是能完全符合这个rfc的最终版的。google是websocket协议的主力支持者,目前主流的浏览器中,对websocket支持最好的就是chrome。chrome目前的最新版本是16,支持的是rfc 6455的draft 13,http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-13 。ie9则是完全不支持websocket。而server端,只有jetty和node.js对websocket的支持比较好。
 
websocket协议可以分为两个阶段,一个是握手阶段,一个是数据传输阶段。
在建立tcp连接之后,首先是websocket层的握手。这阶段很简单,client给server发一个http request,server给client一个http response。这个阶段,所有数据传输都是基于文本的,和现有的http/1.1协议保持兼容。
这是一个请求的例子:
connection:upgrade
host:echo.websocket.org
origin:http://websocket.org
sec-websocket-key:ov0xgasdkdbfh7uz1o nsw==
sec-websocket-version:13
upgrade:websocket
 
(其中host和origin不是必须的)
connection是http/1.1中常用的一个header,以前经常填的是keepalive或close。这里填的是upgrade。在设计http/1.1的时候,委员们就想到一个问题,假如以后出http 2.0了,那么现有的这套东西怎么办呢?所以http协议中就预定义了一个header叫upgrade。如果客户端发来的请求中有这个,那么意思就是说,我支持某某协议,并且我更偏向于用这个协议,你看你是不是也支持?你要是支持,咱们就换新协议吧!
然后就是websocket协议中所定义的两个特殊的header,sec-websocket-key和sec-websocket-version。
其中sec-websocket-key是客户端生的一串随机数,然后base64之后填进去的。sec-websocket-version是指协议的版本号。这里的13,代表draft 13。下面给出,我年前写的发送握手请求的java代码:
// 生一个随机字符串,作为sec-websocket-key
?view code java
        byte[] nonce = new byte[16];        rand.nextbytes(nonce);        base64encoder encode = new base64encoder();        string chan = encode.encode(nonce);         httprequest request = new basichttprequest("get", "/someurl");        request.addheader("host", host);        request.addheader("upgrade", "websocket");        request.addheader("connection", "upgrade");        request.addheader("sec-websocket-key", chan); // 生的随机串         request.addheader("sec-websocket-version", "13");        httpresponse response;        try {            conn.sendrequestheader(request);            conn.flush();            request.tostring();            response = conn.receiveresponseheader();        } catch (httpexception ex) {            throw new runtimeexception("handshake fail", ex);        }
 
服务器在收到握手请求之后需要做相应的答复。消息的例子如下:
http/1.1 101 switching protocols
connection:upgrade
date:sun, 29 jan 2012 18:05:49 gmt
sec-websocket-accept:7vi97qq5qrxq6ld6e5rrx36mobc=
server:jetty
upgrade:websocket
(其中date、server都不是必须的)
第一行是http的status-line。注意,这里的status code是101。很少见吧!sec-websocket-accept字段是一个根据client发来的sec-websocket-key得到的计算结果。
算法为:
把客户端发来的key作为字符串,与” 258eafa5-e914-47da-95ca-c5ab0dc85b11″这个字符串连接起来,然后做sha1 hash,将计算结果base64编码。注意,用来和” 258eafa5-e914-47da-95ca-c5ab0dc85b11″做连接操作的字符串,是base64编码后的。也就是说,客户端发来什么样就是什么样,不要试图去做base64解码。
示例代码如下:
?view code cpp
    std::string value=request.get("sec-websocket-key");    value ="258eafa5-e914-47da-95ca-c5ab0dc85b11";    unsigned char hash[20];    sha1::calc(value.c_str(),value.length(),hash);    std::string res=base64_encode(hash,sizeof(hash));    std::ostringstream oss;    oss<<"http/1.1 101 switching protocols\r\n"        "upgrade: websocket\r\n"        "connection: upgrade\r\n"        "sec-websocket-accept: "<
握手成功后,进入数据流阶段。这个阶段就和http协议没什么关系了。是在tcp流的基础上,把数据分成frame而已。首先,websocket的一个message,可以被分成多个frame。从逻辑上来看,frame的格式如下
isfinal
opcode
ismasked
data length
mask key
data(可以是文本,也可以是二进制)
 
isfinal:
每个frame的第一个字节的最高位,代表这个frame是不是该message的最后一个frame。1代表是最后一个,0代表后面还有。
opcode:
指明这个frame的类型。目前定义了这么几类continuation、text 、binary 、connection close、ping、pong。对于应用而言,最关心的就是,这个message是binary的呢,还是text的?因为html5中,对于这两种message的接口有细微不一样。
ismasked:
客户端发给服务器的消息,要求加扰之后发送。加扰的方式是:客户端生一个32位整数(mask key),然后把data和这32位整数做异或。
mask key:
前面已经说过了,就是用来做异或的随机数。
data:
这才是我们真正要传输的数据啊!!
发送frame时加扰的代码如下:
        java.util.random rand ;
        bytebuffer buffer;
        byte[] datatosend;
        …
        
        byte[] mask = new byte[4];
        rand.nextbytes(mask);
        buffer.put(mask);
        int oldpos = buffer.position();        
        buffer.put(data);
        int newpos = buffer.position();
        // 按位异或
        for (int i = oldpos; i != newpos; i) {
            int maskindex = (i – oldpos) % mask.length;
            buffer.put(i, (byte) (buffer.get(i) ^ (byte) mask[maskindex]));
        }
下面讨论一下这个协议的某些设计:
为什么要做这个异或操作呢?
说来话长。首先从connection:upgrade这个header讲起。本来它是留给tls用的。就是,假如我从80端口去连接一个服务器,然后通过发送connection:upgrade,仿照上面所说的流程,把http协议”升级”成https协议。但是实际上根本没人这么用。你要用https,你就去连接443。我80端口根本不处理https。由于这个header只是出现在rfc中,并未实际使用,于是大多数cache server看不懂这个header。这样的结果是,cache server可能以为后面的传输数据依然是普通的http协议,然后按照原来的规则做cache。那么,如果这个client和server都已经被黑客很好的操控,他就可以往这个cache server上投毒。比如,从client发送一个websocket frame,但是伪装成普通的http get请求,指向一个js文件。但是这个get请求的目的地未必是之前那个websocket server,可能是另外一台web server。然后他再去操控这个web server,做好配合,给一个看起来像http response的答复(实际是websocket frame),里面放的是被修改过的js文件。然后cache server就会把这个js文件错误的缓存下来,以后发给其他人。
首先,client是谁?是浏览器。它在一个不很安全的环境中,很容易受到xss或者流氓插件的攻击。假如我们的页面遭到了xss,使得攻击者可以利用js从受害者的页面上发送任意字符串给服务器,如果没有这个异或操作,那么他就可以控制什么样的二进制数据出现在信道上,从而实现上述攻击。但是我还是觉得有点问题。proxy server一般都会对目的地做严格的限制,比如,sina的squid肯定不会帮new.163.com做cache。那么既然你已经控制了一个web server,为什么不让js直接这么做呢?那篇paper的名字叫《talking to yourself for fun and pro?t》,有空我继续看。貌似是中国人写的。
还有,为什么要把message分成frame呢? 因为http协议有chunk功能,可以让服务器一边生数据,一边发。而websocket协议也考虑到了这点。如果没有framing功能,那么我必须知道整个message的长度之后,才能开始发送message的data。


小马歌 2014-04-19 15:00
]]>lua-5.2.2http://www.blogjava.net/xiaomage234/archive/2013/09/13/404037.html小马歌小马歌fri, 13 sep 2013 04:33:00 gmthttp://www.blogjava.net/xiaomage234/archive/2013/09/13/404037.htmlhttp://www.blogjava.net/xiaomage234/comments/404037.htmlhttp://www.blogjava.net/xiaomage234/archive/2013/09/13/404037.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/404037.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/404037.htmllua-5.2.2

发布已有一段时间了,最近在redhat linux平台编译时报错。这里给出凯发天生赢家一触即发官网的解决方案,或许对某人会有帮助。

编译报错,如下:

lua@home> make linux  ... gcc -o2 -wall -dlua_compat_all -dlua_use_linux    -c -o lstrlib.o lstrlib.c gcc -o2 -wall -dlua_compat_all -dlua_use_linux    -c -o ltablib.o ltablib.c gcc -o2 -wall -dlua_compat_all -dlua_use_linux    -c -o loadlib.o loadlib.c gcc -o2 -wall -dlua_compat_all -dlua_use_linux    -c -o linit.o linit.c ar rcu liblua.a lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o         lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o lauxlib.o lbaselib.o lbitlib.o     lcorolib.o ldblib.o liolib.o lmathlib.o loslib.o lstrlib.o ltablib.o loadlib.o linit.o  ranlib liblua.a gcc -o2 -wall -dlua_compat_all -dlua_use_linux    -c -o lua.o lua.c gcc -o lua   lua.o liblua.a -lm -wl,-e -ldl -lreadline  /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/libreadline.so: undefined reference to `pc' /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/libreadline.so: undefined reference to `tgetflag' /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/libreadline.so: undefined reference to `tgetent' /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/libreadline.so: undefined reference to `up' /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/libreadline.so: undefined reference to `tputs' /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/libreadline.so: undefined reference to `tgoto' /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/libreadline.so: undefined reference to `tgetnum' /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/libreadline.so: undefined reference to `bc' /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/libreadline.so: undefined reference to `tgetstr' collect2: ld returned 1 exit status make[1]: *** [lua] error 1 make[1]: leaving directory `/home/lua/lua-5.2.2/src' make: *** [linux] error 2 

由于lua编译依赖readline库,而其依赖ncurses库,但没有指定,所以出现“未定义的符合引用”错误。需要修改${lua_dir}/src/makefile中linux编译target,在syslibs变量中追加‘-lncurses’选项即可。修改后,如下:

  1. linux:
  2. $(make) $(all) syscflags="-dlua_use_linux" syslibs="-wl,-e -ldl -lreadline -lncurses"
  3.  


小马歌 2013-09-13 12:33
]]>
varnish使用汇总(不断更新)http://www.blogjava.net/xiaomage234/archive/2013/09/10/403904.html小马歌小马歌tue, 10 sep 2013 08:00:00 gmthttp://www.blogjava.net/xiaomage234/archive/2013/09/10/403904.htmlhttp://www.blogjava.net/xiaomage234/comments/403904.htmlhttp://www.blogjava.net/xiaomage234/archive/2013/09/10/403904.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/403904.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/403904.htmlq:如何配置varnish缓存到硬盘?

a:

 

q:如果debug vcl?

a:

 

q:怎样不重启varnish让新的vcl生效?

a:用varnishadm进入管理员页面:

shell代码  
  1. vcl.load   //加载一个新的vcl配置,configname:给配置起个名字,filename:配置的路径  
  2. vcl.use  //使用新的配置  
  3. vcl.discard  // 删除某个配置  
  4. vcl.list //查看所有加载的配置  

 

q:vcl怎么urlrewrite?

a:

ps:regsub函数支持后向引用(backreferences)。

eg:

vcl代码  
  1. set req.url = regsub(req.url,"/attachment/(. )(&token=. )$","/cache/attachment/\1");  

q:503 service unavailable?  

a:503错误,这是因为varnish对后端服务器响应header有限制,默认长度是2048,可将其调大一些

启动参数代码  
  1. -p http_resp_hdr_len=8192  
 

 

 

vcl官方文档:



小马歌 2013-09-10 16:00
]]>
xsplit a php extension for chinese segmentation using mmseg algorithm[zz]http://www.blogjava.net/xiaomage234/archive/2013/08/13/402755.html小马歌小马歌tue, 13 aug 2013 09:35:00 gmthttp://www.blogjava.net/xiaomage234/archive/2013/08/13/402755.htmlhttp://www.blogjava.net/xiaomage234/comments/402755.htmlhttp://www.blogjava.net/xiaomage234/archive/2013/08/13/402755.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/402755.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/402755.htmlfrom:
一点历史
这个project大约是09年初开始做的,很快就形成了现在版本的样子,后陆续做了一些小修改和修复了一些小bug,现整理了一下决定发布。把它open source的主要原因,就是希望这个小工具能对大家有用,并且能够参与进来一起把它做的更好
20101025
change log
20130509 0.0.9 released fixed an issue when compiler uses strict type checking
20101108 0.0.8 beta,加入xs_simhash和xs_hdist函数,分别计算simhash和汉明距离。
关于xsplit的交流,请到xsplit贴吧: http://tieba.baidu.com/f?kw=xsplit 参与讨论。
xsplit是一个php扩展,提供基于mmseg算法的分词功能。目前只在linux下测试并部署过,希望有朋友可以帮忙编译提供windows下的dll。
xsplit只处理utf8编码格式,如果是其他编码格式,请在使用前自行转换
xsplit主要有以下几个函数:
bool xs_build ( array $words, string $dict_file )
resource xs_open (string $dict_file [, bool $persistent])
array xs_split ( string $text [, int $split_method = 1 [, resource $dictionary_identifier ] ] )
mixed xs_search ( string $text [, int $search_method [, resource $dictionary_identifer ] ] )
string xs_simhash( string $text [, bool $isbinary] ) 
int xs_hdist( string $simhash1, string $simhash2 )
安装过程与一般的php扩展安装一样
$phpize
$./configure --with-php-config=/path/to/php-config
$make
$make install
php.ini中可以设置以下参数:
xsplit.allow_persisten = on
xsplit.max_dicts = 5
xsplit.max_persistent = 3
xsplit.default_dict_file = /home/xdict
xsplit.allow_persistent 是否允许加载持久词典
xsplit.max_dicts 允许同时打开的最大词典数目
xsplit.max_persistent 允许同时打开的最大持久词典数目
xsplit.default_dict_file 默认的词典,没有指定词典时会调用此词典
源码中有一个utils目录,包含
make_dict.php 提供命令行方式创建词典
xsplit.php 一个简单的示例文件
xdict_example.txt 一个文本词库的格式示例
make_dict.php的使用例子如下:
$php make_dict.php ./xdict_example.txt ./xdict.db
文本词库的格式请参考xdict_example.txt
bool xs_build (array $words, string $dict_file)
从$words数组建立名称为$dict_file的词典,若成功则返回true。$words数组的格式请参考示例,key为词语,value为词频。
例子如下:
$dict_file='dict.db';
$dwords['美丽']=100;
$dwords['蝴蝶']=100;
$dwords['永远']=100;
$dwords['心中']=100;
$dwords['翩翩']=100;
$dwords['飞舞']=100;
$dwords['翩翩飞舞']=10;
if(!xs_build($dwords, $dict_file)) {
    die('建立词典失败!');
}
resource xs_open (string $dict_file [, bool $persistent])
打开一个词典文件,并返回一个resource类型的identifier。$persistent可以指定是否是持久化词典,持久化词典在这里可以理解为词典资源生命周期的不同,一般情况下$persistent=true或者默认缺省即可。在进行分词的时候,可以指定不同的词典。
$dict_file_1 = 'xdcit.db';
$dict_file_2 = 'mydict.db';
$dict1 = xs_open($dict_file);
xs_open($dict_file); 
array xs_split ( string $text [, int $split_method = 1 [, resource $dictionary_identifier ] ] )
对文本进行分词,可以指定分词方法和词典。分词方法目前有两种,一个是mmseg算法(默认),一个是正向最大匹配,分别用常量xs_split_mmseg和xs_split_mmfwd表示。返回值是一个数组,包含所有切分好的词语。如果不指定词典,最后一次打开的词典将被使用。
$text="那只美丽的蝴蝶永远在我心中翩翩飞舞着。";
$dict_file = 'xdict.db';
$dict_res = xs_open($dict_file);
$words = xs_split($text);  /* 此处没有指定词典资源,默认使用最后一次打开的词典 */
$words1 = xs_split($text, xs_split_mmseg, $dict_res);
mixed xs_search ( string $text [, int $search_method [, $dictionary_identifer ] ] ) 基于双数组trie树提供的一些功能,$search_method有四个常量表示:
xs_search_cp : darts的commonprefixsearch封装,如果没有找到,返回false。
xs_search_em : darts的exactmatchsearch封装,如果没有找到,返回false。
xs_search_all_simple : 按照词典返回所有词语词频总和,一个int型数值。
xs_search_all_detail : 按照词典返回所有词典的词频,并以数组形式返回每一个词语的详细统计。
如果不指定词典,最后一次打开的词典将被使用。
xs_open($dict_file);
$text="那只美丽的蝴蝶永远在我心中翩翩飞舞着。";
$word='翩翩飞舞';
$result=xs_search($word, xs_search_cp); /* common prefix search */
var_dump($result);
$result=xs_search($word, xs_search_em); /* exact match search */
var_dump($result);
$result=xs_search($text, xs_search_all_simple);
var_dump($result);
$result=xs_search($text, xs_search_all_detail);
var_dump($result);
string xs_simhash( array $tokens [, bool $rawoutput] )
计算simhash。这里所有token权重都是1,$tokens的例子如array('在', '这个', '世界')。$rawoput默认为0,即返回simhash的hex string形式,如md5, sha1函数一样;如过$rawoput为真,返回一个8字节的字符串,这个字符串实际上是一个64 bits的整型数,uint64_t,在一些特殊情况下可以用到。
int xs_hdist( string $simhash1, $string $simhash2)
计算汉明距离。
xs_open('xdict');
$text1="那只美丽的蝴蝶永远在我心中翩翩飞舞着。";
$text2="那只美丽的蝴蝶永远在我心中翩翩飞舞。";
$tokens1=xs_search($text1, xs_search_all_indict); /* 去掉标点等特殊符号,经过实验,计算simhash时,一些标点、换行、特殊符号等对效果影响较大 */
$tokens2=xs_search($text2, xs_search_all_indict);
$simhash1=xs_simhash($tokens1);
$simhash2=xs_simhash($tokens2);
echo "simhash1 is {$simhash1}\n";
echo "simhash2 is {$simhash2}\n";
$hamming_dist=xs_hdist($simhash1, $simhash2);
echo "bit-wise format:\n";
echo decbin(hexdec($simhash1)), "\n";
echo decbin(hexdec($simhash2)), "\n";
echo "hamming distance is {$hamming_dist}\n";
terms - privacy


小马歌 2013-08-13 17:35
]]>darts: double-array trie system [zz]http://www.blogjava.net/xiaomage234/archive/2013/08/13/402750.html小马歌小马歌tue, 13 aug 2013 08:45:00 gmthttp://www.blogjava.net/xiaomage234/archive/2013/08/13/402750.htmlhttp://www.blogjava.net/xiaomage234/comments/402750.htmlhttp://www.blogjava.net/xiaomage234/archive/2013/08/13/402750.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/402750.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/402750.htmldarts 是用于构建双数组 double-array  的简单的 c template library . 双数组 (double-array) 是用于实现 trie 的一种数据结构, 比其它的类 trie 实现方式(hash-tree, digital trie, patricia tree, suffix array) 速度更快。 原始的 double-array 使能够支持动态添加删除 key, 但是 darts 只支持把排好序的词典文件转换为静态的 double-array.

darts 既可以像 hash 一样作为简单的词典使用,也能非常高效的执行分词词典中必须的 common prefix search 操作。

自2003年7月起, 两个开源的日语分词系统 ,  都使用了 darts .

  • darts 是自由软件.遵循 (lesser gnu general public license) 和 bsd 协议, 可以修改后重新发布.
  • darts-0.32.tar.gz: 
% ./configure 
% make
% make check
% make install
然后在程序中 include /usr/local/include/darts.h

darts 只提供了 darts.h 这个 c 模板文件。每次使用的时候 include 该文件即可.
使用这样的发布方式是希望通过内联函数实现高效率。

类接口

namespace darts {

template class arrayutype, class lengthfunc = length >

class dobulearrayimpl
{
public:
typedef arraytype result_type;
typedef nodetype key_type;

doublearrayimpl();
~doublearrayimpl();

int set_array(void *ptr, size_t = 0);
void *array();
void clear();
size_t size ();
size_t unit_size ();
size_t nonzero_size ();
size_t total_size ();

int build (size_t key_size,
key_type **key,
size_t *len = 0,
result_type *val = 0,
int (*pg)(size_t, size_t) = 0);

int open (const char *file,
const char *mode = "rb",
size_t offset = 0,
size_t _size = 0);

int save (const char *file,
const char *mode = "wb",
size_t offset = 0);

result_type exactmatchsearch (const key_type *key,
size_t len = 0,
size_t node_pos = 0)

size_t commonprefixsearch (const key_type *key,
result_type *result,
size_t result_size,
size_t len = 0,
size_t node_pos = 0)

result_type traverse (const key_type *key,
size_t &node_pos,
size_t &key_pos,
size_t len = 0)
};

typedef darts::doublearrayimpl int, unsigned int> doublearray;
};

模板参数说明

 

nodetypetrie 节点类型, 对普通的 c 字符串检索, 设置为 char 型即可.
nodeutypetrie 节点转为无符号整数的类型, 对普通的 c 字符串检索, 设置为 unsigned char 型即可.
arraytypedouble-array 的 base 元素使用的类型, 通常设置为有符号 32bit 整数
arrayutypedouble-array 的 check 元素使用的类型, 通常设置为无符号 32bit 整数
lengthfunc使用 nodetype 数组的时候,使用该函数对象获取数组的大小, 在该函数对象中对 operator() 进行重载. 
nodetype 是 char 的时候, 缺省使用 strlen 函数, 否则以 0 作为数组结束标志计算数组的大小 .

typedef 说明

模板参数类型的别名. 在外部需要使用这些类型的时候使用 .

key_type待检索的 key 的单个元素的类型. 等同于 nodetype.
result_type单个结果的类型. 等同于 arraytype .

方法说明

int darts::doublearrayimpl::build(size_t size, const key_type **str, const size_t *len = 0, const result_type *val = 0, int (*progress_func)(size_t, size_t) = 0)
构建 double array .

size 词典大小 (记录的词条数目),
str 指向各词条的指针 (共 size个指针)
len 用于记录各个词条的长度的数组(数组大小为 size)
val 用于保存各词条对应的 value 的数组 (数组大小为 size)
progress_func 构建进度函数.

str 的各个元素必须按照字典序排好序.
另外 val 数组中的元素不能有负值.
len, val, progress_func 可以省略,
省略的时候, len 使用 lengthfunc 计算,
val 的各元素的值为从 0 开始的计数值。 


构建成功,返回 0; 失败的时候返回值为负.
进度函数 progress_func 有两个参数.
第一个 size_t 型参数表示目前已经构建的词条数 
第二个 size_t 型参数表示所有的词条数 

result_type darts::doublearrayimpl::exactmatchsearch(const key_type *key, size_t len = 0, size_t node_pos = 0)
进行精确匹配(exact match) 检索, 判断给定字符串是否为词典中的词条.

key 待检索字符串,
len 字符串长度,
node_pos 指定从 double-array 的哪个节点位置开始检索.

len, 和 node_pos 都可以省略, 省略的时候, len 缺省使用 lengthfunc 计算,
node_pos 缺省为 root 节点.

检索成功时, 返回 key 对应的 value 值, 失败则返回 -1. 

size_t darts::doublearrayimpl::commonprefixsearch (const key_type *key, result_type *result, size_t result_size, size_t len = 0, size_t node_pos = 0)
执行 common prefix search. 检索给定字符串的哪些的前缀是词典中的词条

key 待检索字符串,
result 用于保存多个命中结果的数组,
result_size 数组 result 大小,
len 待检索字符串长度,
node_pos 指定从 double-array 的哪个节点位置开始检索.

len, 和 node_pos 都可以省略, 省略的时候, len 缺省使用 lengthfunc 计算,
node_pos 缺省为 root 节点.

函 数返回命中的词条个数. 对于每个命中的词条, 词条对应的 value 值存依次放在 result 数组中. 如果命中的词条个数超过 result_size 的大小, 则 result 数组中只保存 result_size 个结果。函数的返回值为实际的命中词条个数, 可能超过 result_size 的大小。 

result_t darts::doublearrayimpl::traverse (const key_type *key, size_t &node_pos, size_t &key_pos, size_t len = 0)
traverse trie, 检索当前字符串并记录检索后到达的位置 

key 待检索字符串,
node_pos 指定从 double-array 的哪个节点位置开始检索.
key_pos 从待检索字符串的哪个位置开始检索
len 待检索字符串长度,

该函数和 exactmatchsearch 很相似. traverse 过程是按照检索串 key 在 trie 的节点中进行转移.
但是函数执行后, 可以获取到最后到达的 trie 节点位置,最后到达的字符串位置 . 这和 exactmatchsearch 是有区别的. 

node_pos 通常指定为 root 位置 (0) . 函数调用后, node_pos 的值记录最后到达的 doublearray 节点位置。 
key_pos 通常指定为 0. 函数调用后, key_pos 保存最后到达的字符串 key 中的位置。 

检索失败的时候, 返回 -1 或者 -2 .
-1 表示再叶子节点失败, -2 表示在中间节点失败,.
检索成功的时候, 返回 key 对应的 value. 

int darts::doublearrayimpl::save(const char *file, const char *mode = "wb", size_t offset = 0)
把 double-array 保存为文件.

file 保存文件名,
mode 文件打开模式 
offset 保存的文件位置偏移量, 预留将来使用, 目前没有实现 .

成功返回 0 , 失败返回 -1 

int darts::doublearrayimpl::open (const char *file, const char *mode = "rb", size_t offset = 0, size_t size = 0)
读入 double-array 文件.

file 读取文件名,
mode 文件打开模式 
offset 读取的文件位置偏移量 

size 为 0 的时候, size 使用文件的大小 .

成功返回 0 , 失败返回 -1 

size_t darts::doublearrayimpl::size()
返回 double-array 大小. 

size_t darts::doublearrayimpl::unit_size()
double-array 一个元素的大小(byte).

size() * unit_size() 是, 存放 double-array 所需要的内存(byte) 大小. 

size_t darts::doublearrayimpl::nonzero_size()
double-array 的所有元素中, 被使用的元素的数目, .
nonezero_size()/size() 用于计算压缩率. 

例子程序

从静态词典构建双数组 double-array.

#include 
#include

int main (int argc, char **argv)
{
using namespace std;

darts::doublearray::key_type *str[] = { "algol", "ansi", "arco", "arpa", "arpanet", "ascii" }; // same as char*
darts::dobulearray::result_type val[] = { 1, 2, 3, 4, 5, 6 }; // same as int

darts::doublearray da;
da.build (6, str, 0, val);

cout << da.exactmatchsearch("algol") << endl;
cout << da.exactmatchsearch("ansi") << endl;
cout << da.exactmatchsearch("arco") << endl;;
cout << da.exactmatchsearch("arpa") << endl;;
cout << da.exactmatchsearch("arpanet") << endl;;
cout << da.exactmatchsearch("ascii") << endl;;
cout << da.exactmatchsearch("appare") << endl;

da.save("some_file");
}

执行结果
1
2
3
4
5
6
-1

从标准输入读取字符串, 对 double-array 执行 common prefix search

#include 
#include
#include
#include

int main (int argc, char **argv)
{
using namespace std;

darts::doublearray da;
if (da.open("some_file") == -1) return -1;

darts::doublearray::result_type r [1024];
darts::doublearray::key_type buf [1024];

while (cin.getline (buf, 1024)) {
size_t result = da.commonprefixsearch(buf, r, 1024);
if (result == 0) {
cout << buf << ": not found" << endl;
} else {
cout << buf << ": found, num=" << result << " ";
copy (r, r result, ostream_iterator(cout, " "));
cout << endl;
}
}

return 0;
}

付属程序说明

mkdarts

% ./mkdarts dictionaryfile doublearrayfile 
把排序好的词典 dictionaryfile 转换为 doublearrayfile

darts

% ./darts doublearrayfile 

使用 doublearrayfile 做 common prefix search .

使用例子

% cd tests
% head -10 linux.words
algol
ansi
arco
arpa
arpanet
ascii
..

% ../mkdarts linux.words dar
making double array: 100% |*******************************************|
done!, compression ratio: 94.6903 %

% ../darts dar
linux
linux: found, num=2 3697 3713
windows
windows: not found
latex
latex: found, num=1 3529

参考文献, 链接

  • [datrie] theppitak karoonboonyanan an implementation of double-array trie
  • [単語と辞書] 松本裕治 ほか. 単語と辞書 岩波講座言語の科学 vol.3 pp.79-81


小马歌 2013-08-13 16:45
]]>
nginx/php-fpm fast-cgi性能优化设置http://www.blogjava.net/xiaomage234/archive/2013/08/05/402404.html小马歌小马歌mon, 05 aug 2013 08:19:00 gmthttp://www.blogjava.net/xiaomage234/archive/2013/08/05/402404.htmlhttp://www.blogjava.net/xiaomage234/comments/402404.htmlhttp://www.blogjava.net/xiaomage234/archive/2013/08/05/402404.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/402404.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/402404.htmlwhen you running a highload website with php-fpm via fastcgi, the following tips may be useful to you : )
如果您高负载网站使用php-fpm管 理fastcgi,这些技巧也许对您有用:)

1. compile php’s modules as less as possible, the simple the best (fast);
1.尽量少安装php模块,最简单是最好(快)的

2. increas php fastcgi child number to 100 and even more. sometime, 200 is ok! ( on 4gb memory server);
2.把您的php fastcgi子进程数调到100或以上,在4g内存的服务器上200就可以
注:我的1g测试机,开64个是最好的,建议使用压力测试获取最佳值

3. using socket php fastcgi, and put into /dev/shm on linux;
3.使用socket连接fastcgi,linux操作系统可以放在 /dev/shm中
注: 在php-fpm.cnf 里设置/tmp/nginx.socket就可以通过socket连接 fastcgi了,/dev/shm是内存文件系统,放在内存中肯定会快了

4. increase linux “max open files”, using the following command (must be root):
# echo ‘ulimit -hsn 65536′ >> /etc/profile
# echo ‘ulimit -hsn 65536 >> /etc/rc.local
# source /etc/profile
4.调高linux内核打开文件数量,可以使用这些命令(必须是root帐号)
echo 'ulimit -hsn 65536' >> /etc/profile
echo 'ulimit -hsn 65536' >> /etc/rc.local
source /etc/profile
注:我是修改/etc/rc.local,加入ulimit -shn 51200的

5. increase php-fpm open file description rlimit:
# vi /path/to/php-fpm.conf
find “1024
change 1024 to 4096 or higher number.
restart php-fpm.
5. 增加 php-fpm 打开文件描述符的限制:
# vi /path/to/php-fpm.conf
找到“1024
把1024 更改为 4096 或者更高.
重启 php-fpm.

6. using php code accelerator, e.g eaccelerator, xcache. and set “cache_dir” to /dev/shm on linux.
6.使用php代码加速器,例如 eaccelerator, xcache.在linux平台上可以把`cache_dir`指向 /dev/shm

小马歌 2013-08-05 16:19
]]>
nginx proxy_cache 使用示例【转】http://www.blogjava.net/xiaomage234/archive/2013/08/02/402315.html小马歌小马歌fri, 02 aug 2013 08:14:00 gmthttp://www.blogjava.net/xiaomage234/archive/2013/08/02/402315.htmlhttp://www.blogjava.net/xiaomage234/comments/402315.htmlhttp://www.blogjava.net/xiaomage234/archive/2013/08/02/402315.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/402315.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/402315.html原文出处:

动态网站使用缓存是很有必要的。前段时间使用了 nginx proxy_stroe 来保存静态页面,以达到缓存的目的。当然 proxy stroe 用来做缓存是不够好的方案。

缓存这一块当然还有 squid 之类的独立缓存服务器。如果使用 nginx 为 web 服务器,还要加个 squid 来缓存,是觉得多了一个 http 请求层。幸好 nginx 0.7 有了 proxy_cache 来做这个缓存的事。

之前来有个 ncache 是新浪员工开发的 nginx 模块(好像只能在 nginx 0.6 中编译无运行)。已经停止维护了,已经被加到 nginx 标准库里了。昨天还不知道 proxy_cache 就是 ncache 的功能时,还在努力匹配 ncahce,浪费了n多时间,最终没看到可以缓存。后来尝试 proxy_cache 才解决,且使用简单。

安装 nginx 请看:,如果没有 pcre 库,可以到 下载(我用的是 8.02)。

nginx 0.7.65 默认安装就可以了。

安装好后开始匹配 proxy_cache,先准备后台服务器的文件,如是 time.jsp,内容:

  1. <%=new java.util.date() %>  

conf/nginx.conf:

  1. user  nobody;  
  2. worker_processes  1;  
  3. error_log  logs/error.log;  
  4. pid        logs/nginx.pid;  
  5.   
  6. events {  
  7.     worker_connections  1024;  
  8.     use epoll;  
  9. }  
  10.   
  11. http {  
  12.     include       mime.types;  
  13.     default_type  application/octet-stream;  
  14.   
  15.     log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '  
  16.                       '$status $body_bytes_sent "$http_referer" "$request_body" '  
  17.                       '"$http_user_agent" "$http_x_forwarded_for" "$request_time"';  
  18.   
  19.     sendfile        on;  
  20.     keepalive_timeout  60;  
  21.   
  22.     proxy_cache_path /var/cache0 levels=1:2 keys_zone=pnc:100m inactive=2h max_size=10g;  
  23.     upstream backend {  
  24.         server 192.168.1.2:8080  weight=6;  
  25.         #server 192.168.1.3:8080  weight=4;  
  26.     }  
  27.   
  28.     server {  
  29.         listen       80;  
  30.         server_name  localhost;  
  31.   
  32.         access_log  logs/access.80.log  main;  
  33.   
  34.         location / {  
  35.             proxy_cache pnc;  
  36.             proxy_temp_path /var/nginx_temp;  
  37.             #proxy_cache_key "$request_uri$request_body";  
  38.             #proxy_cache_methods get post;  
  39.             proxy_cache_valid 200 304 1m;  
  40.             proxy_pass http://backend;  
  41.         }  
  42.   
  43.         error_page   500 502 503 504  /50x.html;  
  44.         location = /50x.html {  
  45.             root   html;  
  46.         }  
  47.     }  
  48. }  

启动 nginx 后,打开浏览器,可以狂刷 ctrl f5,可以看到一样的页面。一分钟后再会一个新的页面。

是 proxy_cache_valid 200 304 1m; 告诉 nginx 后台返回的结果是 200 或 304 的响应,用 1m(分钟)的缓存。

proxy_cache_key 默认是 "$scheme$host$request_uri"。

proxy_cache_methods 默认是 get head。

当要缓存 post 请求后,要用 proxy_cache_methods post 来打开。并且 proxy_cache_key 要对,post 的请求 query string 是在请求体内,所以加 $request_body 作为 key 的一部分。要用 post ,上面匹配去了注释就可以了。

这些匹配指令详情请看官方:,中文版:



小马歌 2013-08-02 16:14
]]>
web前端 https 缓存加速squid 3.3.8 实战【原创】http://www.blogjava.net/xiaomage234/archive/2013/07/31/402195.html小马歌小马歌wed, 31 jul 2013 05:58:00 gmthttp://www.blogjava.net/xiaomage234/archive/2013/07/31/402195.htmlhttp://www.blogjava.net/xiaomage234/comments/402195.htmlhttp://www.blogjava.net/xiaomage234/archive/2013/07/31/402195.html#feedback1http://www.blogjava.net/xiaomage234/comments/commentrss/402195.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/402195.html
到网上下了一个最新版 3.3.8,开始搜索配置资料,发现都是以前的旧的,不适用,后来发现了一个 针对3.0的配置:   按照提示安装完成了,启用了 --enable-ssl选项。

后来又参考官方文档 加上了https支持,参考: 但是很不辛,居然报错:“fatal: http(s)_port: defaultsite option requires acceleration mode flag.”

然后根据提示 去 查找https_port用法,参考资料:原来 是 缺少[mode]选项,根据我的需要,加了“accel”,问题解决.

具体业务的完整配置参考附件。
https_port 443 cert=/usr/local/squid/cert.pem key=/usr/local/squid/cert.key accel defaultsite=img0-yoursite.yourdomain.com vhost
cache_peer 1.2.3.4 parent 80 0 no-query originserver ssl sslflags=dont_verify_peer name=img0
acl sites_server_img0 dstdomain img0-yoursite.yourdomain.com
cache_peer_access img0 allow sites_server_img0
http_access allow sites_server_img0

https_port 443 cert=/usr/local/squid/cert.pem key=/usr/local/squid/cert.key accel defaultsite=img1-yoursite.yourdomain.com vhost
cache_peer 1.2.3.4 parent 80 0 no-query originserver ssl sslflags=dont_verify_peer name=img1
acl sites_server_img1 dstdomain img1-yoursite.yourdomain.com
cache_peer_access img1 allow sites_server_img1
http_access allow sites_server_img1

####base######
visible_hostname localhost
cache_mgr xiaomage234@163.com
cache_effective_user nobody
cache_effective_group nobody
####cache#####
cache_mem 600 mb
cache_swap_low 90
cache_swap_high 95
maximum_object_size 12000 kb
maximum_object_size_in_memory 1024 kb
cache_dir ufs /usr/local/squid/var/cache 10000 16 256
cache_access_log /usr/local/squid/var/logs/access.log
cache_log /usr/local/squid/var/logs/cache.log
cache_store_log /usr/local/squid/var/logs/store.log
#####no-cache##########
hierarchy_stoplist cgi-bin ?/.php
acl query urlpath_regex cgi-bin /?/.php
#acl direct url_regex -i ^http://192.168.0.201
cache deny query
#cache deny direct
#####refresh_pattern####
refresh_pattern ^ftp: 60 20% 10080
refresh_pattern ^gopher: 60 0% 1440

refresh_pattern ^gopher: 60 0% 1440
refresh_pattern . 0 20% 1440
refresh_pattern -i /.css$       360     50%     2880     reload-into-ims
refresh_pattern -i /.js$        1440    50%     2880     reload-into-ims
refresh_pattern -i /.html$      720     50%     1440     reload-into-ims
refresh_pattern -i /.jpg$       1440    90%     2880     ignore-reload
refresh_pattern -i /.gif$       1440    90%     2880     ignore-reload
refresh_pattern -i /.swf$       1440    90%     2880     ignore-reload
refresh_pattern -i /.jpg$       1440    50%     2880     ignore-reload
refresh_pattern -i /.png$       1440    50%     2880     ignore-reload
refresh_pattern -i /.bmp$       1440    50%     2880     ignore-reload
refresh_pattern -i /.doc$       1440    50%     2880     ignore-reload
refresh_pattern -i /.ppt$       1440    50%     2880     ignore-reload
refresh_pattern -i /.xls$       1440    50%     2880     ignore-reload
refresh_pattern -i /.pdf$       1440    50%     2880     ignore-reload
refresh_pattern -i /.rar$       1440    50%     2880     ignore-reload
refresh_pattern -i /.zip$       1440    50%     2880     ignore-reload
refresh_pattern -i /.txt$       1440    50%     2880     ignore-reload
######proxy agent###        
http_port 80 accel vhost vport
cache_peer 1.2.3.4 parent 80 0 no-query originserver name=img00
cache_peer_domain img00 img0-yoursite.yourdomain.com

cache_peer 1.2.3.4 parent 80 0 no-query originserver name=img01
cache_peer_domain img01 img1-yoursite.yourdomain.com
######alc#####
acl manager2 proto cache_object
acl localhost src 127.0.0.1/32
acl to_localhost dst 127.0.0.0/8
acl localnet src 10.0.0.0/8     # rfc1918 possible internal network
acl localnet src 172.16.0.0/12  # rfc1918 possible internal network
acl localnet src 192.168.0.0/16 # rfc1918 possible internal network
acl lansrc src all
acl landst dst all
acl ssl_ports port 443
acl safe_ports port 80          # http
acl safe_ports port 21          # ftp
acl safe_ports port 443         # https
acl safe_ports port 70          # gopher
acl safe_ports port 210         # wais
acl safe_ports port 1025-65535  # unregistered ports
acl safe_ports port 280         # http-mgmt
acl safe_ports port 488         # gss-http
acl safe_ports port 591         # filemaker
acl safe_ports port 777         # multiling http
acl connect method connect
acl landstdm dstdomain .kanbox.com

http_access allow manager2 localhost
http_access deny manager2
http_access deny !safe_ports
http_access deny connect !ssl_ports
http_access allow landstdm
http_access allow lansrc
http_access allow landst
http_access allow localnet
http_access deny all

下载附件:
arnish的配置,不支持https:


小马歌 2013-07-31 13:58
]]>
大流量网站的底层系统架构http://www.blogjava.net/xiaomage234/archive/2012/11/05/390813.html小马歌小马歌mon, 05 nov 2012 07:25:00 gmthttp://www.blogjava.net/xiaomage234/archive/2012/11/05/390813.htmlhttp://www.blogjava.net/xiaomage234/comments/390813.htmlhttp://www.blogjava.net/xiaomage234/archive/2012/11/05/390813.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/390813.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/390813.html动态应用,是相对于网站静态内容而言, 是指以c/c 、php、java、perl、.net等 服务器端语言开发的网络应用软件,比如论坛、网络相册、交友、blog等常见应用。动态应用系统通 常与数据库系统、缓存系统、分布式存储系统等密不可分。

  大型动态应用系统平台主要是针对于大流 量、高并发网站建立的底层系统架构。大型网站的运行需要一个可靠、安全、可扩展、易维护的应用系统平台做为支撑,以保证网站应用的平稳运行。

  大型动态应用系统又可分为几个子系统:

  l web前 端系统

  l 负 载均衡系统

  l 数 据库集群系统

  l 缓 存系统

  l 分 布式存储系统

  l 分 布式服务器管理系统

  l 代 码分发系统

  web前端系统

  结构图:

  为了达到不同应用的服务器共享、避免单点故障、集中管理、统一配置等目的,不以应用划分服 务器,而是将所有服务器做统一使用,每台服务器都可以对多个应用提供服务,当某些应用访问量升高时,通过增加服务器节点达到整个服务器集群的性能提高,同 时使他应用也会受益。该web前端系统基于apache/lighttpd/eginx等 的虚拟主机平台,提供php程序运行环境。服务器对开发人员是透明的,不需要开发人员介入服务器管理

  负载均衡系统

  负载均衡系统分为硬件和软件两种。硬件负载均衡效率高,但是价格贵,比如f5等。软件负载均衡系统价格较低或者免费,效率较硬件负载均衡系统 低,不过对于流量一般或稍大些网站来讲也足够使用,比如lvs,nginx。大多数网站都是硬件、软件负载均衡系统并用。

  数据库集群系统

  结构图:

  由于web前端采用了负载均衡集群结构提高了服务的有效性和扩展性,因此数据库必须也是高可靠的才能保证整个服务体系的高可靠性,如何构建一个高可靠的、可以提供大规模并发处理的数据库体系?

  我们可以采用如上图所示的方案:

  1) 使用 mysql 数据库,考虑到web应用的数据库读多写少的特点,我们主要对读数据库做了优化,提供专用的读数据库和写数据库,在应用程序中实现读操作和写操作分别访问不同的数据库。

  2) 使用 mysql replication 机制实现快速将主库(写库)的数据库复制到从库(读库)。一个主库对应多个从库,主库数据实时同步到从库。

  3) 写数据库有多台,每台都可以提供多个应用共同使用,这样可以解决写库的性能瓶颈问题和单点故障问题。

  4) 读数据库有多台,通过负载均衡设备实现负载均衡,从而达到读数据库的高性能、高可靠和高可扩展性。

  5) 数据库服务器和应用服务器分离。

  6) 从数据库使用bigip做负载均衡。

  缓存系统

  缓存分为文件缓存、内存缓存、数据库缓存。在大型web应用中使用最多且效率最高的是内存缓存。最常用的内存缓存工具是memcachd。使用正确的缓存系统可以达到实现以下目标:

  1、 使用缓存系统可以提高访问效率,提高服务器吞吐能力,改善用户体验。

  2、 减轻对数据库及存储集服务器的访问压力

  3、memcached服务器有多台,避免单点故障,提供高可靠性和可扩展性,提高性能。

  分布式存储系统

  结构图:

  web系统平台中的存储需求有下面两个特点:

  1) 存储量很大,经常会达到单台服务器无法提供的规模,比如相册、视频等应用。因此需要专业的大规模存储系统。

  2) 负载均衡cluster中的每个节点都有可能访问任何一个数据对象,每个节点对数据的处理也能被其他节点共享,因此这些节点要操作的数据从逻辑上看只能是一个整体,不是各自独立的数据资源。

  因此高性能的分布式存储系统对于大型网站应用来说是非常重要的一环。(这个地方需要加入对某个分布式存储系统的简单介绍。)

  分布式服务器管理系统

  结构图:

  随着网站访问流量的不断增加,大多的网络服务都是以负载均衡集群的方式对外提供服务,随之集群规模的扩大,原来基于单机的服务器管理模式已经不能够满足我们的需求,新的需求必须能够集中式的、分组的、批量的、自动化的对服务器进行管理,能够批量化的执行计划任务。

  在分布式服务器管理系统软件中有一些比较优秀的软件,其中比较理想的一个是 cfengine。它可以对服务器进行分组,不同的分组可以分别定制系统配置文件、计划任务等配置。它是基于c/s 结构的,所有的服务器配置和管理脚本程序都保存在cfengine server上,而被管理的服务器运行着 cfengine client 程序,cfengine client通过ssl加密的连接定期的向服务器端发送请求以获取最新的配置文件和管理命令、脚本程序、补丁安装等任务。

  有了cfengine 这种集中式的服务器管理工具,我们就可以高效的实现大规模的服务器集群管理,被管理服务器和 cfengine server 可以分布在任何位置,只要网络可以连通就能实现快速自动化的管理。

  代码发布系统

  结构图: 

  随着网站访问流量的不断增加,大多的网络服务都是以负载均衡集群的方式对外提供服务,随之集群规模的扩大,为了满足集群环境下程序代码的批量分发和更新,我们还需要一个程序代码发布系统。

  这个发布系统可以帮我们实现下面的目标:

  1) 生产环境的服务器以虚拟主机方式提供服务,不需要开发人员介入维护和直接操作,提供发布系统可以实现不需要登陆服务器就能把程序分发到目标服务器。

  2) 我们要实现内部开发、内部测试、生产环境测试、生产环境发布的4个开发阶段的管理,发布系统可以介入各个阶段的代码发布。

  3) 我们需要实现源代码管理和版本控制,svn可以实现该需求。

  这里面可以使用常用的工具rsync,通过开发相应的脚本工具实现服务器集群间代码同步分发。



小马歌 2012-11-05 15:25
]]>
小白谈memcache和memcached的区别【转】http://www.blogjava.net/xiaomage234/archive/2011/10/26/362114.html小马歌小马歌wed, 26 oct 2011 09:25:00 gmthttp://www.blogjava.net/xiaomage234/archive/2011/10/26/362114.htmlhttp://www.blogjava.net/xiaomage234/comments/362114.htmlhttp://www.blogjava.net/xiaomage234/archive/2011/10/26/362114.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/362114.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/362114.htmlhttp://www.cnblogs.com/scotoma/archive/2011/02/15/1955573.html

用了段时间的memcache和memcached总结下认识,看很多人在用cache的时候,刚刚都没有搞清楚memcache和 memcached的区别,还有就是使用的时候基本都是 get/set  用了memcached之后其实可以发现getmulti/setmulti 是多么好用,这篇写个那些刚刚使用memcache缓存的新人,老鸟请略过。

关于memcached就不用多说了,就是a distributed memory object  caching system 。既然是一个用来存东西的系统,那么一定要有个存放的地方吧,我们就叫它服务器端吧,然后谁把东西存放在上面就叫它客户端吧,那怎么放呢,肯定是 客户端 -- 连接服务器端 -- 把东西发送给服务器端 -- 实现了东西的存放么,要去取的时候也是一样的,先连接,在取东西回来了。所有就有了memcached的服务器端,安装请见 http://www.cnblogs.com/scotoma/archive/2010/05/27/1745011.html 这个是win下的,*unix下的请到 http://memcached.org/ 去下载然后编译安装了,这里我就不多说安装的配置了,网上已经有很多了。

安装完成后看下自己的进程里面memcached的服务是否在跑着的? 好了进程在跑着呢,那就看看客户端吧

我是做php开发的,所有就安装了php的客户端扩展,有memcache和memcached扩展2种,安装我也不说了自己去动手,安装完成后查看phpinfo会发现如下页面就说明你的扩展安装成功了,如果不成功请自己检查php.ini里面的配置是否正确

服务器端和客户端都弄好了看看示例代码可以跑起来的么,如图

结果如图:

都跑起来了,看看memcache和memcached的使用的区别,那就好好的翻看下php手册吧,其实手册是最好的东西了

memcache扩展的方法

memcached扩展的方法

完成了,其实2个可以理解成2个扩展历史原因也不想多说了,就是尽量使用memcached就好了,不过也会出现一些很奇怪的bug,比如使用memcached扩展的适合设置的session(session存放到memcached中,使用的是memcached扩展存放的就会发现不会过期)。

在实践中用了之后才会知道什么和什么的,动手是最好的学习方式.



小马歌 2011-10-26 17:25
]]>
杨卫华谈新浪微博架构:mysql和nosqlhttp://www.blogjava.net/xiaomage234/archive/2011/07/25/354999.html小马歌小马歌mon, 25 jul 2011 08:24:00 gmthttp://www.blogjava.net/xiaomage234/archive/2011/07/25/354999.htmlhttp://www.blogjava.net/xiaomage234/comments/354999.htmlhttp://www.blogjava.net/xiaomage234/archive/2011/07/25/354999.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/354999.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/354999.html

在2010年的qcon北京大会上,记者对杨卫华进行了采访,其中谈到了关于系统平台应对各种问题的凯发天生赢家一触即发官网的解决方案,以及正在开发中的新浪云。

  杨卫华,新浪产品部技术经理,目前工作以新浪微博技术平台为主,曾负责过新浪im等通讯服务端架构设计。对互联网后端技术,分布式,网络编程,xmpp即时通讯等领域感兴趣。曾组织多次广州及珠三角技术沙龙活动。个人blog 为:。

  记者:大家都知道,在美国有一个非常有名的信息分享平台叫做twitter,而在中国,我们也有同样的方式,就是现在非常流行的新浪微博,它还有个非常温馨的名字,叫做围脖。而新浪微博的架构就是杨卫华先生主持开发的。

  今天我有幸采访到杨卫华先生,让他来给大家谈一谈,在新浪微博的技术架构方面,他们是如何为用户提供更好的性能、更好的服务的。

  卫华先生你好,我的第一个问题是,在新浪微博上有很多名人,名人的微博一般都是非常热的,对它们的访问量也特别高,那么对于这些微博,您采用了么样的方式来支持这种大数据量的访问呢?

  杨卫华(以下简称卫华):对于这个问题,我们做过专门的分析。因为最近新浪微博有名人扎堆的现象,我们根据这个现象,从以下几个角度来进行解决。

  首先根据中国的网络现状,比如说网通和电信,之间的网络访问速度会比较慢,我们考虑让用户能够访问就近的,这样使用体验、速度都能达到要求。我们根据新浪以往的经验,在全国部署了大量,这样就为微博提供了硬件上的保证。

  第二个方面,在程序优化的方面,在产品上线之前,我们进行了全方面的压力测试,如果系统在某个方面可能会出现瓶颈,比如名人的访问量比较高的话,我们就从那个角度去优化。比如说cache是否够用,数据库访问是不是瓶颈,这方面我们预先都有对压力的估计,然后会针对那些方面去做优化。

  第三个方面,对于那些静态资源,比如图片、视频、js脚本,我们有专业的cdn来解决的,这样就能够保证全国的用户在访问新浪微博时都能够得到比较好的体验。

  记者:现在的服务器大概都架设在哪几个部分?覆盖全国哪几个地区?

  卫华:全国基本上大部分省份都有服务器,特别是一些比较核心的节点,比如北京、上海、广州,在这些核心的节点可能部署了更多的服务器,而在其它一些二线城市、其它省份也都有部署的。

  记者:您也是为这种大数据量做了充分的准备。最近大家都知道,玉树发生地震,对于这种突发事件,我们也会把微博作为一种信息交流、信息分享的平台,大家的访问也会造成大数据量访问,那么对于这种突发事件,您在技术架构上也做了相应的准备吗?

  卫华:对,这种突发事件以及访问峰值,是微博上经常出现的现象。突发事件的访问峰值有两种,一种是可以预测的,比如说我们将来要搞的世界杯,比如春节,大家都相互拜年这种;另外一种是不可预测的,比如地震这种。对可以预测的这种,我们事先会做准备,比如说世界杯,我们要增加相关的服务器来完成。而面对这种不可预测的情况时,我们平时会有个数字,那就是我们平时的平均流量,硬件设备要比它高一定量,这样就能够应对这种峰值的请求。

  另外从程序上来说,我们可能有一些专门的机制,比如说用户发表微博,并不是一发表就存到数据库中,简单地理解,他不是这样操作的。业界中微博之类的产品都有一种机制,叫做异步机制,也就是说,在发表的时候,我会把这个信息放到消息队列里面,然后再用另外一个专门的业务处理程序来处理它。当某一时刻发表量非常大,比如说地震了,很多人都会发表,那这个时候系统依然能够有条不紊的来处理这个业务,这样子就能让我们的系统稳定运行,并具有高可用性。

  记者:也就是要对整个事务的进行有效的控制?

  卫华:对。

  记者:大家应该知道,因为有这么多的微博,有那么多名人,而且还有很多平民的、草根的微博,系统的数据量也是非常非常大的,而且还有很多很多的评论,很多很多的留言等等。那么对于这种海量存储,是不是也要做技术架构上的准备?

  卫华:对,微博这个产品从技术上来说,有一个很大的特征,就是每天用户发表特别容易,这造成每天新增的数据量都是百万级的、上千万级的这样一个量。这样你经常要面对的一个问题就是增加服务器,因为一般一台服务器,它可能支撑的规模也就是几千万,或者说复杂一点只有几百万,这样,你可能每天都要增加服务器,从而解决所你面对的这些问题。你要考虑,如果每天要加服务器,你的程序上、访问上会不会有问题,会不会间断。

  我们其实有一些优化的方法,比如说我们会考虑热点数据和冷数据,如果经常要访问的这个数据,也就是热数据,而过几天才会访问的就是冷数据,我们会把它们合并,这样就可以按这个时间来分段,也就是把热数据放在一起,冷数据放在一起,这样可以解决这个访问热点的问题。

  另外业界还有种思路,刚才说的用mysql,我们采用shade的技术会按时间分片,这是一种解决思路;另外还有一种解决思路,业界特别现在国外流行的一种方法,也就是nosql的方法。有一种比较好的产品,现在大家比较关注,叫cassandra,就可以解决这个问题。如果我们每天要加一台服务器的话,那么我们程序、运维这些能不能跟上呢,是否有一种产品可以让你程序不需要做丝毫改动呢?cassandra这个产品就可以帮你来解决这个问题,你只需要把服务器插进去,那它马上可以使用,那个产品内部就有这样的机制。

 记者:那样的话对我们整个产品的维护就比较方便了?

  卫华:对,这个可能就是说以后业界发展的一种方向,使用这种分布式的存储来解决这种海量增长的问题。

  记者:你觉得nosql的数据库和传统的关系型的数据库,那种更适合微博这种形式的网站?

  卫华:从长远来说,nosql这个更适合一些,特别是分布式的nosql,刚才我也讲了,如果能全部下来的话,那可能经常要面对这种扩充的困扰,需要的干扰,可能是说,如果要保证服务不间断,可能就会面临一种很大的挑战,nosql,特别是这些分布式的nosql产品在内部就解决了这种问题,你不用停机,就可以加,加设备。

  记者:这会对我们用户造成很大的方便?

  卫华:对。

  记者:那么在性能方面,还有一种我们常采用的方式就是cache的方式,那么在新浪微博系统里面,cache方式有什么样的特点?

  卫华:在像微博这样的web2.0产品里面,技术界有一种很重要的说法,cache就是ram,ram就是memory的意思,ram也就是new disk,已经成为新的磁盘,代替磁盘的访问了。当我们大量使用cache的时候,可能会存在很多问题,比如很多那种web2.0的产品,它在cache的数量已经不是g的概念了,不是几g、4g、8g的,可能达到一个tb的概念了,一个t相当于1024g,面对这样海量的数据,那我们访问的时候可能就会出现很多新的问题,比如我们的带宽,因为用户请求我的凯发k8网页登录首页的时候,他会获取很多资源,比如有50个人关注你的微博,他需要从cache里面把这50个人的数据都聚合起来,同时还会有很多人也在访问这个,假如说,有一千个人访问,这一千个人里面,每个人都从五十个里面选,那么这个cache的带宽将是一个比较大的问题,这是以前那种我们使用cache时没有遇到过的。然后,为了解决这个带宽的问题,我们可以使用压缩的技术,我们保持cache里面的数据,经过一种快速的压缩算法,比较传统的我们可以使用gzip,那实际上在这种对时效性要求比较高的技术里面,我们是要求更快速的算法,比如说有一些dozo算法,它对消耗很小,但它压缩很快,效果也非常好。

  另外的一个新问题,单点故障,我们非常依赖那个cache,假如某个时候它突然崩溃了,那么应用访问可能就会遇到很大的问题,也就是响应速度会出问题,为了解决这个问题,我推荐的做法是,使用一致性的哈希算法,就说送我一个业务,他可以用多个cache服务器来完成,然后我们使用一致性的哈希算法,当一个cache崩溃之后,它的请求就可以分散到其它的cache来完成,总体的那个振荡不会太大,也就是说这个延迟会分散开来,让用户访问页面的时候感觉不到,实际上后台它可能有一台服务器,刚才经历一次crash,可能造成一次波动,经过我们这样改造之后,用户可能察觉不到这种变化。

  记者:用其它的服务器,同时来弥补这个地方的失误?

  卫华:对,使用一致性的哈希算法,能够巧妙地达到这个目的。

  记者:您刚才提到了nosql,另外在最近的业界还有一个流行的词就是cloud,云计算,我们是不是有计划以后会把微博系统推广到云平台上,或者说采用云计算的方式来处理呢?

  卫华:没错,我们微博现在有一部分跟云计算结合比较密切,我们现在微博正打算推出一个开放平台,开放平台什么意思呢?就是说,第三方的开发者可以在我们上面写应用,可以连接到新浪微博,比如说可以获取信息,可以发表微博,而这些应用程序,可以放在我们的开发的另外一个服务上,叫新浪云。这个新浪云有什么好处呢?这些第三方开发的应用,可能他刚开发的时候,请求量不大,但有可能因为这个创意很好,忽然访问量大了。如果你用你自己的凯发天生赢家一触即发官网的解决方案的话,可能就达不到这种要求。比如说最大的问题,可能就是全国访问不畅,或者访问量突然增长了,原来的服务器不够用,你要自己去加硬件,来不及处理。如果你放在那个新浪云上面的话,那我们系统自动会帮你解决这个问题,不管你的一个非常小的程序,比如一天只有几百个访问,还是一个海量的应用,我们都能够放在这个平台里面。在这个云应用里面,你不需要自己操心,系统自动会帮你把这个任务完成。另外它还有一个好处就是,这个云自动实现了全国分布,你只要host在上面,全国的用户不管从哪里访问,他可以访问一个就近的服务器,这在速度比自己部署都具有很大的优势。

  记者:那咱们新浪云现在已经正式推出来,还是正在计划中?

  卫华:我们现在还处于测试阶段,我们采用一种邀请式,希望邀请更多的开发者来试用它,我们根据开发者的反馈来改善它,等到一定程度,我们再去大规模地推广。

  记者:以后对于大家来维护自己的微博、访问别人微博,是不是也更方便,不一定非要到各种各样的网页上,或者是等等,可以在自己开发的程序上就可以做这些事了,对吧?

  卫华:对,以后结合这个微博的开放平台,结合新浪云,可以形成一个良好的生态圈,第三方的开发者要有一个很好的环境,给微博增加各种创意,增加各种应用。

  记者:这应该是对开发者带来的一个福音。

  卫华:对。

  记者:感谢杨卫华先生接受我们的采访。谢谢!



小马歌 2011-07-25 16:24
]]>几个负载均衡软件比较(haproxy vs lvs vs nginx)http://www.blogjava.net/xiaomage234/archive/2011/04/26/349040.html小马歌小马歌tue, 26 apr 2011 07:07:00 gmthttp://www.blogjava.net/xiaomage234/archive/2011/04/26/349040.htmlhttp://www.blogjava.net/xiaomage234/comments/349040.htmlhttp://www.blogjava.net/xiaomage234/archive/2011/04/26/349040.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/349040.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/349040.html

nginx的优点:

          性能好,可以负载超过1万的并发。

          功能多,除了负载均衡,还能作web服务器,而且可以通过geo模块来实现流量分配。

          社区活跃,第三方补丁和模块很多

          支持gzip proxy

              缺点:

           不支持session保持。

           对后端realserver的健康检查功能效果不好。而且只支持通过端口来检测,不支持通过url来检测。

           nginx对big request header的支持不是很好,如果 设置的比较小,就会返回400 bad request页面。

haproxy的优点:

          它的优点正好可以补充nginx的缺点。支持session保持,同时支持通过获取指定的url来检测后端服务器的状态。

          支持tcp模式的负载均衡。比如可以给mysql的从服务器集群和邮件服务器做负载均衡。

              缺点:

          不支持虚拟主机(这个很傻啊)

          目前没有nagios和cacti的性能监控模板

lvs的优点:

           性能好,接近硬件设备的网络吞吐和连接负载能力。

           lvs的dr模式,支持通过广域网进行负载均衡。这个其他任何负载均衡软件目前都不具备。

              缺点:

           比较重型。另外社区不如nginx活跃。



小马歌 2011-04-26 15:07
]]>千万级并发haproxy均衡负载系统介绍http://www.blogjava.net/xiaomage234/archive/2011/04/26/349039.html小马歌小马歌tue, 26 apr 2011 07:00:00 gmthttp://www.blogjava.net/xiaomage234/archive/2011/04/26/349039.htmlhttp://www.blogjava.net/xiaomage234/comments/349039.htmlhttp://www.blogjava.net/xiaomage234/archive/2011/04/26/349039.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/349039.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/349039.html阅读全文

小马歌 2011-04-26 15:00
]]>
arnish资源http://www.blogjava.net/xiaomage234/archive/2009/08/08/290319.html小马歌小马歌sat, 08 aug 2009 01:50:00 gmthttp://www.blogjava.net/xiaomage234/archive/2009/08/08/290319.htmlhttp://www.blogjava.net/xiaomage234/comments/290319.htmlhttp://www.blogjava.net/xiaomage234/archive/2009/08/08/290319.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/290319.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/290319.htmlhttp://www.vg.no) 使用3台varnish代替了原来的12台squid,

性能比以前更好。
varnish的作者poul-henning kamp是freebsd的内核开发者之一,他认为现在的计算机比起1975年已经复杂许多。在1975年时,储存媒介只有两

种:内存与硬盘。但现在计算机系统的内存除了主存外,还包括了cpu内的l1、l2,甚至有l3快取。硬盘上也有自己的快取装置,因此squid

cache自行处理物件替换的架构不可能得知这些情况而做到最佳化,但操作系统可以得知这些情况,所以这部份的工作应该交给操作系统处理,

这就是 varnish cache设计架构。

varnish项目:http://varnish.projects.linpro.no/
varnish 中文wiki:http://zh.wikipedia.org/wiki/varnish_cache


小马歌 2009-08-08 09:50
]]>
使用varnish代替squid做网站缓存加速器的详细凯发天生赢家一触即发官网的解决方案[转]http://www.blogjava.net/xiaomage234/archive/2009/08/08/290317.html小马歌小马歌sat, 08 aug 2009 01:42:00 gmthttp://www.blogjava.net/xiaomage234/archive/2009/08/08/290317.htmlhttp://www.blogjava.net/xiaomage234/comments/290317.htmlhttp://www.blogjava.net/xiaomage234/archive/2009/08/08/290317.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/290317.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/290317.html
我曾经写过一篇文章──《》,但当时仅仅是用着玩,没做深入研究。

今天写的这篇关于varnish的文章,已经是一篇可以完全替代squid做网站缓存加速器的详细凯发天生赢家一触即发官网的解决方案了。网上关于varnish的资料很少,中文资料更是微乎其微,希望本文能够吸引更多的人研究、使用varnish。

在我看来,使用varnish代替squid的理由有三点:
1、varnish采用了“visual page cache”技术,在内存的利用上,varnish比squid具有优势,它避免了squid频繁在内存、磁盘中交换文件,性能要比squid高。
2、varnish的稳定性还不错,我管理的一台图片服务器运行varnish已经有一个月,没有发生过故障,而进行相同工作的squid服务器就倒过几次。
3、通过varnish管理端口,可以使用正则表达式快速、批量地清除部分缓存,这一点是squid不能具备的。

点击在新窗口中浏览此图片


下面来安装varnish网站缓存加速器(linux系统):
1、创建www用户和组,以及varnish缓存文件存放目录(/var/vcache):
/usr/sbin/groupadd www -g 48
/usr/sbin/useradd -u 48 -g www www
mkdir -p /var/vcache
chmod w /var/vcache
chown -r www:www /var/vcache


2、创建varnish日志目录(/var/logs/):
mkdir -p /var/logs
chmod w /var/logs
chown -r www:www /var/logs


3、编译安装varnish:
wget
tar zxvf varnish-1.1.2.tar.gz
cd varnish-1.1.2
./configure --prefix=/usr/local/varnish
make && make install


4、创建varnish配置文件:
vi /usr/local/varnish/vcl.conf

输入以下内容:
引用
backend myblogserver {
       set backend.host = "192.168.0.5";
       set backend.port = "80";
}

acl purge {
       "localhost";
       "127.0.0.1";
       "192.168.1.0"/24;
}

sub vcl_recv {
       if (req.request == "purge") {
               if (!client.ip ~ purge) {
                       error 405 "not allowed.";
               }
               lookup;
       }

       if (req.http.host ~ "^blog.s135.com") {
               set req.backend = myblogserver;
               if (req.request != "get" && req.request != "head") {
                       pipe;
               }
               else {
                       lookup;
               }
       }
       else {
               error 404 "zhang yan cache server";
               lookup;
       }
}

sub vcl_hit {
       if (req.request == "purge") {
               set obj.ttl = 0s;
               error 200 "purged.";
       }
}

sub vcl_miss {
       if (req.request == "purge") {
               error 404 "not in cache.";
       }
}

sub vcl_fetch {
       if (req.request == "get" && req.url ~ "\.(txt|js)$") {
               set obj.ttl = 3600s;
       }
       else {
               set obj.ttl = 30d;
       }
}

这里,我对这段配置文件解释一下:
(1)、varnish通过反向代理请求后端ip为192.168.0.5,端口为80的web服务器;
(2)、varnish允许localhost、127.0.0.1、192.168.0.***三个来源ip通过purge方法清除缓存;
(3)、varnish对域名为blog.s135.com的请求进行处理,非blog.s135.com域名的请求则返回“zhang yan cache server”;
(4)、varnish对http协议中的get、head请求进行缓存,对post请求透过,让其直接访问后端web服务器。之所以这样配置,是因为post请求一般是发送数据给服务器的,需要服务器接收、处理,所以不缓存;
(5)、varnish对以.txt和.js结尾的url缓存时间设置1小时,对其他的url缓存时间设置为30天。

5、启动varnish
ulimit -shn 51200
/usr/local/varnish/sbin/varnishd -n /var/vcache -f /usr/local/varnish/vcl.conf -a 0.0.0.0:80 -s file,/var/vcache/varnish_cache.data,1g -g www -u www -w 30000,51200,10 -t 127.0.0.1:3500 -p client_http11=on


6、启动varnishncsa用来将varnish访问日志写入日志文件:
/usr/local/varnish/bin/varnishncsa -n /var/vcache -w /var/logs/varnish.log &


7、配置开机自动启动varnish
vi /etc/rc.local

在末尾增加以下内容:
引用
ulimit -shn 51200
/usr/local/varnish/sbin/varnishd -n /var/vcache -f /usr/local/varnish/vcl.conf -a 0.0.0.0:80 -s file,/var/vcache/varnish_cache.data,1g -g www -u www -w 30000,51200,10 -t 127.0.0.1:3500 -p client_http11=on
/usr/local/varnish/bin/varnishncsa -n /var/vcache -w /var/logs/youvideo.log &


8、优化linux内核参数
vi /etc/sysctl.conf

在末尾增加以下内容:
引用
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.ip_local_port_range = 5000    65000



再看看如何管理varnish:
1、查看varnish服务器连接数与命中率:
/usr/local/varnish/bin/varnishstat

点击在新窗口中浏览此图片

2、通过varnish管理端口进行管理:
用help看看可以使用哪些varnish命令:
/usr/local/varnish/bin/varnishadm -t 127.0.0.1:3500 help

引用
available commands:
ping [timestamp]
status
start
stop
stats
vcl.load
vcl.inline
vcl.use
vcl.discard
vcl.list
vcl.show
param.show [-l] [
]
param.set
help [command]
url.purge
dump.pool

3、通过varnish管理端口,使用正则表达式批量清除缓存:
(1)、例:清除类似的url地址):
/usr/local/varnish/bin/varnishadm -t 127.0.0.1:3500 url.purge /a/

(2)、例:清除类似的url地址:
/usr/local/varnish/bin/varnishadm -t 127.0.0.1:3500 url.purge w*$

(3)、例:清除所有缓存:
/usr/local/varnish/bin/varnishadm -t 127.0.0.1:3500 url.purge *$


4、一个清除squid缓存的php函数(清除varnish缓存同样可以使用该函数,无需作任何修改,十分方便):
  1. function purge($ip$url)   
  2. {   
  3.     $errstr = '';   
  4.     $errno = '';   
  5.     $fp = fsockopen ($ip, 80, $errno$errstr, 2);   
  6.     if (!$fp)   
  7.     {   
  8.          return false;   
  9.     }   
  10.     else  
  11.     {   
  12.         $out = "purge $url http/1.1\r\n";   
  13.         $out .= "host:blog.s135.com\r\n";   
  14.         $out .= "connection: close\r\n\r\n";   
  15.         fputs ($fp$out);   
  16.         $out = fgets($fp , 4096);   
  17.         fclose ($fp);   
  18.         return true;   
  19.     }   
  20. }   
  21.   
  22. purge("192.168.0.4""/index.php");   
  23. ?>  


附1:varnish官方网站:

附2:2007年12月10日,我写了一个每天0点运行,按天切割varnish日志,生成一个压缩文件,同时删除上个月旧日志的脚本(/var/logs/cutlog.sh):
/var/logs/cutlog.sh文件内容如下:
引用
#!/bin/sh
# this file run at 00:00
date=$(date -d "yesterday" "%y-%m-%d")
pkill -9 varnishncsa
mv /var/logs/youvideo.log /var/logs/${date}.log
/usr/local/varnish/bin/varnishncsa -n /var/vcache -w /var/logs/youvideo.log &
mkdir -p /var/logs/youvideo/
gzip -c /var/logs/${date}.log > /var/logs/youvideo/${date}.log.gz
rm -f /var/logs/${date}.log
rm -f /var/logs/youvideo/$(date -d "-1 month" "%y-%m*").log.gz

设置在每天00:00定时执行:
/usr/bin/crontab -e
或者
vi /var/spool/cron/root
输入以下内容:
引用
0 0 * * * /bin/sh /var/logs/cutlog.sh



tags: , , ,
» | | |
jacky
2007-12-3 10:28
varnish如何做到在不重启的情况下重新载入配置文件
jacky
2007-12-3 10:29
用varnish做反向代理的时候,登录一般的网站没有任何问题。登录dz论坛的后台出现无法登录,没有任何提示。用squid就没有这样的问题,不知道那位老大遇到过这样的问题。
回复于 2007-12-5 19:08
出问题是肯定的,因为本文中的varnish配置将缓存所有类型的文件,而你使用squid之所以正常,是因为在squid配置文件中没有配置去缓存php文件。同样,对于varnish,你可以选择不缓存.php文件,修改vcl.conf配置文件:
if (req.request != "get" && req.request != "head") {
  pipe;
}
elseif(req.url ~ "\.(php|cgi)($|\?)") {
  pass;
}
else {
  lookup;
}
itsea
2007-12-4 23:42
张兄,今天测了一下varnish,原来用nginx squid estab连接大概在1700的机器换了varnish后连接数只有300多了,访问起来一切正常,cacti查看到流量也是正常的,难道varnish就强在这shock?配置是按您的配置做的。
另外还有个问题vcache这个目录是用来保存cache文件的是吗?我在ll vcache里什么文件都没有。
还有用varnish这个方法还解决了一直让我头疼的squid不支持iis compress问题,实在太感谢了grin
回复于 2007-12-5 20:02
tcp连接数varnish要比squid少,因为varnish的tcp连接释放要比squid快。

但同时处理的请求数varnish要比squid高一些,这是我在f5 big-ip下的两台服务器,一台varnish、另一台squid,f5 big-ip分给它们的连接数相同,varnish实时处理的请求数比squid多1倍,平均处理的请求数也比squid多100余个:

/usr/local/webserver/varnish/bin/varnishstat
-----------------------------------------------------------
   70979868       580.97       356.55 client requests received
   70897998       580.97       356.14 cache hits

/usr/local/squid/bin/squidclient -p 80 mgr:5min
-----------------------------------------------------------
client_http.requests = 248.425264/sec
client_http.hits = 245.135282/sec


如果正常的话,vcache这个目录里只有一个大小为1g的文件:varnish_cache.data
itsea
2007-12-5 10:06
今天遇到的问题貌似跟楼上说的一样,varnish做反向代理后dvbbs登陆不正常,用户登陆后显示同一个用户名,验证码不变。
回复于 2007-12-5 19:21
同理,有些url是实时的,不需要被缓存,可以自己修改配置文件,用req.url ~过滤掉这些url。

不过,不建议对discus!、dvbbs等别人写的论坛程序使用squid、varnish做缓存,因为这些程序本身就没有用purge指令去刷新squid、varnish缓存的功能。

就连discuz!的官方论坛,也只不过对图片、css、js文件用squid进行了缓存,php等其他文件都是miss透过:


via  1.0 www1.discuz.net:80 (squid)
x-cache  miss from www1.discuz.net
x-powered-by  php/5.2.4


via  1.0 www1.discuz.net:80 (squid)
x-cache  miss from www1.discuz.net
x-powered-by  php/5.2.4


via  1.0 www1.discuz.net:80 (squid)
x-cache  hit from www1.discuz.net


via  1.0 www1.discuz.net:80 (squid)
x-cache  hit from www1.discuz.net
minuteman
2007-12-6 16:20
正好这两天我在自己的blog上也做了varnish缓存的实验
用varnishncsa输出日志,但发现里面有不少日志条目是127.0.0.1来的访问,觉得比较奇怪,是不是varnishd工作时候产生的?上网找也没找到相关的解释。
老大你有没有相关知识分享一下?嘿嘿
leftleg
2007-12-7 12:50
discuz 做缓存的话 ,可以试试使用缓存帖子分页。
jacky
2007-12-7 14:12
varnish可以实现类似于squid那样的父子节点关系吗?
itsea
2007-12-7 14:51
今天在另外一个平台上使用varnish测试
增加了
if (req.request != "get" && req.request != "head") {
                   pipe;
                 }
              elseif(req.url ~ "\.(aspx|asp|shtml|vimg)($|\?)") {
                   pass;
                 }
              else {
                   lookup;
                 }
}
后还是偶尔有用户登陆后显示别人的用户名
而且程序员更新js文件后不能马上看到
/usr/local/varnish/bin/varnishadm -t 127.0.0.1:3500 url.purge *$
purge所有后也不行,还发现一个小问题执行 varnishadm后容易使varnishd父进程吃cpu 100%一直下不来
我的访问量在 350 request/sec
e文的理解能力比较查在man跟官方faq里似乎没看到类似情况
minuteman
2007-12-7 17:57
缓存不该缓存的对象的问题
也许可以通过在recv里
   if (req.http.cache-control ~ "no-cache") {
       pass;
   }
在fetch里加
   if (obj.http.pragma ~ "no-cache" || obj.http.cache-control ~ "no-cache" || obj.http.cache-control ~ "private") {
       pass;
   }
leftleg
2007-12-10 16:00
ping [timestamp]
status
start
stop
stats
vcl.load
vcl.inline
vcl.use
vcl.discard
vcl.list
vcl.show
param.show [-l] []
param.set
help [command]

telnet 管理有个 vcl.load 应该可以 不重启的情况下重新载入配置文件
小春
2007-12-20 12:02
张老师,我装好了,一切正常,只提到的管理这些功能不正常:
[root@linux1 ~]# /usr/local/varnish/bin/varnishadm -t 127.0.0.1:3500
usage: varnishadm -t [address]:port command [...]

上面命令明明没有问题,端口监听也正常.

[root@linux1 ~]# /usr/local/varnish/bin/varnishstat
cannot open /usr/local/varnish/var/varnish/www.38hao.org/_.vsl: no such file or directory
但是我的,这_.vsl文件明明是在/data/cache目录下,他非到 /usr/local/varnish/var/varnish/下读!
回复于 2007-12-20 21:31
/usr/local/varnish/bin/varnishstat -n /data/vcache
jack
2007-12-21 09:59
[root@localhost root]# cat start_cache.sh
ulimit -shn 51200
/usr/local/varnish/sbin/varnishd -n /home/cache -f /usr/local/varnish/vcl.conf -a 0.0.0.0:81 -s file,/home/cache/varnish_cache.data,1g -g www -u www -w 30000,51200,10 -t 127.0.0.1:3500 -p client_http11=on
/usr/local/varnish/bin/varnishncsa -n /home/cache -w /home/logs/www.log &
[root@localhost root]# sh start_cache.sh
file /home/cache/varnish_cache.data size 1073741824 bytes (262144 fs-blocks, 262144 pages)
using old shmfile
[root@localhost root]# netstat -untl
active internet connections (only servers)
proto recv-q send-q local address               foreign address             state      
tcp        0      0 0.0.0.0:199                 0.0.0.0:*                   listen      
tcp        0      0 0.0.0.0:80                  0.0.0.0:*                   listen      
tcp        0      0 0.0.0.0:21                  0.0.0.0:*                   listen      
tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   listen      
tcp        0      0 127.0.0.1:25                0.0.0.0:*                   listen      
udp        0      0 0.0.0.0:161                 0.0.0.0:*  

服务启动时也不报错,就是看不到varnish监听的端口,如何debug? 实在看不出什么问题,
请张老师指点一下!
coffee
2007-12-21 16:49
(1)、varnish通过反向代理请求后端ip为192.168.0.5,端口为80的web服务器;
backend.host  如果有多台的话 是否也可以象 squid 那样设置在 hosts文件里面,
(3)、varnish对域名为blog.s135.com的请求进行处理,非blog.s135.com域名的请求则返回“zhang yan cache server”;  
squid 可以根据到目的ip是否符合在判断是否可以使用 这样就不用判断域名 不知道在 varnish 也可以这样设置
阿木
2007-12-23 08:34
张老师,我服务器上用varnish nginx在同一台机器上跑,运行没有三分钟的时候,就开始卡,仍后几乎网页打不开。不知道什么原因,而我在本地虚拟环境测试一点问题都没有,只是本地的是varnish apache,而线上服务器是varnish nginx,有点不解,请张老师指点一下,有遇到想关问题的朋友指点一下!
原来本地是squid nginx速度飞快,现在是varnish nginx就卡得不行...
varnish
2008-1-4 17:41
问下varnish 怎么配置 泛域名 的主机,我很很多二级域名,比如 xx.abc.com    ,一个一个加好麻烦。。。squid 或者nginx 都支持 .abc.com 的
回复于 2008-1-4 21:24
if (req.http.host ~ "^blog.s135.com") {
改成
if (req.http.host ~ ".abc.com") {
2008-1-5 11:38
张老师,我连菜鸟都算不上。。
想问问如何,把访问的地址的ip更换成的类型呢?
需要什么才可以的吗?
antiaiqingno
2008-1-6 16:56
需要反向dns
2008-1-6 18:30
问个问题,如果要做个全国性的网站负载均衡,可否搭配varnish f5 bigip实现
1.varnish专门做cache  server
2.f5 bigip用做服务器负载均衡
回复于 2008-1-7 08:16
f5 bigip varnish是可行的,但是varnish的缓存基本上在内存中,如果varnish进程停止再启动,varnish就会重新访问后端web服务器。
还有种方案就是f5 bigip squid,squid的缓存会保持在磁盘和内存,虽然squid性能没有varnish高,但它停止、重启的时候,可以直接先从磁盘读取缓存数据。
2008-1-9 15:36
引用
f5 bigip varnish是可行的,但是varnish的缓存基本上在内存中,如果varnish进程停止再启动,varnish就会重新访问后端web服务器。
还有种方案就是f5 bigip squid,squid的缓存会保持在磁盘和内存,虽然squid性能没有varnish高,但它停止、重启的时候,可以直接先从磁盘读取缓存数据。


这样的话.重启varnish会导致边缘节点访问一定时间内卡一下吧?
内存方式虽然快.但是这点上会很郁闷了.
2008-1-16 01:45
张老师:我出现如下错误
101 32      
all commands are in lower-case.

我的配置是这样的 varnish 和 nginx 同在一台机器上,没办法,只有一台机器。我把varnish配置为公网的80,如 210.21.21.21:80 这样,nginx配置为:127.0.0.1:80 启动是正常的,但访问时出现
101 32      
all commands are in lower-case.

请教一下怎样解决。
2008-1-16 12:42
sub vcl_hit {
      if (req.request == "purge") {
              set obj.ttl = 0s;
              error 200 "purged.";
      }
}

这段不是很理解
每次获取到以后就把生存期设置成0?
那么不是每次请求都是分发去backend了?
没有起到cache的作用了?
回复于 2008-1-16 14:50
http协议通常有三种方法,get、head和post。而purge是一种由squid作者定义的非http官方方法,用来清除squid缓存,我为了兼容squid,也沿用squid的purge方法来清除varnish缓存。

通过浏览器访问一个url地址,发送的http请求头是:
get
当遇到get或head方法,varnish会从缓存中返回网页:

当从浏览器提交表单时(请求头中的方法为post),需要透过varnish将信息传递给后端web服务器上的php程序处理,下面这几行表示如果请求头中的方法不是get和head,则透过varnish访问后端web服务器:
if (req.request != "get" && req.request != "head") {
pipe;
}

当遇到purge方法时,varnishd会set obj.ttl = 0s;使某个url的缓存失效,从而达到刷新varnish缓存的目的。varnish配置了只接收并处理以下ip发送purge请求:
acl purge {
      "localhost";
      "127.0.0.1";
      "192.168.1.0"/24;
}
2008-1-16 17:21
谢谢.今天看到varnish没有txt格式的help和sample.
倒是man里面非常详细.
powerv
2008-1-19 18:30
不知道大家dz后台登陆问题解决没有,有的话请给个方案。我按
if (req.request != "get" && req.request != "head") {
 pipe;
}
elseif(req.url ~ "\.(php|cgi)($|\?)") {
 pass;
}
else {
 lookup;
}
也还是没解决。php是没被缓存,但还是无法登陆后台。
25hours
2008-2-1 15:18
看你的数据,跑得相当不错
我测试了下,当varnish创建了100多个worker后
varnishlog -i debug出现大量的 create worker thread failed 12 cannot allocate memory错误,还没发现该如何解决,我的环境是dell2950 4g mem/rhel4u4
1
2008-2-26 18:14
有没有加速网页刷新后不变的加速器
鸡尾酒
2008-3-16 22:01
squid可以批量删除,需要安装purge
然后squid用acl给purge的权限。
geminis
2008-3-17 17:19
这个软件不知道是否支持 反向代理??
gerry
2008-4-1 18:20
sir,我发现varnish在日志操过2g的时候就不写日志了,哪个参数可以修改?
2008-6-20 11:10
张哥
请教你个问题
我采用单机做下载服务器,本机varnish运行在80端口,nginx在81
下载的文件夹中的exe文件很快,但是下载其它的文件,比如:zip\dat\等文件就很慢,时常报
503 service temporarily unavailable

还有就是dat文件我是要下载,但在ie中打开绝对路径.却是把文件中的内容给解释出来了,
请帮帮我,应该如何配置!
谢谢
2008-6-20 17:59
我们试用时,发现 varnish 在将 virtual memory 占用达到 3g 时( linux 的 top 显示), cache 命中率会直接返回到 0%, 似乎是 varnish 的处理程序自动 reset 了,不知这个是个已知的 bug 还是什么其他问题?

这个故障在我这里是反复出现。
网友一个
2008-6-24 16:34
张老师你好。我按照你这个成功建立了。
但是,有写命令却用不了。比如/usr/local/varnish/bin/varnishstat,好像是没有编译好。不知道为什么
kevin
2008-7-2 16:36
您好,请问varnish配置生效除了重启以外没有别的办法么?
另外,vcl.conf控制访问的时候不支持非运算么?
我想实现除了所有的静态文件都转发到后台的web服务器,但是好像失败了
if (req.http.host ~ ".test.com") {
              set req.backend = webserver;
              if (req.request != "get" && req.request != "head") {
                      pipe;
              }
               elseif(req.url !~ "\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|js|htm|html)($|\?)") {
                      pass;
              }
              else {
                      lookup;
              }
      }
2008-8-28 11:59
varnish 做代理服务cache 怎么实现?
yyrjw
2008-8-29 09:50
varnish 2.0出来了,不知道张大哥对其参数设置有没有做过测试,想把1.2升到2.0,具体的参数调优不大清楚
freeke
2008-9-4 10:25
强烈支持张老师再将这个版本更新v2
dell
2008-9-11 18:05
/usr/local/varnish/bin/varnishstat  执行这个命令的时候.全是0.怎么回事
chaing
2008-10-10 16:22
引用
/usr/local/varnish/bin/varnishstat  执行这个命令的时候.全是0.怎么回事

说明varnish没有起作用,查看下配置文件
hello
2008-10-30 09:49
请问如何缓存动态网页?
meikuai
2008-11-26 18:32
请问 varnish只用内存做缓存, 机器 如果内存只有2g, 但缓存的内容 有几十g,是不是就不合适用它呢, 另外大的(超过2m)文件,也不适合用它吧。 这点还是squid 比较合适。
回复于 2008-11-26 18:41
是的。
key
2008-12-30 18:24
我的网站架构是:
前端是一个lvs,后端是apache tomcat,假设域名指向lvs的59.141.45.67这个ip
例如:
tcp  59.141.45.67:80 wlc persistent 900
 -> 192.168.1.116:80            
 -> 192.168.1.113:80          
后端的192.168.1.116和192.168.1.113是用的apache tomcat,准备加varnish cache
现在已经是把动态和静态分开了,现在就是想把静态的做varnish cache

不知道这样的架构varnish cache 加在什么地方,是lvs上,还是其他的机器上
比如说我的域名是指向的是lvs的ip,当我访问的时候它首先访问lvs,
然后通过lvs分到两台realserver,那cache是怎么样调用的呢,这块有点迷惑

请张宴老师指点指点!!!!
狂乱
2009-5-12 12:28
有最新版的说明么?现在最新2.0.4没有办法按照你的安装
一刀砍死
2009-7-21 17:09
引用
网友一个2008-6-24 16:34
张老师你好。我按照你这个成功建立了。
但是,有写命令却用不了。比如/usr/local/varnish/bin/varnishstat,好像是没有编译好。不知道为什么

没有ncurses-devel




小马歌 2009-08-08 09:42
]]>
squid 2.7 通过域名反向代理多个服务器配置成功[转]http://www.blogjava.net/xiaomage234/archive/2009/07/28/288704.html小马歌小马歌tue, 28 jul 2009 03:51:00 gmthttp://www.blogjava.net/xiaomage234/archive/2009/07/28/288704.htmlhttp://www.blogjava.net/xiaomage234/comments/288704.htmlhttp://www.blogjava.net/xiaomage234/archive/2009/07/28/288704.html#feedback1http://www.blogjava.net/xiaomage234/comments/commentrss/288704.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/288704.htmlvisible_hostname squid1.abc.com

#设定squid的主机名,如无此项squid将无法启动

http_port 
80 accel vhost vport

#设定squid为accel加速模式,vhost必须要加.否则将无法将主机头转发至后端服务器,访问时就会出现无法找到主机头的错误

cache_peer 
192.168.1.88 parent 80 0 no-query originserver name=contentchina

cache_peer 
192.168.1.88 parent 80 0 no-query originserver name=bbs

cache_peer 
192.168.1.1 parent 80 0 no-query originserver name=ihompy

#定义不同的父节点,将节点设为no-query以及originserver说明这些节点是实际服务器

cache_peer_domain contentchina 
aaa.abc.com

cache_peer_domain bbs bbb.abc.com

cache_peer_domain ihompy ccc.abc.com

#设定不同域名转发到不同的cache_peer上,如果没有这项.不同域名的域名可能被分发到同一台服务器上.

acl all src 
0.0.0.0/0.0.0.0

no_cache deny all

http_access allow all

#允许所有客户端访问

cache_log /var/log/squid/cache.log

#记录日志

#***********acl存取控制*************

#acl querystring url_regex .php?

#***********缓冲存取控制*************

#no_cache deny querystring

#不对符合querystring的acl内容进行缓冲

#***********性能优化配置*************

maximum_object_size 
320010 kb

#大于此容量的对象将不会被保存在磁盘上,默认大小是4m,如果squid服务器用于缓冲flash等大型文件,建议将此值变大.否则过大的文件在下次重启后将需要重新获取

maximum_object_size_in_memory 
100 kb

#最大位于内存中的对象的大小,默认大小是8k,如果服务器内存很大.可以适当提高此值的大小,建议根据网站的80%图片的大小来定.或者根据web服务器实际存取文件中最常访问的文件大小来定制

#***********其他可选配置*************

#dns_nameservers 
10.0.0.1 192.172.0.4

#配置dns服务器地址.获取后端时将从此dns获取ip地址

#cache_mgr ggg_g@tom.com

#在错误日志中出现的webmaster地址.


小马歌 2009-07-28 11:51
]]>
squid使用详解[转]http://www.blogjava.net/xiaomage234/archive/2009/07/28/288703.html小马歌小马歌tue, 28 jul 2009 03:44:00 gmthttp://www.blogjava.net/xiaomage234/archive/2009/07/28/288703.htmlhttp://www.blogjava.net/xiaomage234/comments/288703.htmlhttp://www.blogjava.net/xiaomage234/archive/2009/07/28/288703.html#feedback0http://www.blogjava.net/xiaomage234/comments/commentrss/288703.htmlhttp://www.blogjava.net/xiaomage234/services/trackbacks/288703.html 1.squid 简介
  squid 是一个缓存internet数据的一个软件,它接收用户的下载申请,并自动处理所下载的数据。也就是说,当一个用户象要下载一个凯发k8网页登录主页时,它向squid 发出一个申请,要squid 替它下载,然后squid连接所申请网站并请求该凯发k8网页登录主页,接着把该凯发k8网页登录主页传给用户同时保留一个备份,当别的用户申请同样的页面时,squid 把保存的备份立即传给用户,使用户觉得速度相当快。目前,squid 可以代理http, ftp, gopher, ssl 和 wais 协议,暂不能代理pop, nntp等协议。不过,已经有人开始修改squid,相信不久的将来,squid能够代理这些协议。
  squid能够缓存任何数据吗?不是的。象缓存信用卡帐号、可以远方执行的scripts、经常变换的凯发k8网页登录主页等是不合适的也是不安全的。squid可以自动的进行处理,你也可以根据自己的需要设置squid,使之过滤掉你不想要的东西。
  squid可以工作在很多的操作系统中,如aix, digital unix, freebsd, hp-ux, irix, linux, netbsd, nextstep, sco, solaris,os/2等,也有不少人在其他操作系统中重新编译过squid。
  squid对硬件的要求是内存一定要大,不应小于128m,硬盘转速越快越好,最好使用服务器专用scsi硬盘,处理器要求不高,400mh以上既可。
2. squid的编译和运行
  其实现在的linux发行套件中基本都有已经编译好的squid,你所作的就是安装它既可。如果你手头没有现成的编译好的squid或想使用最新的版本,去ftp:squid.nlanr.net下载一份,自己编译。
  squid的编译是非常简单的,因为它基本上是自己配置自己。最容易出现的问题是你的系统上没有合适的编译器,这可以通过安装相应的编译器解决。如果出现其他问题,你可以问一下有经验的用户或到相应的邮件列表寻找帮助。
  编译squid之前,最好建一个专门运行squid的用户和组。我就在自己的服务器上建了一个名为squid的用户和组,用户目录设为/usr/local/squid。然后su为用户squid并从squid.nlanr.net下载squid的源文件到目录 /usr/local/squid/src中,用如下命令进行解压:
  %tar xzf squid-2.0.release-src.tar.gz
  %cd /usr/local/squid/src/ squid-*.*.release /
  %./configure
  %make
  %make install
  第一个命令在目录/usr/local/squid/src中产生一个新的子目录/squid-*.*.release/。命令./configure会自动查询你的系统配置情况以及你系统中使用的头文件。不加参数的./configure会把squid安装在目录/usr/local/squid中,如果你想使用其他目录,用如下命令./configure --prefix=/some/other/directory,这会把squid安装在目录/some/other/directory中。make命令编译squid,make install命令安装squid。
  不出意外的话,目录/usr/local/squid中会出现如下目录:
  /bin
  /cache
  /etc
  /logs/
  /src (自己创建的)
  目录/bin中含有squid可执行程序,包括squid本身,ftpget等。
  目录/cache包含squid缓存的数据,其中包含象/00/ /01/ /02/ 以及/03/这样的目录,这些目录中还有子目录,因为目录多了比在一个目录成千上万的文件中寻找一个文件更容易,速度更快。
  目录/etc中包含squid的唯一的配置文件squid.conf。
  目录/logs中包含squid的日志。
3. squid.conf文件的配置
  在安装squid后,在目录/usr/local/squid /etc中会自动产生一个样本squid.conf文件,文件中对每一个选项都有详细的说明,用户可以通过修改该文件以满足不同的需要。
  总的来说,有如下几个重要选项:
  ?http_port:设定squid监听的端口,你最好设一个比较好记的端口号,以便在进行客户机配置时容易记住。我的机器上端口号设的是8080。缺省为3128。
  ?cache_mem:设定squid占用的物理内存,根据我的经验,cache_mem的大小不应超过你的服务器物理内存的三分之一,否则将会影响机器的总体性能。
  ?maximum_object_size:设定squid可以接收的最大对象的大小。squid缺省值为4m,我自己入认为太大,你可以根据自己的需要进行设定。
  ?cache_dir:设定缓存的位置、大小。一般看起来形式如下“cache_dir /usr/local/squid/cache 100 16 256”。 /usr/local/squid/cache代表缓存的位置;100代表缓存最大为100m;16和256代表一级和二级目录数。
  ?cache_effective_user:设定使用缓存的有效用户。缺省为用户nobody,如果你的系统中没有用户nobody,最好建一个或以非root用户运行squid。
  下面我给出一个最简单的squid.conf文件:
  #squid.conf - a very basic config file for squid
  #turn logging to its lowest level
  debug_options all,1
  #defines a group (or access control list) that includes all ip addresses
  acl all src 0.0.0.0/0.0.0.0
  #define ram used
  cache_mem 32m
  #defines the cache size
  cache_dir /usr/local/squid/cache 100 16 256
  #allow all sites to use connect to us via http
  http_access allow all
  #allow all sites to use us as a sibling
  icp_access allow all
  #test the following sites to check that we are connected
  dns_testnames internic.net usc.edu cs.colorado.edu mit.edu yale.edu
  #run as the squid user
  cache_effective_user squid squid
  这个配置文件允许所有人使用squid,创建了100m缓存,使用32m内存,在缺省位置"/usr/local/squid/cache"缓存数据,所有缓存数据以组squid和用户squid身份保存,端口为3128。虽然这个配置很不安全,但是它已经能使用了。
4. 运行squid
  首先以root身份登陆。运行如下命令:
  %/usr/local/squid/bin/squid ?z
  该命令会产生squid所有的缓存目录。
  如果你想前台执行squid,接着执行命令:
  %/usr/local/squid/bin/squid -ncd1
  该命令正式启动squid。如果一切正常,你会看到一行输出
  ready to serve requests.
  如果想后台运行squid,把它做为一个精灵进程,执行命令:
  %/usr/local/squid/bin/squid
  观察squid是否运行使用命令:
  % squid -k check
  输出会告诉你squid的当前状态。
  好了,文章先写到这里,其实这里介绍的都是最基本的东西,squid有好多高级的功能,如做web服务器的高速缓存,做二级代理服务器,做为防火墙,以及怎样设定过滤规则等,这里就不详述了,如果有机会再奉献给大家。

小马歌 2009-07-28 11:44
]]>
网站地图