sulong 于 2009-08-03
2 篇评论 »
什么是集群
计算机集群(以下简称集群)在维基百科上被定义为一组相互连接的计算机,紧密的工作在一起,以至于在很多方面看来,它们都像是一台机器。
集群的好处
集群可能能给我们带来很多好处,其中负载均衡(loadbalance)和故障恢复(failover)一般是最常用的。负载均衡是将系统的负载分派到集群内不同的计算机上,让每个节点都不至于太忙或太闲,通过增加集群中计算机的数量,可以提升整体的负载能力。故障恢复是指在集群中某个节点发生故障时,其它的节点代替它们继续工作,这样整个系统依旧能对外提供服务。
web服务器集群的特点
对于web服务器来说,集群就是让一组计算机对外像一台web服务器一样运行。web服务器的特点是它通过http协议与客户端交互,而http协议的工作机制是请求响应模式的。web服务器的集群要能把客户端的http请求发送到集群内各个节点上,实现loadbalance,并能探测到各节点的工作情况,在某个节点失效的时候,不再把http请求发送到该节点上。
有状态与无状态
web程序本身是否有状态对实现集群的方法和难以度有很大的影响。如果web程序和客户端交互的记录下了一些状态信息,并在处理之后的请求时需要知道这样的信息,那么这个程序就是有状态的。比如,登录功能,当用户正确登录后,web程序会记录下用户的登录状态,当用户访问其它的页面时,web程序会参照用户的登录信息做不同的处理。在实现集群的时候,有状态的程序要复杂些,因为必须保证处理请求的节点上能有该用户的状态信息。对于无状态的程序,则没有这个问题,请求被分发到任何节点都是一样的,没有额外的维护状态的工作。
为了保证处理请求的节点上能有状态信息,要么在多个节点上复制程序的状态,要么采用否种策略保证将请求正确的发送到具有相应状态的节点上。如上面的例子,要么把用户登录的信息复制到集群的所有节点上,以保证无论之后请求发送到哪个节点上,都能够找得到登录信息,要么每次都把这个用户的请求发送到同一个节点上,就像mod_jk的sticky_session那样。
多线程与多进程
php,ruby,python等脚本语言往往采用无状态的结构,而java往往采用有状态的结构。并非语言决定了它们的工作方式,更多的是一种习惯。
java web服务在运行时是一个常驻内存的进程,用不同的线程处理用户请求。当处理一个http请求的线程结束后,保留在该进程内的信息并没有消失,因为进程还在。因此,可以很方便的把一些交互信息放到java进程的内存中,在多个线程间共享。在加上又有好用的HttpSession类,这样在java ee里把用户信息保存到session中,是一件非常容易的事,程序员们也自然的就采用的,导致了java web程序成了有状态的。如果完全不用session等,java web程序也能做到无状态。
和java的单进程,多线程工作方式不同,php等脚本语言采用了多进程的工作方式。当有一个http请求到来时,web服务器开启一个新的进程,这个进程调用脚本语言的解释器来运行脚本处理请求,处理结束后进程退出。如果要在多个进程间共享信息,就得采用外部的介质,DB就成了最好的选择。
本质上来说,只要需要记录会话的状态,就肯定有状态,差别只是把状态放到什么地方。java ee里往往把它放到应用程序的内存里,而php等则往往放到db里。
sulong 于 2009-07-14
没有评论 »
为什么java开发没有php容易?,我在那篇文章了提出了三点原因,利用groovy,我们能在一定程度上做到那三点,从而加快了java web的开发。jsp本身以具有不需要重启就可以生效的能力,但是没有好用的map和动态类型的能力,用在前文 用groovyServlet和TemplateServlet快速开发网页中的方法,可以通过groovy让页面具有好用的map和动态类型的能力,但是 TemplateServlet的局限性 还是很难让我们单凭在页面里编程来构建规模稍大些的应用。引入spring,利用spring对动态语言的支持,我们可以将可重用的逻辑封装到由groovy编写的spring的bean里,这样,就可以最终实现从页面到后台全groovy的效果了,让java的web开发可以达到近似于php的易用度。
看看详细的做法。
把最新版的groovy-all.jar和spring.jar以及spring所依赖的相关包放到/WEB-INF/lib/目录下。
首先,在web.xml里配置好对groovyServlet, TemplateServlet和spring的支持
代码如下:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>groovlet</servlet-name>
<servlet-class>groovy.servlet.GroovyServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>gsp</servlet-name>
<servlet-class>groovy.servlet.TemplateServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>groovlet</servlet-name>
<url-pattern>*.groovy</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>gsp</servlet-name>
<url-pattern>*.gsp</url-pattern>
</servlet-mapping>
然后,配置用groovy写spring的bean
如果你要写一个id为foo的bean, 那么要先用java写一个接口,然后用groovy写Bean实现接口,这样不但可以让你以后可以更容易用java重写groovy的bean,也可以避免和spring aop的冲突。
interface Foo.java 代码:
groovy实现类 FooImpl.groovy代码:
然后在applicationContext中配置
<lang:groovy id="foo" refresh-check-delay="5000" script-source="classpath:FooImpl.groovy">
<lang:property name="sampleProp" value="Hello" />
</lang:groovy>
注意上面的refresh-check-delay=”5000″是让spring每过五秒钟就刷新一下groovy代码,重新编译,当最终部署的时候,可以把它去掉,这样就不会重复刷新了。但是在开发时,我们因此获得了不重启就生效能里。
最后,可以在页面groovy文件中使用这个bean了
使用这个bean和使用其他的spring bean没有什么区别。
import org.springframework.web.context.support.WebApplicationContextUtils;
def spring = WebApplicationContextUtils.getWebApplicationContext(context)
Foo foo = spring.getBean("foo")
foo.shout("sulong")
只要不修改applicationConfig.xml,修改其他的部分都不需要重启或重新部署,这样,你可以通过groovy和spring来达到类似于php那种快速开发的目的。并且在后期,如果有必要,你还可以通过用java重写的bean的方式,来做性能优化。
sulong 于 2009-07-10
没有评论 »
我想利用TemplateServlet,像使用php那样使用groovy。只要设置好了,就可以在web目录下写gsp文件,就像写php那样,即时写即时看到效果。
但是我错了,目前的TemplateServlet非常简陋,远不能达到要求。问题主要发生在include功能。php的inclue require等功能,可以把页面变成方法库,或类库,但是在TemplateServlet的gsp里不行。我无法访问被包含的页面里的方法,闭包等。想想也很自然,每个gsp文件都有自己的名称空间。
另外,不能在gsp里定义类,这个太伤了~~~
如果能解决以上两个问题,TemplateServlet就可以让groovy像php那样使用了。唉,那些做grails的家伙真的应该先把这块搞好,再搞重量级的东西,毕竟不是所有人都想用spring hibernate的。
看了看gails的roadmap,今年9月的1.2版本里将有standalone gsp module,那是真正的gsp,而不是现在的简单的TemplateServlet。Grails里的gsp支持页面片段和非常方便的自定义标签,前者便于共享页面展示,后者便于共享页面行为,那么处理页面的是什么呢?还要写controller吗?到时候看吧,还是很令人期待的。
sulong 于 2009-07-09
2 篇评论 »
上一篇文章里快速上手使用groovy来写页面了,如果在页面里使用中文的话,可能会遇到中文问题。在1.6.3版本的groovy里,可以设置两个属性来解决:
groovy.source.encoding=UTF-8
file.encoding=UTF-8
groovy在解释脚本时,默认会使用一个叫做groovy.source.encoding的系统属性的值来作为源码的编码,如果这也没有设置的话,就会使用file.encoding这个系统属性,也就是操作系统的默认字符集了。然而TemplateServlet很傻,它只认file.encoding,所以要两个属性都设置上,才能解决问题。而file.encoding属性是在整个jvm下都有效的,可能会带来其他的问题。下个版本中groovy会修正这个问题。如果你等不及了,你可以像我这样,hack一下TemplateServlet,把getTemplate()方法的一段代码改为:
//
// Template not cached or the source file changed - compile new
// template!
//
if (template
== null) {
if (verbose
) {
log
("Creating new template from file " + file
+ "...");
}
String fileEncoding
= System.
getProperty("groovy.source.encoding");
Reader reader
= null;
try {
reader
= fileEncoding
== null ?
new FileReader(file
) : new InputStreamReader(new FileInputStream(file
), fileEncoding
);
template
= engine.
createTemplate(reader
);
} catch (Exception e
) {
throw new ServletException
("Creation of template failed: " + e,
e
);
} finally {
if (reader
!= null) {
try {
reader.
close();
} catch (IOException ignore
) {
// e.printStackTrace();
}
}
}
cache.
put(key,
new TemplateCacheEntry
(file, template, verbose
));
if (verbose
) {
log
("Created and added template to cache. [key=" + key
+ "]");
}
}
用了如上的代码后就只要设置groovy.source.encoding一个属性就可以了。