面向服务的体系架构(SOA)

来源:互联网 发布:正规淘宝刷客平台 编辑:程序博客网 时间:2024/05/18 00:40

面向服务的体系架构(SOA)

@(Blog)[SOA]

  • 面向服务的体系架构SOA
    • 概念
    • RPC的实现方式
      • 1 基于TCP协议的RPC
      • 2 基于HTTP协议的RPC
      • 3 HTTP的请求和响应
      • 4 HTTPClient的使用
      • 5 JSON
      • 6 XML
      • 7 RESTful
      • 8基于HTTP协议的RPC实现
    • 服务的路由和负载均衡
      • 1 负载均衡算法
      • 2 ZooKeeper 使用

1 概念

  • RPC(Remote Process Call) 远程过程调用。实现方式:RMI、WebService。
  • 对象的序列化 将对象转换为二进制流的过程
    反序列化 将二进制流恢复成对象
    常用方式:Google的Protocal Buffers、Java API、Hessian、JSON、XML。
  • Java API序列化
Person zhansan = new Person();zhansan.setName("zhansan");zhansan.setAge(18);//序列化ByteArrayOutputStream os = new ByteArrayOutputStream();ObjectOutputStream out = new ObjectOutputStream(os);out.writeObject(zhansan);byte[] zhansanByte = os.toByteArray();//反序列化ByteArrayInputStream is = new ByteArrayInputStream(zhansanByte);ObjectInputStream in = new ObjectInputStream(is);Person o = (Person) in.readObject();

2 RPC的实现方式

2.1 基于TCP协议的RPC

2.2 基于HTTP协议的RPC

都是通过socket实现,HTTP协议的RPC多了HTTP请求头部和响应头部

//客户端发送Socket client = new Socket("127.0.0.1", 1234);ObjectOutputStream output = new ObjectOutputStream(client.getOutputStream());output.writeUTF(interfacename);//调用的接口名称output.writeUTF(method.getName);//调用的方法output.writeObject(arguments);//参数//服务器接受 ServerSocket server = new ServerSocket(1234);while(true){    Socket socket = server.accept();    ObjectInputStream input = new ObjectInputStream(socket.getInputStream());    String interfacename = input.readUTF();    String method = input.readUTF();    Object[] arguments = (Object[])input.readObject();}

Java采用Big Endian字节序,所有网络协议也是采用Big Endian字节序进行传输。
HTTP协议使用TCP协议进行连接

  • 基于HTTP协议的RPC**优点**
    跨平台、实现简单(Web容器如Tomcat、JBoss、Apache已经考虑了多线程并发、锁、I/O问题)
  • 缺点: 相对于TCP协议,由于是上层协议,HTTP协议会占用更多的字节。

2.3 HTTP的请求和响应

如: http://www.google.com:80/index.html
1. 浏览器根据URL解析出域名和端口号
2. 通过DNS域名解析服务器,查询出对应的IP地址
3. 根据解析出的IP地址和端口号,建立连接
4. 浏览器发送请求,资源为index.html
5. 服务器返回内容,浏览器渲染网页
6. 浏览器关闭与服务器的连接

2.4 HTTPClient的使用

//创建httpClientHttpClientBuilder httpClientBuilder = HttpClientBuilder.create();CloseableHttpClient closeableHttpClient = httpClientBuilder.build();//Get请求HttpGet httpGet = new HttpGet("http://www.baidu.com");System.out.println(httpGet.getRequestLine());//执行请求CloseableHttpResponse httpResponse = closeableHttpClient.execute(httpGet);HttpEntity entity = httpResponse.getEntity();System.out.println(httpResponse.getStatusLine());if(entity != null){    System.out.println(entity.getContentEncoding());    System.out.println(new String(EntityUtils.toByteArray(entity), "utf8"));}closeableHttpClient.close();

2.5 JSON

JSON (Javascript Object Notation) 是一种轻量级的数据交换语言,易于阅读。将对象序列化成JSON格式,可以再网络上方便的进行传输。

//创建对象Person person = new Person();person.setName("zhansan");person.setAge(18);//创建mapperObjectMapper mapper = new ObjectMapper();StringWriter sw = new StringWriter();String personJson;JsonGenerator gen = new JsonFactory().createGenerator(sw);//对象转JSONmapper.writeValue(gen, person);gen.close();personJson = sw.toString();//{"name":"zhansan","age":18}System.out.println(personJson);//JSON转对象Person zhangsan = mapper.readValue(personJson, Person.class);

2.6 XML

XML(Extensible Markup Language),可扩展标记语言,可以用来标记数据、定义数据类型,允许用户自定义。独立于应用程序的结构化数据,适合Web传输。

//创建对象Person person = new Person();person.setAge(18);person.setName("zhangsan");//对象转XMLXStream xStream = new XStream(new DomDriver());xStream.alias("person", Person.class);String personXML = xStream.toXML(person);/**<person>  <name>zhangsan</name>  <age>18</age></person>**/System.out.println(personXML);//XML转对象Person zhangsan = (Person) xStream.fromXML(personXML);

2.7 RESTful

REST最早由Roy Thomas Fielding再2000年提出,即为表现层状态转换(Representational State Transfer)。由于HTTP协议是无状态的,所有的状态都保存在服务器端。
RESTful风格中的一个思想是:通过HTTP请求对应的POST、GET、PUT、DELETE方法,完成对应的CRUD操作。

POST http://hostname/peopleGET   http://hostname/people/zhangsanPUT  http://hostname/people/zhangsanDELETE http://hostname/people/zhangsan

2.8基于HTTP协议的RPC实现

首先定义RPC的服务接口及实现。

pubic interface Service{    public Object execute(Map<String, Object> args);}

RPC风格的实用Servlet方式发送和接收请求。

@Ovrrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp){    //使用httpClient发送请求    HttpClient httpClient = new DefaultHttpClient();    HttpGet httpGet = new HttpGet(urCol);    HttpResponse response = httpClient.execute(httpGet);    ....}

服务提供者接受请求并返回服务执行结果。

@Override proected void doPost(HttpServletRequest req, HttpServletResponse resp){    String servicename = req.getParameter("service");    Map parameters = req.getParmeterMap();    serviceMap.get(servicename).execute(parameters);    resp.getWriter().write(...);}

需要在web.xml中配置servlet

RESTful风格的RPC,基于SpringMVC很容易实现。

@ResponseBody@RequestMapping(value="/provider/{servicename}/{timestamp}",method=RequestMethod.POST)public void provide(HttpServletRequest request, HttpSrevletResponse response,    @PathVariable("servicename") String servicename, @PathVariable("timestamp") Date timestamp){    //处理请求}

Spring配置文件

//包扫描的基本路径<context:component-scan base-package=""/>//开启Spring MVC<mvc:annotation-driven /> <bean id="contentNegotiatingViewResolver" class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">    //在没有扩展名时的默认展现形式    <property name="defaultContentType" value="application/xml" />    <property name="mediaTypes">        <map>            <entry key="html" value="text/html" />            <entry key="json" value="application/json" />            <entry key="xml" value="application/xml" />        </map>    </propety></bean>

3 服务的路由和负载均衡

SOA架构中,服务消费者通过服务名称,在众多服务中找到要调用的服的地址列表,称为服务的路由
负载均衡程序将从服务对应的地址列表中,通过负载均和算法,选择一台服务器进行访问,这个过程称为服务的负载均衡。
Alt text

3.1 负载均衡算法

  1. 轮询法:按顺序均匀的分配
  2. 随机法
  3. 源地址哈:获取客户端IP地址,计算哈希值,用该值对服务器列表取模,同一IP每次都会映射到同一台服务器。
  4. 加权轮询:可以按权重在服务集合众增加重复次数实现。
  5. 加权随机法
  6. 最小连接数

3.2 ZooKeeper 使用

基于ZooKeeper的持久和非持久节点,能够近乎实时的该知道后端服务器的状态(上线、下线、宕机)。通过集群间zab协议,是的服务信息保持一致。ZooKeeper本身容错特性和leader选举机制,方便扩容。通过ZooKeeper来实现服务动态注册、机器上线与下线的感知,且无中心化结构能够解决负载均衡设备单点故障问题。只有当配置信息更新时才会去ZooKeeper上回去最新的服务器地址列表,其他时候使用本地缓存。
Alt text

ZooKeeper是Hadoop下的一个子项目,它是一个针对大型分布式系统的可靠的协调系统,提供配置维护、名字服务、分布式同步、组服务等。

安装及配置ZooKeeper

#Ubuntu环境sudo wget http://www-eu.apache.org/dist/zookeeper/stable/zookeeper-3.4.10.tar.gz#解压sudo tar -xf zookeeper-3.4.10.tar.gzsudo mv zookeeper-3.4.10.tar.gz zookeepersudo rm -f zookeeper-3.4.10.tar.gz#修改系统的环境变量,到处Zookper的安装路径sudo vim /etc/profile# Zookeeper配置export ZOOKEEPER_INSTALL=/usr/ZooKeeperexport PATH=$PATH:ZOOKEEPER_INSTALL/bin#创建Zookeeper配置文件cd ZooKeeper/confcp zoo_sample.cfg zoo.cfg#vim zoo.cfgtickTime=2000 #zookeeper心跳时间 msinitLimit=10 #投票选举leader的初始化时间 10*tickTimesyncLimit=5 #leader与follower最大容忍时间 5*tickTime超时,leader会从服务列表中删除follwerdataDir=/tmp/zookeeper/data #数据目录dataLogDir=/tmp/zookeeper/log # 日志目录clientPort=2181 #客户连接端口#启动zookeeper服务cd /usr/zookeeper/binsudo./zkServer.sh start#使用自带的zkCli.sh查看节点连接情况。./zkCli.sh

开源项目ZKClient (https://github.com/sgroschupf/zkclient)