志当存高远,功到自然成!

少年强则中国强,少年进步则中国进步!

BlogJava 首页 新随笔 联系 聚合 管理
  53 Posts :: 2 Stories :: 2 Comments :: 0 Trackbacks

2008年11月13日 #

mysql 5.1支持触发器以及自定义函数接口(UDF)的特性,如果配合libmemcache以及Memcached Functions for MySQL,就能够实现memcache的自动更新。简单记录一下安装测试步骤。

  mysql 5.1支持触发器以及自定义函数接口(UDF)的特性,如果配合libmemcache以及Memcached Functions for MySQL,就能够实现memcache的自动更新。简单记录一下安装测试步骤。

  安装步骤

  安装memcached,这个步骤很简单,随处可见。安装mysql server 5.1RC,安装办法也很大众,不废话 了。

  编译libmemcached,解压后安装即可./configure; make; make install

  编译Memcached Functions for MySQL,在http://download.tangent.org/找一个最新的版本下载就 是,./configure --with-mysql=/usr/local/mysql/bin/mysql_config -- libdir=/usr/local/mysql/lib/mysql/

  make

  make install

  接下来有两个办法让Memcached Functions for MySQL在mysql中生效。

  在mysql的shell中执行memcached_functions_mysql源码目录下的sql/install_functions.sql,这会 把memcache function作为UDF加入mysql。

  运行memcached_functions_mysql源码目录下的utils/install.pl,这是一个perl脚本,作用同上一 条。

  测试memcache function。

  以下测试脚本摘自memcached_functions_mysql的源码目录,有兴趣可以试试。


PLAIN TEXTCODE: drop table if exists urls;
create table urls (
id int(3) not null,
url varchar(64) not null default '',
primary key (id)
);
select memc_servers_set('localhost:11211');
select memc_set('urls:sequence', 0);
DELIMITER |
DROP TRIGGER IF EXISTS url_mem_insert;
CREATE TRIGGER url_mem_insert
BEFORE INSERT ON urls
FOR EACH ROW BEGIN
SET NEW.id= memc_increment('urls:sequence');
SET @mm= memc_set(concat('urls:',NEW.id), NEW.url);
END |
DELIMITER ;
insert into urls (url) values ('http://google.com');
insert into urls (url) values ('http://www.ooso.net/index.php');
insert into urls (url) values ('http://www.ooso.net/');
insert into urls (url) values ('http://slashdot.org');
insert into urls (url) values ('http://mysql.com');
select * from urls;
select memc_get('urls:1');
select memc_get('urls:2');
select memc_get('urls:3');
select memc_get('urls:4');
select memc_get('urls:5');
posted @ 2010-08-12 15:22 存鹰之心于高远,取鹰之志而凌云,习鹰之性以涉险,融鹰之神在山巅. 阅读(454) | 评论 (0)编辑 收藏

假设我们有3台memcached 服务器,server1 和server2 有3GB 的内存空间,server3 有2GB 的内存空间.
下面程序说明怎么来创建客户端.
import com.danga.MemCached.*;

public class MyClass {

// 创建一个 memcached 客户端对象

protected static MemCachedClient mcc = new MemCachedClient();

// 创建  memcached连接池

static

{  // 指定memcached服务地址 String[] servers =
{ "server1.mydomain.com:1121","server2.mydomain.com:1121",
"server3.mydomain.com:1121" };
// 指定memcached服务器负载量
Integer[]  weights    ={ 3, 3, 2 };
// 从连接池获取一个连接实例

SockIOPool pool = SockIOPool.getInstance();

// 设置服务器和服务器负载量

pool.setServers( servers );

pool.setWeights( weights );

// 设置一些基本的参数

//设置初始连接数5   最小连接数 5   最大连接数 250

//设置一个连接最大空闲时间6小时

pool.setInitConn( 5 );

pool.setMinConn( 5 );

pool.setMaxConn( 250 );

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

// 设置主线程睡眠时间

// 每隔30秒醒来  然后

// 开始维护 连接数大小

pool.setMaintSleep( 30 );

// 设置tcp 相关的树形

// 关闭nagle算法

// 设置 读取 超时3秒钟  set the read timeout to 3 secs

//  不设置连接超时

pool.setNagle( false );

pool.setSocketTO( 3000 );

pool.setSocketConnectTO( 0 );

// 开始初始化 连接池

pool.initialize();

// 设置压缩模式

//如果超过64k压缩数据

mcc.setCompressEnable( true );

mcc.setCompressThreshold( 64 * 1024 );

}

public static void examples() {

mcc.set( "foo", "This is a test String" );

String bar = mcc.get( "foo" );

}

}
MemCachedClient 类 常用的方法说明

创建 client对象 设置参数:

MemCachedClient mc = new MemCachedClient();
//压缩模式
mc.setCompressEnable(true);
// 如果 cache数据 大于4 KB  就启用压缩
mc.setCompressThreshold(4096);
// 基本类型tostring方法
// 通常不需要设置
mc.setPrimitiveAsString(true);
存储一个对象:

MemCachedClient mc = new MemCachedClient();

String key   = "cacheKey1";

Object value = SomeClass.getObject();

mc.set(key, value);
用客户端hashcode 存储一个对象:


MemCachedClient mc = new MemCachedClient();

String key   = "cacheKey1";

Object value = SomeClass.getObject();

Integer hash = new Integer(45);

mc.set(key, value, hash);

set方法:在cache中存储一个指定对象

   add 和replace 方法功能差不多

  add -- 如果不存在 这个key的对象,将会存储一个对象到cache中
  replace --只有当存在指定key对象的时候 会覆盖已有对象
删除一个对象:

MemCachedClient mc = new MemCachedClient();

String key   = "cacheKey1";

mc.delete(key);
结合hashcode 删除一个对象:

MemCachedClient mc = new MemCachedClient();

String key   = "cacheKey1";

Integer hash = new Integer(45);

mc.delete(key, hashCode);
怎么cache计数,增 减计数:

MemCachedClient mc = new MemCachedClient();

String key   = "counterKey";

mc.storeCounter(key, new Integer(100));

System.out.println("counter after adding      1: " mc.incr(key));

System.out.println("counter after adding      5: " mc.incr(key, 5));

System.out.println("counter after subtracting 4: " mc.decr(key, 4));

System.out.println("counter after subtracting 1: " mc.decr(key));
利用客户端的hashcode存储计数 增减 计数:

MemCachedClient mc = new MemCachedClient();

String key   = "counterKey";

Integer hash = new Integer(45);

mc.storeCounter(key, new Integer(100), hash);

System.out.println("counter after adding      1: " mc.incr(key, 1, hash));

System.out.println("counter after adding      5: " mc.incr(key, 5, hash));

System.out.println("counter after subtracting 4: " mc.decr(key, 4, hash));

System.out.println("counter after subtracting 1: " mc.decr(key, 1, hash));
获取一个对象:

MemCachedClient mc = new MemCachedClient();

String key   = "key";

Object value = mc.get(key);
用客户端hashcode获取一个对象:

MemCachedClient mc = new MemCachedClient();

String key   = "key";

Integer hash = new Integer(45);

Object value = mc.get(key, hash);
MemCachedClient mc = new MemCachedClient();

String key   = "key";

Integer hash = new Integer(45);

Object value = mc.get(key, hash);
从cache 中获取多个对象

MemCachedClient mc = new MemCachedClient();

String[] keys      ={ "key", "key1", "key2" };Mapvalues = mc.getMulti(keys);
用客户端hashcode 从cache中获取多个对象
MemCachedClient mc = new MemCachedClient();
String[] keys      = { "key", "key1", "key2" };

Integer[] hashes   =
{ new Integer(45), new Integer(32), new Integer(44) };
Mapvalues = mc.getMulti(keys, hashes);
清空所有的对象
MemCachedClient mc = new MemCachedClient();

mc.flushAll();
得到服务器memcached的状态信息
MemCachedClient mc = new MemCachedClient();

Map stats = mc.stats();
注意点
1:Failover/Failback
当一个memcached服务器失效的时候客户端默认会failover另一个服务去.

如果失效的服务器 恢复运行,客户端会返回到原来连接的服务器.
如果你不想用这个功能 设置下面的参数
pool.setFailover( false );
pool.setFailback( false );

2:序列化

Boolean
Byte
String
Character
StringBuffer
StringBuilder
Short
Long
Double
Float
Date
java默认的类型没有实现序列化 可以设置
mcc.setPrimitiveAsString( true )替代.
Meetup.com实践过程中得出的一个经验 ,项目中model 对象implement Externalizable 实现序列化,
可以节省cache 对象的大小。从而节省网络带宽和内存空间。
posted @ 2010-08-11 23:21 存鹰之心于高远,取鹰之志而凌云,习鹰之性以涉险,融鹰之神在山巅. 阅读(10756) | 评论 (1)编辑 收藏

一:硬架构

1 :机房的选择:

在 选择机房的时候,根据网站用户的地域分布,可以选择网通或电信机房,但更多时候,可能双线机房才是合适的。越大的城市,机房价格越贵,从成本的角度看可以 在一些中小城市托管服务器,比如说广州的公司可以考虑把服务器托管在东莞,佛山等地,不是特别远,但是价格会便宜很多。

2 :带宽的大小:

通常老板花钱请我们架构网站的时候,会给我们提出一些目标,诸如网站每天要能承受100 万PV 的访问量等等。这时我们要预算一下大概需要多大的带宽,计算带宽大小主要涉及两个指标(峰值流量和页面大小),我们不妨在计算前先做出必要的假设:

第一:假设峰值流量是平均流量的5 倍。
第二:假设每次访问平均的页面大小是100K 字节左右。

如果100 万PV 的访问量在一天内平均分布的话,折合到每秒大约12 次访问,如果按平均每次访问页面的大小是100K 字节左右计算的话,这12 次访 问总计大约就是1200K 字节,字节的单位是Byte ,而带宽的单位是bit ,它们之间的关系是1Byte = 8bit ,所以1200K Byte 大致就相当于9600K bit ,也就是9Mbps 的样子,实际情况中,我们的网站必须能在峰值流量时保持正常访问,所以按照假设的峰值流量算,真实带宽的需求应该在45Mbps  左右。

当然,这个结论是建立在前面提到的两点假设的基础上,如果你的实际情况和这两点假设有出入,那么结果也会有差别。

3 :服务器的划分:

先看我们都需要哪些服务器:图片服务器,页面服务器,数据库服务器,应用服务器,日志服务器等等。

对于访问量大点的网站而言,分离单独的图片服务器和页面服务器相当必要,我们可以用lighttpd 来跑图片服务器,用apache 来跑页面服务 器,当然也可以选择别的,甚至,我们可以扩展成很多台图片服务器和很多台页面服务器,并设置相关域名,如img.domain.com 和 www.domain.com ,页面里的图片路径都使用绝对路径,如<img src="http://img.domain.com/abc.gif" /> ,然后设置DNS 轮循,达到最初级的负载均衡。当然,服务器多了就不可避免的涉及一个同步的问题,这个可以使用rsync 软件来搞定。

数据库服务器是重中之重,因为网站的瓶颈问题十有八九是出在数据库身上。现在一般的中小网站多使用MySQL 数据库,不过它的集群功能似乎还没有达 到stable 的阶段,所以这里不做评价。一般而言,使用MySQL 数据库的时候,我们应该搞一个主从(一主多从)结构,主数据库服务器使用innodb  表结构,从数据服务器使用myisam 表结构,充分发挥它们各自的优势,而且这样的主从结构分离了读写操作,降低了读操作的压力,甚至我们还可以设定一个专门的从服务器做备份服务器,方便备份。不然如果你只有一台主服务器,在大数据量的情况下,mysqldump 基本就没戏了,直接拷贝数据文件的话,还得先停止数据库服务再拷贝,否则备份文件会出错。但对于很多网站而言,即使数据库服务仅停止了一秒也是不可接受的。如果你有了一台从数据库服务器,在备份数 据的时候,可以先停止服务(slave stop )再备份,再启动服务(slave start )后从服务器会自动从主服务器同步数据,一切都没有影响。但是主从结构也是有致命缺点的,那就是主从结构只是降低了读操作的压力,却不能降低写操作的压力。为了适应更大的规模,可能只剩下最后这招了:横向/ 纵向分割数据库。所谓横向分割数据库,就是把不同的表保存到不同的数据库服务器上,比如说用户表保存在A 数据库服务器上,文章表保存在B 数据库服务器上,当然这样的分割是有代价的,最基本的就是你没法进行LEFT JOIN 之类的操作了。所谓纵向分割数据库,一般是指按照用户标识(user_id )等来划分数据存储的服务器,比如说:我们有5 台数据库服务器,那么 “user_id % 5 + 1” 等于1 的就保存到1 号服务器,等于2 的就保存到2 好服务器,以此类推,纵向分隔的原则有很多种,可以视情况选择。不过和横向分割数据库一样,纵向分割 数据库也是有代价的,最基本的就是我们在进行如COUNT, SUM 等汇总操作的时候会麻烦很多。综上所述,数据库服务器的解决方案一般视情况往往是一个混合的方案,以其发挥各种方案的优势,有时候还需要借助 memcached 之类的第三方软件,以便适应更大访问量的要求。

如果有专门的应用服务器来跑PHP 脚本是最合适不过的了,那样我们的页面服务器只保存静态页面就可以了,可以给应用服务器设置一些诸如 app.domain.com 之类的域名来和页面服务器加以区别。对于应用服务器,我还是更倾向于使用prefork 模式的apache ,配上必要的 xcache 之类的PHP 缓存软件,加载模块要越少越好,除了mod_rewrite 等必要的模块,不必要的东西统统舍弃,尽量减少httpd 进程的内存消耗,而那些图片服务器,页面服务器等静态内容就可以使用lighttpd 或者tux 来搞,充分发挥各种服务器的特点。

如果条件允许,独立的日志服务器也是必要的,一般小网站的做法都是把页面服务器和日志服务器合二为一了,在凌晨访问量不大的时候cron 运行前一天 的日志计算,不过如果你使用awstats 之类的日志分析软件,对于百万级访问量而言,即使按天归档,也会消耗很多时间和服务器资源去计算,所以分离单独的日志服务器还是有好处的,这样不会影响正式服务器的工作状态。

二:软架构

1 :框架的选择:

现在的PHP 框架有很多选择,比如:CakePHP ,Symfony ,Zend Framework 等等,至于应该使用哪一个并没有唯一的答案,要根据Team 里团队成员对各个框架的了解程度而定。很多时候,即使没有使用框架,一样能写出好的程序来,比如Flickr 据说就是用Pear+Smarty 这样的类库写出来的,所以是否用框架,用什么框架,一般不是最重要,重要的是我们的编程思想里要有框架的意识。

现在的.NET 框架有很多选择,比如:cnForums ,.text ,cs, Castle, 等等

2 :逻辑的分层:

网站规模到了一定的程度之后,代码里各种逻辑纠缠在一起,会给维护和扩展带来巨大的障碍,这时我们的解决方式其实很简单,那就是重构,将逻辑进行分层。通常,自上而下可以分为表现层,应用层,领域层,持久层。

所 谓表现层,并不仅仅就指模板,它的范围要更广一些,所有和表现相关的逻辑都应该被纳入表现层的范畴。比如说某处的字体要显示为红色,某处的开头要空两格, 这些都属于表现层。很多时候,我们容易犯的错误就是把本属于表现层的逻辑放到了其他层面去完成,这里说一个很常见的例子:我们在列表页显示文章标题的时 候,都会设定一个最大字数,一旦标题长度超过了这个限制,就截断,并在后面显示“..” ,这就是最典型的表现层逻辑,但是实际情况,有很多程序员都是在非表现层代码里完成数据的获取和截断,然后赋值给表现层模板,这样的代码最直接的缺点就是同样一段数据,在这个页面我可能想显示前10 个字,再另一个 页面我可能想显示前15 个字,而一旦我们在程序里固化了这个字数,也就丧失了可移植性。正确的做法是应该做一个视图助手之类的程序来专门处理此类逻辑,比如说:Smarty 里的truncate 就属于这样的视图助手(不过它那个实现不适合中文)。

所谓应用层,它的主要作用是定义用户可以做什么,并把操作结果反馈给表现层。至于如何做,通常不是它的职责范围(而是领域层的职责范围),它会通过委派把如何做的工作交给领域层去处理。在使用MVC 架构的网站中,我们可以看到类似下面这样的URL :domain.com/articles/view/123 ,其内部编码实现,一般就是一个Articles 控制器类,里面有一个view 方法,这就是一 个典型的应用层操作,因为它定义了用户可以做一个查看的动作。在MVC 架构中,有一个准则是这么说的:Rich Model Is Good 。言外之意,就是Controller 要保持“ 瘦” 一些比较好,进而说明应用层要尽量简单,不要包括涉及领域内容的逻辑。

所谓领域层,最直接的解释就是包含领域逻辑的层。它是一个软件的灵魂所在。先来看看什么叫领域逻辑,简单的说,具有明确的领域概念的逻辑就是领域逻辑,比如我们在ATM 机上取钱,过程大致是这样的:插入银联卡,输入密码,输入取款金额,确定,拿钱,然后ATM 吐出一个交易凭条。在这个过程中,银联卡 在ATM 机器里完成钱从帐户上划拨的过程就是一个领域逻辑,因为取钱在银行中是一个明确的领域概念,而ATM 机吐出一个交易凭条则不是领域逻辑,而仅是一 个应用逻辑,因为吐出交易凭条并不是银行中一个明确的领域概念,只是一种技术手段,对应的,我们取钱后不吐交易凭条,而发送一条提醒短信也是可能的,但并 不是一定如此,如果在实际情况中,我们要求取款后必须吐出交易凭条,也就是说吐出交易凭条已经和取款紧密结合,那么你也可以把吐出交易凭条看作是领域逻辑 的一部分,一切都以问题的具体情况而定。在Eric 那本经典的领域驱动设计中,把领域层分为了五种基本元素:实体,值对象,服务,工厂,仓储。具体可以参 阅书中的介绍。领域层最常犯的错误就是把本应属于领域层的逻辑泄露到了其他层次,比如说在一个CMS 系统,对热门文章的定义是这样的:每天被浏览的次数多 于1000 次,被评论的次数多于100 次,这样的文章就是热门文章。对于一个CMS 来说,热门文章这个词无疑是一个重要的领域概念,那么我们如何实现这个逻辑的设计的?你可能会给出类似下面的代码:“SELECT ... FROM ... WHERE  浏览 > 1000 AND  评论 > 100” ,没错,这是最简单的实现方式,但是这里需要注意的是“ 每天被浏览的次数多于1000 次,被评论的次数多于100 次” 这个重要的领域逻辑被隐藏到了SQL 语句中,SQL 语句显然不属于领域层的范畴,也就是说,我们的领域逻辑泄露了。

所谓持久层,就是指把我们的领域模型保存到数据库中。因为我们的程序代码是面向对象风格的,而数据库一般是关系型的数据库,所以我们需要把领域模型 碾平,才能保存到数据库中,但是在 PHP 里,直到目前还没有非常好的 ORM 出现,所以这方面的解决方案不是特别多,参考 Martin 的企业应用架构模式一   书,大致可以使用的方法有行数据入口( Row Data Gateway )或者表数据入口( Table Data Gateway),或者把领域层和持久层合二为一变成活动记录(Active Record)的方式。

posted @ 2010-08-11 14:32 存鹰之心于高远,取鹰之志而凌云,习鹰之性以涉险,融鹰之神在山巅. 阅读(401) | 评论 (0)编辑 收藏

TOMCAT崩溃事件

http://www.blogjava.net/tedeyang/archive/2008/06/04/205740.html

今天一大早产品一部项目经理就来找我,他们的一台服务器昨天晚上tomcat服务崩溃,还不能重启服务,最后将服务器重启才OK。
我将事件过程和分析过程记录如下:

服务器:win 2000 sp4,apache 2 + tomcat 5.0 采用mod_jk级联。内存2G,硬盘剩余空间充足,CPU基本空闲。
主要应用:J2EE 1.4,JDBC(连接另一台mysql服务器)
崩溃时间: 2008-6-3 18:37:50

一.各种日志综合如下:

   1.37分45秒,操作系统事件中诺顿杀毒软件报内存过低警报
   2.37分45秒,web应用抛出JDBC连接异常:

2008-06-03 18:37:45 cn.*.db.DBManager.getConnection(DBManager.java:157) ERROR swim.db.DBManager   com.mysql.jdbc.CommunicationsException: Communications link failure due to underlying exception:
** BEGIN NESTED EXCEPTION **
java.net.SocketException
MESSAGE: java.net.SocketException: No buffer 
space available (maximum connections reached?): JVM_Bind


   3.37分50秒,tomcat抛出session无法save异常:

2008-06-03 18:37:50 ERROR- IOException while saving persisted sessions: java.io.FileNotFoundException: "izzs"SESSIONS.ser (系统资源不足,无法完成请求的服务。)
java.io.FileNotFoundException: "izzs"SESSIONS.ser (系统资源不足,无法完成请求的服务。)
    at java.io.FileOutputStream.open(Native Method)
    at java.io.FileOutputStream.
<init>(FileOutputStream.java:179)
    at java.io.FileOutputStream.
<init>(FileOutputStream.java:70)
    at org.apache.catalina.session.StandardManager.doUnload(StandardManager.java:
511)
    at org.apache.catalina.session.StandardManager.unload(StandardManager.java:
485)
    at org.apache.catalina.session.StandardManager.stop(StandardManager.java:
687)
    at org.apache.catalina.core.StandardContext.stop(StandardContext.java:
4496)
    at org.apache.catalina.core.StandardContext.reload(StandardContext.java:
3037)
    at org.apache.catalina.core.StandardContext.backgroundProcess(StandardContext.java:
4658)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:
1619)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:
1628)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:
1628)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:
1608)
    at java.lang.Thread.run(Thread.java:
534)


 

二.简单分析

崩溃原因:内存不足导致资源不足,引起Tomcat的session崩溃。
  这台服务器上运行着很多应用,是什么原因引起内存不足还无法确定。
初步判断罪魁祸首可能是apache,该进程平常占用500MB内存,经常会飚到1G以上。

Apache2的配置文件中:KeepAlive=On,MaxKeepAliveRequests=100,KeepAliveTimeout=15,分析aceess.log文件可以发现每个页面触发的request数量在10个以下,点击率较低,可能使连接过多。
我建议将keepAlive设为off,增加CPU负载,降低内存消耗。

三.效果

 有待观察......

参考资料:
http://www.withend.com/post/78.html

四.结局 
时隔一天,晚上九点再次崩溃,黑暗事件重演。
这一次,我才得知原来该apache还配置有其他域名,于是调出该域名下的access.log。项目经理去了机房,在轰轰地风扇声中打电话给我,让我分析分析。
仔细看访问日志,发现原来有N多Connect 443连接,443是什么?是SSL端口!HTTPS!,Connect命令则显然是代理功能!
而且这些connect的IP来自全球各地,加拿大、美国、澳洲、新西兰、北京、上海、英国、哪都有。
看来这台服务器是被人当代理服务器用了。
怪不得半夜会死机,人家西半球那时正大白天撒欢儿呢。

问题就出在apache的配置上,由于应用众多,并且这台服务器还是其他几台web服务器的对外出口,因此apache中配置了反向代理,不过不小心把正向代理(mod_proxy模块的ProxyRequests指令)也打开了。
看看apache2.0的官方文档中mod_proxy部分,里面明明白白写着:

警告
在您没有对服务器采取安全措施之前,请不要用ProxyRequests启用您的代理。一个开放的代理服务器不仅对您的网络有威胁,对整个因特网来说也同样如此。
真的是很有威胁!大量代理请求急剧消耗内存,最终造成死机!

解决办法就是把正向代理关掉:ProxyRequests Off
posted @ 2010-08-11 14:25 存鹰之心于高远,取鹰之志而凌云,习鹰之性以涉险,融鹰之神在山巅. 阅读(2011) | 评论 (0)编辑 收藏

分布式缓存系统Memcached简介与实践

http://blog.csdn.net/hitman9099/archive/2008/09/04/2878417.aspx

 

缘起: 在数据驱动的web开发中,经常要重复从数据库中取出相同的数据,这种重复极大的增加了数据库负载。缓存是解决这个问题的好办法。但是ASP.NET中的虽然已经可以实现对页面局部进行缓存,但还是不够灵活。此时Memcached或许是你想要的。

Memcached是什么?
Memcached是由Danga Interactive开发的,高性能的,分布式的内存对象缓存系统,用于在动态应用中减少数据库负载,提升访问速度。

Memcached能缓存什么?
通过在内存里维护一个统一的巨大的hash表,Memcached能够用来存储各种格式的数据,包括图像、视频、文件以及数据库检索的结果等。

Memcached快么?

非 常快。Memcached使用了libevent(如果可以的话,在linux下使用epoll)来均衡任何数量的打开链接,使用非阻塞的网络I/O,对 内部对象实现引用计数(因此,针对多样的客户端,对象可以处在多样的状态), 使用自己的页块分配器和哈希表, 因此虚拟内存不会产生碎片并且虚拟内存分配的时间复杂度可以保证为O(1).。

Danga Interactive为提升Danga Interactive的速度研发了Memcached。目前,LiveJournal.com每天已经在向一百万用户提供多达两千万次的页面访问。而这 些,是由一个由web服务器和数据库服务器组成的集群完成的。Memcached几乎完全放弃了任何数据都从数据库读取的方式,同时,它还缩短了用户查看 页面的速度、更好的资源分配方式,以及Memcache失效时对数据库的访问速度。

Memcached的特点
Memcached的缓存是一种分布式的,可以让不同主机上的多个用户同时访问, 因此解决了共享内存只能单机应用的局限,更不会出现使用数据库做类似事情的时候,磁盘开销和阻塞的发生。

Memcached的使用 
 
Memcached服务器端的安装 (此处将其作为系统服务安装)
下载文件:memcached 1.2.1 for Win32 binaries (Dec 23, 2006)
    1 解压缩文件到c:\memcached
   2 命令行输入 'c:\memcached\memcached.exe -d install' 
    3 命令行输入 'c:\memcached\memcached.exe -d start' ,该命令启动 Memcached ,默认监听端口为 11211
通过 memcached.exe -h 可以查看其帮助

 

一个简单的测试例子

  1. package com.mapbar.util.cache;

  2. import java.util.Date;
  3. import java.util.ResourceBundle;

  4. import com.danga.MemCached.MemCachedClient;
  5. import com.danga.MemCached.SockIOPool;
  6. /**
  7.  * 使用配置文件方式的memcache组件
  8.  *
  9.  */
  10. public class Cache {

  11.  protected static ResourceBundle rb=ResourceBundle.getBundle("memcached");;
  12.  public static MemCachedClient mcc = new MemCachedClient(); 
  13.  static {
  14.   init();
  15.  }     
  16.  public static void init(){
  17.   synchronized (mcc) {  
  18.    System.out.println("init call");
  19.    String[] servers =rb.getString("cache.servers").split(",");       
  20.          
  21.          String[] strWeights =rb.getString("cache.weights").split(",");  
  22.          Integer[] weights = new Integer[strWeights.length];
  23.          for(int i=0;i<strWeights.length;i++){
  24.           weights[i]=Integer.parseInt(strWeights[i]);
  25.          }
  26.         
  27.          //创建一个实例对象SockIOPool     
  28.          SockIOPool pool = SockIOPool.getInstance();       
  29.         
  30.          // set the servers and the weights    
  31.          //设置Memcached Server    
  32.          pool.setServers( servers );       
  33.          pool.setWeights( weights );       
  34.          pool.setInitConn(Integer.parseInt(rb.getString("cache.initConn")));       
  35.          pool.setMinConn(Integer.parseInt(rb.getString("cache.minConn")));       
  36.          pool.setMaxConn(Integer.parseInt(rb.getString("cache.maxConn")));       
  37.          pool.setMaxIdle(Long.parseLong(rb.getString("cache.maxIdle")));       
  38.         
  39.          // set the sleep for the maint thread       
  40.          // it will wake up every x seconds and       
  41.          // maintain the pool size       
  42.          pool.setMaintSleep( 30 );       
  43.         
  44. //         Tcp的规则就是在发送一个包之前,本地机器会等待远程主机    
  45. //         对上一次发送的包的确认信息到来;这个方法就可以关闭套接字的缓存,    
  46. //         以至这个包准备好了就发;    
  47.          pool.setNagle( false );       
  48.          //连接建立后对超时的控制    
  49.          pool.setSocketTO( 3000 );    
  50.          //连接建立时对超时的控制    
  51.          pool.setSocketConnectTO( 0 );       
  52.         
  53.          // initialize the connection pool       
  54.          //初始化一些值并与MemcachedServer段建立连接    
  55.          pool.initialize();    

  56.          // lets set some compression on for the client       
  57.          // compress anything larger than 64k       
  58.          mcc.setCompressEnable( true );       
  59.          mcc.setCompressThreshold( 64 * 1024 );  
  60.   }
  61.  }
  62.  protected static void bulidCache(){  
  63.   
  64.         //set(key,value,Date) ,Date是一个过期时间,如果想让这个过期时间生效的话,这里传递的new Date(long date) 中参数date,需要是个大于或等于1000的值。    
  65.         //因为java client的实现源码里是这样实现的 expiry.getTime() / 1000 ,也就是说,如果 小于1000的值,除以1000以后都是0,即永不过期    
  66.         mcc.set( "test""This is a test String" ,new Date(100000));   //十秒后过期    
  67.               
  68.     }       
  69.       
  70.  protected static void output() {       
  71.         //从cache里取值    
  72.         String value = (String) mcc.get( "test" );       
  73.         System.out.println(value);        
  74.     }       
  75.            
  76.  public static void main(String[] args){       
  77.         bulidCache();      
  78.         output();           
  79.     }        

  80. }


其中在classespath下有个memcached.properties文件

内容如下:

##muti servers spilt by ,

#这里是你的memcached启动的地址
cache.servers=192.168.0.116:11211  
cache.weights=1
#memcached be used
cache.cluster=true

#set some basic pool settings       
#5 initial, 5 min, and 250 max conns       
#and set the max idle time for a conn       
#to 6 hours  6*60*60*1000
cache.initConn=5
cache.minConn=5
cache.maxConn=250
cache.maxIdle=21600000

 

 

 

 

在Windows下安装Memcached

http://www.oschina.net/docs/article/4

很多phper不知道如何在Windows下搭建Memcache的开发调试环境,最近个人也在研究Memcache,记录下自己安装搭建的过程。
其实我开始研究Memcache的时候并不知道居然还有memcached for Win32这个鸟东西,害得我在CnetOS下折腾1天才搞定,今天突然发现Windows下的Memcache进行开发调试完全没有问题,所以写篇 Memcache的文档分享给大家。

Windows下的Memcache安装
1. 下载memcache的 windows稳定版,解压放某个盘下面,比如在c:\memcached
2. 在终端(也即cmd命令界面)下输入 ‘c:\memcached\memcached.exe -d install’ 安装
3. 再输入: ‘c:\memcached\memcached.exe -d start’ 启动。NOTE: 以后memcached将作为windows的一个服务每次开机时自动启动。这样服务器端已经安装完毕了。
4.下载php_memcache.dll, 请自己查找对应的php版本的文件
5. 在C:\winnt\php.ini 加入一行 ‘extension=php_memcache.dll’
6.重新启动Apache,然后查看一下phpinfo,如果有memcache,那么就说明安装成功!

memcached的基本设置

-p 监听的端口
-l 连接的IP地址, 默认是本机
-d start 启动memcached服务
-d restart 重起memcached服务
-d stop|shutdown 关闭正在运行的memcached服务
-d install 安装memcached服务
-d uninstall 卸载memcached服务
-u 以的身份运行 (仅在以root运行的时候有效)
-m 最大内存使用,单位MB。默认64MB
-M 内存耗尽时返回错误,而不是删除项
-c 最大同时连接数,默认是1024
-f 块大小增长因子,默认是1.25
-n 最小分配空间,key+value+flags默认是48
-h 显示帮助

Memcache环境测试
运行下面的php文件,如果有输出This is a test!,就表示环境搭建成功。开始领略Memcache的魅力把!
< ?php
$mem = new Memcache;
$mem->connect(”127.0.0.1″, 11211);
$mem->set(’key’, ‘This is a test!’, 0, 60);
$val = $mem->get(’key’);
echo $val;
?>

posted @ 2010-08-11 14:22 存鹰之心于高远,取鹰之志而凌云,习鹰之性以涉险,融鹰之神在山巅. 阅读(451) | 评论 (0)编辑 收藏

日志原文:http://j2ee.blog.sohu.com/70343632.html   
memcache for win 软件主页:http://jehiah.cz/projects/memcached-win32/  
http://labs.northscale.com/memcached-packages/
meecache for liunx 软件主页:http://memcached.org/  
                                     
最近一直在做一个项目的前期设计工作,考虑到后期系统的扩展和性能问题也找了很多解决方法,有一个就是用到了数据库的缓存工具memcached(当然该工具并不仅仅局限于数据库的缓存)。先简单的介绍下什么是memcached。

    Memcached是高性能的,分布式的内存对象缓存系统,用于在动态应用中减少数据库负 载,提升访问速度。Memcached由Danga Interactive开发,用于提升LiveJournal.com访问速度的。LJ每秒动态页面访问量几千次,用户700万。Memcached将数 据库负载大幅度降低,更好的分配资源,更快速访问。

    上网baidu了很多东西,几乎都差不多,而且基于java的说的很少,所有只有在研究了各个其他语言类的应用后再来尝试在java上进行简单的操作应 用。先从memcached上进行说明,memcached的最新版是采用c语言进行开发和设计的,据说旧版的是采用perl语言开发的,而且它是一个应 用软件来的,是作为缓存服务器的服务器端运行在服务器上的,需要使用特定的语言编写客户端与其进行通信来进行数据的缓存和获取。通常我们是把 memcached安装运行在web服务器上,然后通过对需要的数据进行缓存,据我目前所知,所有数据的缓存设置和存取操作,以及数据的更新后替换操作全 部需要程序来进行,而不是自动进行的(自动不知道能不能成功,呵呵)。下面从一个实际的例子来应用memcached。

    首先到http://danga.com/memcached/下 载memcached的windows版本和java客户端jar包,目前最新版本是memcached-1.2.1-win32.zip和 java_memcached-release_1.6.zip,分别解压后即可!首先是安装运行memcached服务器,我们将memcached- 1.2.1-win32.zip解压后,进入其目录,然后运行如下命令:

c:>memcached.exe -d install
c:>memcached.exe -l 127.0.0.1 -m 32 -d start

    第一行是安装memcached成为服务,这样才能正常运行,否则运行失败!第一行是启动memcached的,作为测试我们就简单的只分配32M内存 了,然后监听本机端口和以守护进行运行。执行完毕后,我们就可以在任务管理器中见到memcached.exe这个进程了。好了,我们的服务器已经正常运 行了, 下面我们就来写java的客户端连接程序。

    我们将java_memcached-release_1.6.zip解压后的目录中的java_memcached-release_1.6.jar文件复制到java项目的lib目录下,然后我们来编写代码,比如我提供的一个应用类如下:

package utils.cache;

import java.util.Date;

import com.danga.MemCached.MemCachedClient;
import com.danga.MemCached.SockIOPool;


/**
* 使用memcached的缓存实用类.
*
*
@author 铁木箱子
*
*/
public class MemCached
{
   
// 创建全局的唯一实例
    protected static MemCachedClient mcc = new MemCachedClient();
   
   
protected static MemCached memCached = new MemCached();
   
   
// 设置与缓存服务器的连接池
    static {
       
// 服务器列表和其权重
        String[] servers = {"127.0.0.1:11211"};
        Integer[] weights
= {3};

       
// 获取socke连接池的实例对象
        SockIOPool pool = SockIOPool.getInstance();

       
// 设置服务器信息
        pool.setServers( servers );
        pool.setWeights( weights );

       
// 设置初始连接数、最小和最大连接数以及最大处理时间
        pool.setInitConn( 5 );
        pool.setMinConn(
5 );
        pool.setMaxConn(
250 );
        pool.setMaxIdle(
1000 * 60 * 60 * 6 );

       
// 设置主线程的睡眠时间
        pool.setMaintSleep( 30 );

       
// 设置TCP的参数,连接超时等
        pool.setNagle( false );
        pool.setSocketTO(
3000 );
        pool.setSocketConnectTO(
0 );

       
// 初始化连接池
        pool.initialize();

       
// 压缩设置,超过指定大小(单位为K)的数据都会被压缩
        mcc.setCompressEnable( true );
        mcc.setCompressThreshold(
64 * 1024 );
    }
   
   
/**
     * 保护型构造方法,不允许实例化!
     *
    
*/
   
protected MemCached()
    {
       
    }
   
   
/**
     * 获取唯一实例.
     *
@return
    
*/
   
public static MemCached getInstance()
    {
       
return memCached;
    }
   
   
/**
     * 添加一个指定的值到缓存中.
     *
@param key
     *
@param value
     *
@return
    
*/
   
public boolean add(String key, Object value)
    {
       
return mcc.add(key, value);
    }
   
   
public boolean add(String key, Object value, Date expiry)
    {
       
return mcc.add(key, value, expiry);
    }
   
   
public boolean replace(String key, Object value)
    {
       
return mcc.replace(key, value);
    }
   
   
public boolean replace(String key, Object value, Date expiry)
    {
       
return mcc.replace(key, value, expiry);
    }
   
   
/**
     * 根据指定的关键字获取对象.
     *
@param key
     *
@return
    
*/
   
public Object get(String key)
    {
       
return mcc.get(key);
    }
   
   
public static void main(String[] args)
    {
        MemCached cache
= MemCached.getInstance();
        cache.add(
"hello", 234);
        System.out.print(
"get value : " + cache.get("hello"));
    }
}

    那么我们就可以通过简单的像main方法中操作的一样存入一个变量,然后再取出进行查看,我们可以看到先调用了add,然后再进行get,我们运行一次 后,234这个值已经被我们存入了memcached的缓存中的了,我们将main方法中红色的那一行注释掉后,我们再运行还是可以看到get到的 value也是234,即缓存中我们已经存在了数据了。

    对基本的数据我们可以操作,对于普通的POJO而言,如果要进行存储的话,那么比如让其实现java.io.Serializable接口,因为 memcached是一个分布式的缓存服务器,多台服务器间进行数据共享需要将对象序列化的,所以必须实现该接口,否则会报错的。比如我们写一个简单的测 试Bean如下:

class TBean implements java.io.Serializable
{
   
private static final long serialVersionUID = 1945562032261336919L;
   
   
private String name;

   
public String getName()
    {
       
return name;
    }

   
public void setName(String name)
    {
       
this.name = name;
    }
}

    然后我们在main方法中加入如下几行代码:

TBean tb = new TBean();
tb.setName(
"铁木箱子");
cache.add(
"bean", tb);
TBean tb1
= (TBean)cache.get("bean");
System.out.print(
"name=" + tb1.getName());
tb1.setName(
"铁木箱子_修改的");
tb1
= (TBean)cache.get("bean");
System.out.print(
"name=" + tb1.getName());

    我们首先把TBean的一个实例放入缓存中,然后再取出来,并进行名称的修改,然后我们再取这个对象,我们再看其名称,发现修改的对象并不是缓存中的对 象,而是通过序列化过来的一个实例对象,这样我们就无须担心对原生类的无意修改导致缓存数据失效了,呵呵~~看来我也是多此一想啊。所以这表明从缓存中获 取的对象是存入对象的一个副本,对获取对象的修改并不能真正的修改缓存中的数据,而应该使用其提供的replace等方法来进行修改。

    以上是我在windows下对memcached的一点小学习和实践,在以后的项目开发过程中将会更深入的学习和应用这一缓存工具,也希望和有兴趣的同行一起讨论学习该工具的使用~~ 微笑


posted @ 2010-08-11 13:51 存鹰之心于高远,取鹰之志而凌云,习鹰之性以涉险,融鹰之神在山巅. 阅读(745) | 评论 (0)编辑 收藏

转载:http://www.blogjava.net/cnfree/archive/2008/06/12/207343.html

最近的项目需要使用报表,因为是RCP应用,所以选择了Birt,用了一下,感觉还可以,就是网上资料少了点,不过以前也研究过一些Eclipse相关技术,这些都不重要了,找了SDK版本Debug,啥研究不出来?

BIRT是一个Eclipse-based开放源代码报表系统。它主要是用在基于Java与J2EE的Web应用程序上。BIRT主要由两部分组成:一个是基于Eclipse的报表设计和一个可以加到你应用服务的运行期组件。BIRT同时也提供一个图形报表制作引擎。

官方主页:http://www.eclipse.org/birt
官方BBS支持:http://www.actuatechina.com/forum2.html

基本上来说Birt功能还是很强大的,支持时下比较流行的WebService,Ajax技术,既可用于Web,也可以用于桌面,更新也算稳定,基本上遵循Eclipse的开发步骤,一个一个大版本,同时支持脚本调用,debug开发等等。唯一不足的就是中国的国情支持得还不够完善,毕竟中国比较特殊,我以前给公司做党务报表,要按照纸质报表画,一分一毫都不能变差,那个变态呀,在电脑上画报表还是拿尺子量。

刚刚开始用,慢慢研究,看了下Birt自带的Example,的确是很强大,做得也很漂亮,自己试着创建一个报表也很简单,希望能够比较快的上手吧。

在网上找了一些资源:
http://blogger.org.cn/blog/more.asp?name=sixsun&id=13933 BIRT 中文指南
http://www.springside.org.cn/docs/reference/Birt.htm BIRT报表
http://www-128.ibm.com/developerworks/cn/opensource/os-ecl-birt/ Birt的IBM DW的中文教程
http://download.eclipse.org/birt/downloads/demos/FirstReport/MyFirstReport.html Birt Flash Demo.
posted @ 2009-02-02 09:31 存鹰之心于高远,取鹰之志而凌云,习鹰之性以涉险,融鹰之神在山巅. 阅读(358) | 评论 (0)编辑 收藏

 

我们公司为每一个新进来的员工指派了一个导师。这让我想起了原来听过的微软培训,现简单的归纳了几条,放上来供大家讨论。

1、首先微软的导师选择不是领导行政上指定的,而是学生选择导师。
    在这里微软强调的是:牛人才能成为导师。公司的人力资源系统有一模块会把导师的特长列出来,以及原来被选择为导师的次数,还有历界学生对其的评价。

    如果是新员工的话,基础的流程常识之类的有培训,具体到某一方面的技术的话,可以由你的上级指导你选择。

2、不是新人才能选择导师,当你换岗,换项目,反正对某个领域是新的时候,都可以选择导师

3、导师不会天天指导你,帮助你制定培训计划。因为导师的时间比你的时间宝贵的多

方法是:

   1)学习、提高等等的计划由你自己来完成。

   2)导师可以在邮件上花几分钟给你指导一下。

   3)导师可以在某个有空地时间找你谈谈(或你约导师),但多是你请导师吃饭的时候。这样饭也吃了,导师也当了。

4、(注意是大点)导师指导你,对他是有好处的......

   1)提高影响力(微软最注意的一点) 

   2)有了影响为,才有绩效吧。

   3)有了影响力,以后的新人才会选择你吧,以后的新人选择你的越多,多到你的档期安排不过来,这才更牛吧!

 

5、这对企业文化也有好处。

  1)文化影响共享,比强制,指派更有效些。 

  2)对新人、旧人都好,不会出现你有难,十方都会,但都不支援你的情况

  3)不会出现研究成果,只保存在某个人的头脑里的情况。节省资源

    特别说明:这种考核对导师不考核。因为是他导的作用,不是师的作用。师的考核是看他被选择的次数,学生对他的评价。这更客观,真实。

posted @ 2009-01-15 23:23 存鹰之心于高远,取鹰之志而凌云,习鹰之性以涉险,融鹰之神在山巅. 阅读(1426) | 评论 (0)编辑 收藏

JAVA中,有六个不同的地方可以存储数据:
1. 寄存器(register)。这是最快的存储区,因为它位于不同于其他存储区的地方——处理器内部。但是寄存器的数量极其有限,所以寄存器由编译器根据需求进行分配。你不能直接控制,也不能在程序中感觉到寄存器存在的任何迹象。
2. 堆栈(stack)。位于通用RAM中,但通过它的“堆栈指针”可以从处理器哪里获得支持。堆栈指针若向下移动,则分配新的内存;若向上移动,则释放那些内存。这是一种快速有效的分配存储方法,仅次于寄存器。创建程序时候,JAVA编译器必须知道存储在堆栈内所有数据的确切大小和生命周期,因为它必须生成相应的代码,以便上下移动堆栈指针。这一约束限制了程序的灵活性,所以虽然某些JAVA数据存储在堆栈中——特别是对象引用,但是JAVA对象不存储其中。
3. 堆(heap)。一种通用性的内存池(也存在于RAM中),用于存放所以的JAVA对 象。堆不同于堆栈的好处是:编译器不需要知道要从堆里分配多少存储区域,也不必知道存储的数据在堆里存活多长时间。因此,在堆里分配存储有很大的灵活性。 当你需要创建一个对象的时候,只需要new写一行简单的代码,当执行这行代码时,会自动在堆里进行存储分配。当然,为这种灵活性必须要付出相应的代码。用 堆进行存储分配比用堆栈进行存储存储需要更多的时间。
4. 静态存储(static storage)。这里的“静态”是指“在固定的位置”。静态存储里存放程序运行时一直存在的数据。你可用关键字static来标识一个对象的特定元素是静态的,但JAVA对象本身从来不会存放在静态存储空间里。
5. 常量存储(constant storage)。常量值通常直接存放在程序代码内部,这样做是安全的,因为它们永远不会被改变。有时,在嵌入式系统中,常量本身会和其他部分分割离开,所以在这种情况下,可以选择将其放在ROM中
6. 非RAM存储。如果数据完全存活于程序之外,那么它可以不受程序的任何控制,在程序没有运行时也可以存在。
就速度来说,有如下关系:
    寄存器 < 堆栈 < 堆 < 其他

『上面这段话摘取之《Thinking in Java》』

在这里,主要要说下堆与堆栈的关系:

      堆:堆是heap,是所谓的动态内存,其中的内存在不需要时可以回收,以分配给新的内存请求,其内存中的数据是无序的,即先分配的和随后分配的内存并没有 什么必然的位置关系,释放时也可以没有先后顺序。一般由使用者自由分配,malloc分配的就是堆,需要手动释放。

      堆栈:就是STACK。实际上是只有一个出入口的队列,即后进先出(First     In     Last     Out),先分配的内存必定后释放。一般由,由系统自动分配,存放存放函数的参数值,局部变量等,自动清除。

还有,堆是全局的,堆栈是每个函数进入的时候分一小块,函数返回的时候就释放了,静态和全局变量,new     得到的变量,都放在堆中,局部变量放在堆栈中,所以函数返回,局部变量就全没了。

其实在实际应用中,堆栈多用来存储方法的调用。而对则用于对象的存储。

       JAVA中的基本类型,其实需要特殊对待。因为,在JAVA中,通过new创建的对象存储在“堆”中,所以用new 创建一个小的、简单的变量,如基本类型等,往往不是很有效。因此,在JAVA中,对于这些类型,采用了与C、C++相同的方法。也就是说,不用new 来创建,而是创建一个并非是“引用”的“自动”变量。这个变量拥有它的“值”,并置于堆栈中,因此更高效。
posted @ 2008-11-16 00:57 存鹰之心于高远,取鹰之志而凌云,习鹰之性以涉险,融鹰之神在山巅. 阅读(1374) | 评论 (0)编辑 收藏

前面讲了用tomcat+axis来实现webservice,而网上对于weblogic+axis实现webservice却不多,按照网上说的做却总是报错,不成功,所以我经过不停的试验,终于配置成功了weblogic+axis

首先我们下载一个weblogic8.1.3,jdk和axis的下载参照Tomcat+axis那片文章里的下载安装和设置

下载好后我们安装weblogic,一直按下一步即可

安装完成后运行Configuration Wizard来新建域配置,一直按下一步,直到输入UserName,Password and Description(我们这里都设置成weblogic),然后在按下一步直到完成

然后我们将下载的axis压缩包下的webapp目录下的axis目录拷贝到C:\bea\user_projects\domains\mydomain\applications下面

由于axis中的一些jar包和weblogic中的有冲突,所以要修改C:\bea\user_projects\domains\mydomain\startWebLogic.cmd文件,优先使用axis的jar,将其中的
set CLASSPATH=%WEBLOGIC_CLASSPATH%;%POINTBASE_CLASSPATH%;%JAVA_HOME%\jre\lib\rt.jar;%CLASSPATH%;%WL_HOME%\server\lib\webservices.jar
改成
set CLASSPATH=%AXISCLASSPATH%;%WEBLOGIC_CLASSPATH%;%POINTBASE_CLASSPATH%;%JAVA_HOME%\jre\lib\rt.jar;%WL_HOME%\server\lib\webservices.jar

set CLASSPATH=%CLASSPATH%;%WEBLOGIC_CLASSPATH%;%POINTBASE_CLASSPATH%;%JAVA_HOME%\jre \lib\rt.jar;%WL_HOME%\server\lib\webservices.jar(这里必须保证将AXISCLASSPATH加入了 CLASSPATH环境变量中)
保存运行这个文件启动weblogic控制台,如下图
查看更多精彩图片

启动好之后打开ie,在url中输入http://localhost:7001/console,输入用户名和密码进入Weblogic Server Console
查看更多精彩图片

点击展开部署节点--点击WEB应用程序模块--然后点击旁边的部署新的新的应用程序模块,会出现选择web应用的窗口,如下图
查看更多精彩图片

选择相应目录下的web应用程序,我们选择axis,如下图
查看更多精彩图片

点击目标模块按钮,接着在出现的窗口中点击部署即可(这里我发现如果不在环境变量CLASSPATH中设置%AXISCLASSPATH%时,部署将报错)完成后如下图
查看更多精彩图片

这是我们可以点击测试选项中的链接,也可以在ie中输入http://localhost:7001/axis/,如果出现以下界面,说明配置成功
查看更多精彩图片

这时我们就可以按照tomcat+axis那篇文章所说的发布web服务了

遇到的问题
weblogic+axis的最大问题是2者间jar包的冲突,客户端调用web服务时会报 NullPointerException错误,网上都说是axis的saaj.jar和weblogic的webservices.jar冲突,须将 saaj.jar加在webservices.jar前面,我按网上这么加了也没用,后来我把整个AXISCLASSPATH都加到了最前面,就如我上面 所说的那样,嘿,他就好了,我晕俄,网上的人也不知道是怎么成功的

还有一种说法就是在web-inf目录下加weblogic.xml,网上的人也没说要加到哪个web-inf下,我想想只有我的axis目录下有web-inf吧,就加他下面了,weblogic.xml的内容如下
<!DOCTYPE weblogic-web-app PUBLIC "-//BEA Systems, Inc.//DTD Web Application 8.1//EN" "http://www.bea.com/servers/wls810/dtd/weblogic810-web-jar.dtd">
<weblogic-web-app>
 <container-descriptor>
  <prefer-web-inf-classes>true</prefer-web-inf-classes>
 </container-descriptor>
</weblogic-web-app>
这 样也可以解决客户端调用web服务时会报NullPointerException的错误,但是我发现这样做的后果是点击axis的service的 wsdl时出现无法显示页面。所以经过我不断的调试,只有像我前面说的那样修改startWebLogic.cmd中的set CLASSPATH项应该算是最完美的方法了,配这个东西的时候网上查了好久,都是千篇一律,说得没头没尾,所以说还是得自己去实践阿(实践是检验真理的 唯一标准嘛0 && image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" alt="" align="absmiddle" border="0">)

注:在部署好的web应用程序的web-inf中加入weblogic.xml需要重新部署web应用程序
        修改了startWebLogic.cmd需重新执行startWebLogic.cmd,以便修改起作用

我在一个干净的winxp sp2,JDK1.4.2.05,weblogic8.1.3的环境下部署了axis1.4,和同事在家远程调用获得成功

相关程序安装目录
JDK        C:\j2sdk1.4.2_05
weblogic  C:\bea
axis1.4     C:\axis14(lib下有一些jar需另外当,老实说我也不知道哪些起了作用,只是把网上所说得涉及到的jar都找来了,嘿嘿)

相关环境变量设置
AXIS_HOME=C:\axis14
AXIS_LIB=%AXIS_HOME%\lib
AXISCLASSPATH=%AXIS_LIB%\axis.jar;%AXIS_LIB%\commons-discovery-0.2.jar;%AXIS_LIB%\commons-logging-1.0.4.jar;%AXIS_LIB%\jaxrpc.jar;%AXIS_LIB%\saaj.jar;%AXIS_LIB%\log4j-1.2.8.jar;%AXIS_LIB%\xml-apis.jar;%AXIS_LIB%\xercesImpl.jar;%AXIS_LIB%\wsdl4j-1.5.1.jar;%AXIS_LIB%\activation.jar;%AXIS_LIB%\xmlrpc-2.0.jar

JAVA_HOME=C:\j2sdk1.4.2_05
CLASSPATH=.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;%AXISCLASSPATH%;

Path前加了%JAVA_HOME%\bin

posted @ 2008-11-13 00:35 存鹰之心于高远,取鹰之志而凌云,习鹰之性以涉险,融鹰之神在山巅. 阅读(6893) | 评论 (1)编辑 收藏

根 据网上搜索到的一些例子做的时候碰到了挺多的问题,经过不懈的努力终于完成了这个webservice的例子,实际上axis的文档上也写了一个例子,网 上的例子也大多都是照他上面所写的那样,只是有些讲的不算很详细,所以产生了不少错误,小弟知识浅薄,如有写的不清楚地地方,还请见谅

所需软件
tomcat        :http://tomcat.apache.org/index.html
axis          :http://ws.apache.org/axis/
jdk           :http://java.sun.com/javase/downloads/index.jsp
jaf           :http://java.sun.com/products/javabeans/jaf/downloads/index.html
xmlrpc        :http://ws.apache.org/xmlrpc

XML解析器
Xalan         :http://archive.apache.org/dist/xml/xalan-j/
Xerces        :http://xml.apache.org/dist/xerces-j/

本例讲解axis定制发布

本实例采用
j2sdk1.4.2_05,tomcat5.0.28,axis1.4,jbuilder X / Eclipse3.2

首先将axis解压至相应目录,如d:\下,安装tomcat至c:\tomcat5,安装jdk至c:\ j2sdk1.4.2_05
然后将d:\axis\webapp目录下的axis目录copy至c:\tomcat5\webapps目录下

设置axis的环境变量

AXIS_HOME=d:\axis

AXIS_LIB=%AXIS_HOME%\lib

AXISCLASSPATH=%AXIS_LIB%\axis.jar;%AXIS_LIB%\commons-discovery-0.2.jar;%AXIS_LIB%\commons-logging-1.0.4.jar;%AXIS_LIB%\jaxrpc.jar;%AXIS_LIB%\saaj.jar;%AXIS_LIB%\log4j-1.2.8.jar;%AXIS_LIB%\xml-apis.jar;%AXIS_LIB%\xercesImpl.jar;%AXIS_LIB%\wsdl4j-1.5.1.jar;%AXIS_LIB%\activation.jar;%AXIS_LIB%\xmlrpc-2.0.jar

 

(xml-apis.jar, xercesImpl.jar属于Xerces或Xalan, activation.jar属于jaf, xmlrpc-2.0.jar属于xmlrpc)

1. 配置完成后启动tomcat,在浏览器中键入http://localhost:8080/axis,将显示如下画面

查看更多精彩图片

2.在C:\Tomcat5\webapps\axis\WEB-INF目录下建立一个src目录,用于存放源程序
接着编写服务端程序server.AxisReturn
package server;
public class AxisReturn {
    public String ReturnMsg(String servicesName) {
      return "Axis Return: "+ servicesName;
    }
}
在 此我们利用了Jbuilder X作为我们java程序的开发工具,利用Jbuilder新建工程中的Project for Existing Code将C:\Tomcat5\webapps\axis\WEB-INF下的程序及目录导入作为Jbuilder的一个工程来操作

查看更多精彩图片
编译AxisReturn程序,Jbuilder将会把编译后的class文件自存放在C:\Tomcat5\webapps\axis\WEB-INF\classes\server目录下

3.编写wsdd文件,此处命名为deploy.wsdd,其内容为

<deployment xmlns=http://xml.apache.org/axis/wsdd/
              xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<service name="AxisReturn" provider="java:RPC">
    <parameter name="className" value="server.AxisReturn"/>
    <parameter name="allowedMethods" value="*"/>
</service>
</deployment>


每个service就代表服务端的一个程序,如有多个可继续添加service,相关参数请查阅axis文档
此处的deployment代表发布服务,如改为undeployment则为撤销服务

4.发布服务
打开windows的命令窗口,转到wsdd文件的存放目录下,此处为C:\Tomcat5\webapps\axis\WEB-INF\src\server
在命令窗口中键入
java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient deploy.wsdd

如果成功将显示<Admin>Done processing</Admin>
如失败,则检查AXISCLASSPATH是否设置正确,tomcat端口是否为默认的8080
在这里有一个问题需注意,不管是在axis目录下还是其他虚拟目录下,如直接执行这条命令,都将在axis的目录下发布service,如果想发布在其他的目录下,如pscsaxis,则应执行
java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient -lhttp://localhost:8080/pscsaxis/services/AdminService deploy.wsdd

-cp表示在AXISCLASSPATH环境变量中检索org.apache.axis.client.AdminClient方法

5.生成client stub文件
在命令窗口中将目录转至C:\Tomcat5\webapps\axis\WEB-INF\classes
然后执行
java -cp %AXISCLASSPATH% org.apache.axis.wsdl.Java2WSDL -oAxisReturn.wsdl -lhttp://localhost:8080/axis/services/AxisReturn -nAxisReturn server.AxisReturn

将会在C:\Tomcat5\webapps\pscsaxis\WEB-INF\classes下生成AxisReturn.wsdl文件
接着在执行
java -cp %AXISCLASSPATH% org.apache.axis.wsdl.WSDL2Java AxisReturn.wsdl -p client

将会在C:\Tomcat5\webapps\axis\WEB-INF\classes\client目录下生成四个java文件
AxisReturn_PortType.java
AxisReturnService.java
AxisReturnServiceLocator.java
AxisReturnSoapBindingStub.java
将这四个文件剪切至C:\Tomcat5\webapps\pscsaxis\WEB-INF\src\client目录下,并编译

6.编写客户端
利用生成client stub文件编写

package client;
public class ClientAxisReturn {
    public static void main(String args[]) {
      try {
        AxisReturnService service = new client.AxisReturnServiceLocator();
        client.AxisReturn_PortType client = service.getAxisReturn();
        String retValue = client.returnMsg("BaoSteel");
        System.out.println(retValue);
      }
      catch (Exception e) {
        System.err.println("Execution failed. Exception: " + e);
      }
    }
}

编写完后,编译运行即可得到返回结果
如需传入多个参数,需在String retValue = client.returnMsg("BaoSteel");这句中增加参数,如
String retValue = client.returnMsg("BaoSteel","PSCS_IMS");
相应的服务端也要更改,如
package server;
public class AxisReturn {
    public String ReturnMsg(String servicesName,String serviceID) {
      return "Axis Return: "+ servicesName+ serviceID;
    }
}

利用发布服务的wsdl的URL编写
package client;
import org.apache.axis.AxisFault;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import javax.xml.rpc.ParameterMode;
import javax.xml.rpc.encoding.XMLType;
public class ClientAxisReturnWsdl {
    public static void main(String args[]) throws Exception{
      String endPoint =
        
http://190.2.63.239:8080/pscsaxis/services/AxisReturn?wsdl;
      Service service = new Service();
      Call call = (Call) service.createCall();
      Object result;
      try {
        call.setTargetEndpointAddress(new java.net.URL(endPoint));
        call.setOperationName("ReturnMsg");
        call.addParameter("OP1", XMLType.XSD_STRING, ParameterMode.IN);
        call.setReturnType(XMLType.XSD_STRING);
        result = (Object) call.invoke(new Object[] {"BaoSteel"});
      }
      catch (AxisFault fault) {
        result = "Error is: " + fault.toString();
      }
      System.out.println(result);
    }
}

编写完后,编译运行即可得到返回结果
如许增加参数,则需添加语句
call.addParameter("OP1", XMLType.XSD_STRING, ParameterMode.IN);
将参数名OP1改为其他,如OP2
在result = (Object) call.invoke(new Object[] {" BaoSteel "});这句中增加参数,如
result = (Object) call.invoke(new Object[] {" BaoSteel "," PSCS_IMS "});
相应的服务端也要更改,如
package server;
public class AxisReturn {
    public String ReturnMsg(String servicesName,String serviceID) {
      return "Axis Return: "+ servicesName+ serviceID;
    }
}

★在这里,我们的服务端只有一个方法供我们调用,如果我们需要调用多个服务端的方法,则可在服务端中加入其他方法,如我们在增加一个xxMsg

package server;
public class AxisReturn {
    public String ReturnMsg(String servicesName,String systemID) {
      return "Axis Return: "+ str+servicesName+systemID;
    }
    public String xxMsg(String serviceName,String systemID) {
    return "XX Return: "+ str+serviceName+systemID;
}
}

★修改完后将其编译,并将其注销后重新发布,反之需要重起tomcat,否则服务将不被更新
★利用生成client stub文件编写的客户端程序,还需重新生成client stub文件,并将其编译,在客户端程序中调用其相应得方法即可

SOAPMonitor的配置

发 布了Web服务以后,如何观察请求和响应数据呢?记录运行日志是一种传统且有效的方法,但对于调试程序来讲还不够方便和直观。值得欣慰的是,Axis为我 们提供了在客户端观察SOAP请求和响应流数据的工具SoapMonitor,经过适当配置后,可以实时地观察到Web服务的SOAP请求和响应数据。 SoapMonitor是一个Java Applet程序,通过浏览器下载到客户端运行。下面就介绍SoapMonitor的配置和使用方法。

在C:\Tomcat5\webapps\axis的目录下有一个SOAPMonitorApplet.java的程序,axis默认没有给我们编译,我们需要自己进行编译

打开windows命令窗口,转到C:\Tomcat5\webapps\axis目录下,执行
javac -classpath %AXIS_HOME%\lib\axis.jar SOAPMonitorApplet.java

编译完成后需要发布服务,我们需要建立一个wsdd文件deploy-monitor.wsdd,内容如下

<deployment xmlns=http://xml.apache.org/axis/wsdd/
      xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
    <handler name="soapmonitor"
        type="java:org.apache.axis.handlers.SOAPMonitorHandler">
      <parameter name="wsdlURL" value="/axis/SOAPMonitorService-impl.wsdl"/>
      <parameter name="namespace" value="http://tempuri.org/wsdl/2001/12/SOAPMonitorService-impl.wsdl"/>
      <parameter name="serviceName" value="SOAPMonitorService"/>
      <parameter name="portName" value="Demo"/>
    </handler>
    <service name="SOAPMonitorService" provider="java:RPC">
      <parameter name="allowedMethods" value="publishMessage"/>
      <parameter name="className" value="org.apache.axis.monitor.SOAPMonitorService"/>
      <parameter name="scope" value="Application"/>
    </service>
</deployment>

需要注意的是红色的那句语句,如果是在我们自己的web应用目录下的话需改成自己的目录。
建立完成后执行命令进行发布
java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient -lhttp://localhost:8080/axis/services/AdminService deploy-monitor.wsdd

发布SOAPMonitor服务后,还要对被监测的Web服务进行配置。方法是先注销该Web服务,然后修改该服务对应的WSDD文件,在其中增加请求流和响应流的配置,否则是观测不到SOAP请求和响应流的。以我们上面的程序为例,将deploy.wsdd修改为

 

<deployment xmlns=http://xml.apache.org/axis/wsdd/
              xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<service name="AxisReturn" provider="java:RPC">
      <requestFlow>
        <handler type="soapmonitor"/>
      </requestFlow>
      <responseFlow>
        <handler type="soapmonitor"/>
      </responseFlow>
    <parameter name="className" value="server.AxisReturn"/>
    <parameter name="allowedMethods" value="*"/>
</service>
</deployment>


增加了
     <requestFlow>
        <handler type="soapmonitor"/>
      </requestFlow>
      <responseFlow>
        <handler type="soapmonitor"/>
      </responseFlow>
这两段

然后我们通过点击http://localhost:8080/axis/主页上的SOAPMonitor或直接访问http://localhost:8080/axis/SOAPMonitor,点击start或stop启动或停止监控,然后我们运行客户端程序,SOAPMonitor会监控到请求和响应流,如下图

查看更多精彩图片

在 这里,我们需要注意一个配置问题,如果tomcat下有多个axis应用,设置了多个SOAPmonitor,我们则需要更改SOAPmonitor的端 口(axis默认配置的是5001),否则会产生冲突,运行SOAPmonitor时会无法启动,提示the soap monitor is unable to communcate with the server,解决方法如下:

打开C:\Tomcat5\webapps\axis\WEB-INF目录下的web.xml,找到

<servlet>
      <servlet-name>SOAPMonitorService</servlet-name>
      <display-name>SOAPMonitorService</display-name>
      <servlet-class>
          org.apache.axis.monitor.SOAPMonitorService
      </servlet-class>
      <init-param>
        <param-name>SOAPMonitorPort</param-name>
        <param-value>5001</param-value>
      </init-param>
      <load-on-startup>100</load-on-startup>
</servlet>

这段,将其中的5001改成5002,依此类推

总结:
尽量将发布websrrvice的文件夹和axis分开放置
建立多个axis应用时,应注意一些端口的设置,命令的参数设置以及一些命令执行的路径设置等,否则会产生一些错误,如ClassNotFound,service发布错误等的错误

 

server-config.wsdd

<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"
     xmlns:handler="http://xml.apache.org/axis/wsdd/providers/handler"
     xmlns="http://xml.apache.org/axis/wsdd/"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     name="defaultClientConfig" xsi:type="deployment">
     <globalConfiguration>
         <parameter name="disablePrettyXML" value="true"/>
         <parameter name="dotNetSoapEncFix" value="true"/>
         <parameter name="enableNamespacePrefixOptimization" value="false"/>
         <requestFlow>
             <handler type="java:org.apache.axis.handlers.JWSHandler">
                 <parameter name="scope" value="session"/>
             </handler>
             <handler type="java:org.apache.axis.handlers.JWSHandler">
                 <parameter name="scope" value="request"/>
                 <parameter name="extension" value=".jwr"/>
             </handler>
         </requestFlow>
     </globalConfiguration>
     <handler name="URLMapper" type="java:org.apache.axis.handlers.http.URLMapper"/>
     <handler name="LocalResponder" type="java:org.apache.axis.transport.local.LocalResponder"/>
     <handler name="Authenticate" type="java:org.apache.axis.handlers.SimpleAuthenticationHandler"/>

    <service name="CallcenterWebServices" provider="java:RPC" style="rpc" use="encoded">
         <parameter name="scope" value="Request"/>
         <parameter name="className" value="com.isw2.ebay.callcenter.axis.CallcenterWebServices"/>
         <parameter name="allowedMethods" value="getStatus,getCsrBean,setStatus,createCase,showContactRecord,getWorkload"/>
         
    <beanMapping qname="myNS:CsrBean" xmlns:myNS="urn:CsrBean"
    languageSpecificType="java:com.isw2.ebay.callcenter.axis.CsrBean" />
   <beanMapping qname="myNS:ContactRecordBean" xmlns:myNS="urn:ContactRecordBean"
    languageSpecificType="java:com.isw2.ebay.callcenter.axis.ContactRecordBean" />  
   <beanMapping qname="myNS:DisputeContactRecord" xmlns:myNS="urn:DisputeContactRecord"
    languageSpecificType="java:com.isw2.ebay.callcenter.axis.DisputeContactRecord" />
   <beanMapping qname="myNS:WorkloadNumberBean" xmlns:myNS="urn:WorkloadNumberBean"
    languageSpecificType="java:com.isw2.ebay.callcenter.axis.WorkloadNumberBean" />  
  
     </service>
    
     <service name="AdminService" provider="java:MSG">
         <parameter name="allowedMethods" value="AdminService"/>
         <parameter name="enableRemoteAdmin" value="false"/>
         <parameter name="className" value="org.apache.axis.utils.Admin"/>
         <namespace>http://xml.apache.org/axis/wsdd/</namespace>
     </service>
     <service name="Version" provider="java:RPC">
         <parameter name="allowedMethods" value="getVersion"/>
         <parameter name="className" value="org.apache.axis.Version"/>
     </service>
     <transport name="http">
         <parameter name="qs:list" value="org.apache.axis.transport.http.QSListHandler"/>
         <parameter name="qs:method" value="org.apache.axis.transport.http.QSMethodHandler"/>
         <parameter name="qs:wsdl" value="org.apache.axis.transport.http.QSWSDLHandler"/>
         <requestFlow>
             <handler type="URLMapper"/>
             <handler type="java:org.apache.axis.handlers.http.HTTPAuthHandler"/>
         </requestFlow>
     </transport>
     <transport name="local">
         <responseFlow>
             <handler type="LocalResponder"/>
         </responseFlow>
     </transport>
</deployment>
posted @ 2008-11-13 00:33 存鹰之心于高远,取鹰之志而凌云,习鹰之性以涉险,融鹰之神在山巅. 阅读(4950) | 评论 (0)编辑 收藏