一、背景
随着网站访问量增加,仅仅靠增加机器已不能满足系统的要求,于是需要对应用系统进行垂直拆分和水平拆分。在拆分之后,各个被拆分的模块如何通信?如何保证性能?如何保证各个应用都以同样的方式交互?这就需要一种负责各个拆分的模块间通信的高性能服务框架(HSF
HSF全称为High-Speed Service Framework)。
二、HSF做的事情
1. 标准Service方式的RPC
1). service定义:基于OSGI的service定义方式
2). TCP/IP通信:
IO方式:nio,采用mina框架
连接方式:长连接
服务器端有限定大小的连接池
WebService方式
3). 序列化:hessian序列化机制
2. 软件负载体系
采用软件实现负载均衡,支持随机、轮询、权重、按应用路由等方式。软件负载均衡没有中间点,通过配置中心统一管理。配置中心收集服务提供者和消费者的注册信息,以推送的方式发送到服务消费者直接使用,不经过中间点;注册中心可以感应服务器的状态,出现failover时,实现注册信息重新推送。
3. 模块化、动态化
4. 服务治理
服务治理利用注册中心实现服务信息管理(服务提供者、调用者信息查询)、服务依赖关系分析、服务运行状况感知、服务可用性保障,如:路由调整、流量分配、服务端降级、调用端降级等
本文来自CSDN博客,转载请标明出处:
二:服务的开发
1.HSF服务的开发
1) 基于Maven创建一个web工程HSFService,如下图,其他的可以自定义。
2)创建好好在src/main目录下创建一个java目录,并将其设置为sources folder,如下图所示:
3) 配置项目的pom.xml,如下
4.0.0 com.hsf HSFService war 1.0-SNAPSHOT HSFService Maven Webapp http://maven.apache.org 1.7.0_67 junit junit 3.8.1 test javax.servlet servlet-api 2.5 org.springframework spring 2.5.6 jar compile mysql mysql-connector-java 5.1.6 commons-dbcp commons-dbcp 1.2.2 org.apache.servicemix.bundles org.apache.servicemix.bundles.ibatis-sqlmap 2.3.4.726_4 com.taobao.hsf hsf.app.spring 1.4.9.2 HSFService maven-compiler-plugin
4) 编写服务接口和服务的实现
代码如下:
package com.hsf.services;import java.lang.String;public interface SayHelloService{ public String sayHello(String user);}package com.hsf.services.impl;import com.hsf.services.SayHelloService;public class SayHelloServiceImpl implements SayHelloService { public String sayHello(String user) { return "Hello "+user+" ,Time is "+System.currentTimeMillis()+"(ms)"; } }
5) 在Spring的配置文件中配置HSFSpringProviderBean
com.hsf.services.SayHelloService 1.0.0.0.dev HSF SayHello com.hsf.services.SayHelloService 1.0.0.0.dev
6) 在Web.xml中配置spring的上下文环境
HSFService index.jsp index.html contextConfigLocation classpath*:applicationContext.xml org.springframework.web.context.ContextLoaderListener
7) 将HSFService部署,启动tomcat,即可在HSF服务治理中心中根据自己主机的IP查找自己发布的服务
8) 将服务接口SayHelloService打成Jar包(二方包)以供客户端使用
2.HSF服务的使用
1) 在客户端的pom.xml文件中添加对HSF的依赖
12 com.taobao.hsf 3hsf.app.spring 41.4.9.2 5
2) 在客户端的Spring配置文件中配置HSFSpringConsumerBean
com.hsf.services.SayHelloService 1.0.0.0.dev
3)引入服务端打好的二方Jar包com.hsf.services.jar,创建SayHelloServlet使用服务
SayHelloServlet的代码如下:
package com.hsf.consumer;import com.hsf.services.SayHelloService;import org.springframework.web.context.WebApplicationContext;import org.springframework.web.context.support.WebApplicationContextUtils;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;public class SayHelloServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //通过ServletContext获取Spring的上下文 WebApplicationContext context= WebApplicationContextUtils.getWebApplicationContext(getServletContext()); //通过BeanFactory获取服务的消费者SayHelloServiceConsumer SayHelloService sayHelloService= (SayHelloService) context.getBean("SayHelloServiceConsumer"); PrintWriter out=response.getWriter(); //调用服务 out.println(sayHelloService.sayHello("xiwu.xxw")); out.close(); return; } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request,response); }}
5)部署该web工程到tomcat,启动tomcat后访问 SayHello?name=zhangsna 即可看到打印出“Hello zhangsan,Time is xxxxx (ms)”
背景: WEBX -- 阿里巴巴网站所采用的WEB应用框架.
HSF接口: com.taobao.item.service.ItemQueryService
需求: 根据商品ID取得商品信息
载体: TBCMS系统
实现步骤: 1. 创建 /bundle/war/src/webroot/META-INF/autoconf/item-hsf-xml.vm
代码:
<?xml version="1.0" encoding="GB2312"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans default-autowire="byName"> <bean id="itemQueryService" class="com.taobao.hsf.app.spring.util.HSFSpringConsumerBean" init-method="init"> <property name="interfaceName"> <value>com.taobao.item.service.ItemQueryService</value> </property> <property name="version"> <value>${item_provide_service_version}</value> </property> <!--asyncallMethods为可选配置[List],含义为调用此服务时需要采用异步调用的方法名列表,默认为空集合,即所有方法都采用同步调用--> <property name="asyncallMethods"> <list> </list> </property> </bean></beans>
2.其中: ${item_provide_service_version} 需要在 auto-config.xml 中配置,在 <group name="arkcms-bundle-war"> ...</group>中增加:
<property name="item.provide.service.version" defaultValue="1.0.0.daily" desc="itemClient调用版本"/>
同时在 <script>...</script>中增加:
<generate template="item-hsf.xml.vm" destfile="WEB-INF/biz/bean/item-hsf.xml" charset="GBK"/>
3.在 /bundle/war/src/webroot/WEB-INF/cms-biz-services.xml中增加:
<service name="BeanFactoryService" class="com.alibaba.service.spring.DefaultBeanFactoryService">
<property name="bean.descriptors">....................
<value>/cms/biz/bean/item-hsf.xml</value>
</property> </service>至此,我们已经引入了ItemQueryService的HSF服务.
4. 接下来我们就要做Servlet接口了,当然写一个servlet直接调用hsf也是可以的,但是从结构考虑,我们还是先本地封装一层先.
但是首先,需要对 /all/project.xml 中需要增加对ItemQueryService的支持:
<projects name="taobao/itemcenter" version="1.9.5">
<project id="taobao/itemcenter/itemcenter-client"/> <project id="taobao/itemcenter/itemcenter-common"/> </projects>并在/biz/project.xml和/web/project.xml中增加:
<?xml version="1.0" encoding="GB2312"?>
<project id="tbcms/web" extends="../all/project.xml">
<build> <dependencies> ............ <include uri="taobao/itemcenter/itemcenter-client"/> <include uri="taobao/itemcenter/itemcenter-common"/> </dependencies> </build> </project>命令行模式下执行:antx reactor goals=eclipse来执行对依赖包的装载.(前提是对/antx/repository.project/taobao/itemcenter/进行SVN更新)
本地封装: 在/biz/src/java/com/ark/cms/biz/util/item/下创建ItemService.java接口:
package com.ark.cms.biz.util.item;
import com.taobao.item.domain.DbRoute;
import com.taobao.item.domain.query.ItemIdDO; import com.taobao.item.domain.result.ItemResultDO; import com.taobao.item.exception.IcException; /** * 根据id取得商品信息 * duxing * */ public interface ItemService { public ItemResultDO getItemById(ItemIdDO itemId,DbRoute mainDbRoute) throws IcException; }在biz/src/java/com/ark/cms/biz/util/item/impl/下 ItemServiceImpl.java进行实现:
package com.ark.cms.biz.util.item.impl;
import com.ark.cms.biz.util.item.ItemService;
import com.taobao.item.domain.DbRoute; import com.taobao.item.domain.query.ItemIdDO; import com.taobao.item.domain.query.QueryItemOptionsDO; import com.taobao.item.domain.result.ItemResultDO; import com.taobao.item.exception.IcException; import com.taobao.item.service.ItemQueryService;/**
* 根据id取得商品信息 实现 * duxing * */public class ItemServiceImpl implements ItemService {
private ItemQueryService itemQueryService;
public void setItemQueryService(ItemQueryService itemQueryService) {
this.itemQueryService = itemQueryService; }@SuppressWarnings("deprecation")
public ItemResultDO getItemById(ItemIdDO itemId, DbRoute mainDbRoute) throws IcException { QueryItemOptionsDO options = null; return itemQueryService.queryItemById(itemId, options, mainDbRoute); }}
然后将此接口移交给spring,在 /bundle/war/src/webroot/META-INF/autoconf/item-hsf-xml.vm中增加<bean id="itemService" class="com.ark.cms.biz.util.item.impl.ItemServiceImpl"></bean>
至此,我们已经在spring中产生一个itemService
5.接下来创建servlet
在/web/src/java/com/ark/cms/web/下创建ItemServiceServlet.java
因为servlet中不能直接用set形式让spring来set itemService进来,所以只能采用一下方法获取itemService:
BeanFactoryService beanFactory = (BeanFactoryService) BizServiceManager.getInstance().getService(BeanFactoryService.SERVICE_NAME);
ItemService itemService = (ItemService) beanFactory.getBean("itemService");完整代码如下:
package com.ark.cms.web;
import java.io.IOException;
import java.io.OutputStream;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;import com.alibaba.service.spring.BeanFactoryService;
import com.ark.cms.biz.core.BizServiceManager; import com.ark.cms.biz.util.item.ItemService; import com.taobao.item.domain.DbRoute; import com.taobao.item.domain.ItemDO; import com.taobao.item.domain.query.ItemIdDO; import com.taobao.item.domain.result.ItemResultDO; import com.taobao.item.exception.IcException; /** * 根据id取得商品大图的接口 * duxing * */ public class ItemServiceServlet extends HttpServlet {private static final long serialVersionUID = -3348559907279438489L;
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // // long itemId=4399800173l;String item_id = request.getParameter("item_id");
String xid = request.getParameter("xid");
DbRoute mainDbRoute=DbRoute.getDbRouteByXid(xid);ItemIdDO itemIDDO=new ItemIdDO();
if(item_id!=null){ itemIDDO.setItemIdStr(item_id); } if(request.getParameter("item_num_id")!=null){ Long item_num_id = Long.valueOf(request.getParameter("item_num_id")); itemIDDO.setItemId(item_num_id); } if(request.getParameter("id")!=null){ Long id = Long.valueOf(request.getParameter("id")); itemIDDO.setItemId(id); } // 两种id的传入方式 // itemIDDO.setItemId(itemId); // itemIDDO.setItemIdStr("67af640ba3f16a2006cd63f1f5dddc271");ItemResultDO itemResultDO;
BeanFactoryService beanFactory = (BeanFactoryService) BizServiceManager.getInstance().getService(BeanFactoryService.SERVICE_NAME); ItemService itemService = (ItemService) beanFactory.getBean("itemService"); try { itemResultDO=itemService.getItemById(itemIDDO, mainDbRoute); } catch (IcException e) { e.printStackTrace(); itemResultDO=new ItemResultDO(); }ItemDO itemDO=itemResultDO.getItem();
byte[] result="".getBytes(); if(itemDO!=null){ result=itemDO.getPictUrl().getBytes(); } response.setContentType("text/xml;charset=gb2312"); response.setContentLength(result.length); OutputStream out = response.getOutputStream(); out.write(result); out.flush();}
}6.servlet写好了之后我们就要配置进WEBX了:在 /bundle/war/src/webroot/META-INF/autoconf/web.xml.vm中增加:
<servlet-mapping>
<servlet-name>ItemServiceServlet</servlet-name>
<url-pattern>/item/query</url-pattern> </servlet-mapping><servlet>
<servlet-name>ItemServiceServlet</servlet-name> <servlet-class>com.ark.cms.web.ItemServiceServlet</servlet-class> </servlet>7.至此,开发完成
命令行模式下执行:antx reactor goals=clean,default来对项目重新编译打包.重启本地服务器进行测试.
对/item/query接口进行post的时候触发此servlet.