分布式架构学习笔记(二)----面向服务的体系架构
面向服务的体系架构
本章目标:
理解分布式架构基础SOA,使用JAVA语言分别进行TCP协议、HTTP协议的RPC实践。
理解服务路由及负载均衡常用算法。
知识要点:
1. 对象序列化与反序列化(无论何种类型的数据,最终都转换为二进制流在网络上传输)
1.1 序列化与反序列化成熟解决方案:
a. Google的Protocol Buffers:性能优异跨平台,编程代码侵入性强,需要编写proto文件,无法直接使用java等面向对象编程语言的对象。
b. java内置序列化:不需要三方包,使用简单,效率不高。
c. Hessian:效率较Protocol Buffers低,但对各种编程语言支持良好,性能稳定
d. XML和JSON格式:高效,跨平台,移动互联网领域大规模使用。
a) java对象序列化为JSON
1 String PersonJson = null; 2 ObjectMapper mapper = new ObjectMapper(); 3 StringWriter sw = new StringWriter(); 4 JsonGenerator gen = new JsonFactory().createJsonGenerator(sw); 5 mapper.writeValue(gen,person); 6 gen.close(); 7 personJson = sw.toString();
b) JSON反序列化为java对象
Person zhangsan = (Person)mapper.readValue(personJson, Person.class);
c) java对象序列化为XML
XStream xStream = new XStream(new DomDriver());
//设置person类别名
xStream.alias("person",Person.class);
String personXML = xStream.toXML(person);
d) XML反序列化为person
Person zhangsan = (Person)xStream.fromXML(personXML);
2. TCP协议的RPC实现
2.1 服务者接口:
public interface SayHelloService {
public String sayHello(String helloArg);
}
2.2 接口实现:
public class SayHelloServiceImpl implements SayHelloService {
public String sayHello(String helloArg) {
if(helloArg.equals("Hello")){
return "Hello";
}else{
return "bye bye";
}
}
}
3. 消费者类实现
public class Consumer {
public static void main(String[] args) throws Exception {
//获取需要发送的东西
String interName = SayHelloService.class.getName();
Method method = SayHelloService.class.getMethod("sayHello", String.class);
Object[] argurements = {"Hello"};
//创建 socket 对象
Socket client = new Socket("127.0.0.1",5555);
//获取输出流
ObjectOutputStream oos = new ObjectOutputStream(client.getOutputStream());
oos.writeUTF(interName);
oos.writeUTF(method.getName());
oos.writeObject(method.getParameterTypes());
oos.writeObject(argurements);
//刷新缓冲区,不然会出现”连接重置 connection reset 找不到资源 “的问题
oos.flush();
//获取输入流
ObjectInputStream ois = new ObjectInputStream(client.getInputStream());
Object result = ois.readObject();
String str = ois.readUTF();
System.out.println("RPC远程调用结果: ");
System.out.println(result);
//关闭连接
client.close();
}
}
4. 服务者类实现:
public class Provider {
public static void main(String[] args) throws Exception {
HashMap<Object, Object> map = new HashMap<>()map.put(SayHelloService.class.getName(), new SayHelloServiceImpl());
//创建socket对象
ServerSocket server = new ServerSocket(5555);
System.out.println("服务器已启动....");
//不断接收新来的请求,得到所需要的参数,包括接口名称、方法名称、参数类型和参数
while(true){
//监听用户请求
Socket client = server.accept();
//获取输入流
ObjectInputStream ois = new ObjectInputStream(client.getInputStream());
String interName = ois.readUTF();
String methodName = ois.readUTF();
Class<?>[] parameterTypes = (Class<?>[]) ois.readObject();
Object[] arguments = (Object[])ois.readObject();
//执行调用 通过反射,得到调用的方法
Class<?> serviceClass = Class.forName(interName);
Object service = map.get(interName);
Method method = serviceClass.getMethod(methodName, parameterTypes);
//执行方法,并返回结果
Object result = method.invoke(service, arguments);
//https://www.cnblogs.com/qingchen521/p/8575761.html
System.out.println("要发送处理的结果: "+result);
//获取输出流
ObjectOutputStream oos = new ObjectOutputStream(client.getOutputStream());
oos.writeObject(result);
oos.writeUTF("调用结束");
oos.flush();
}
}
}
3. HTTP协议的RPC实现
TCP实现RPC,不同平台的移动端应用程序,需要开发不同的工具包进行请求发送和响应解析。基于HTTP协议的RPC,可以使用JSON或XML格式的响应数据,JSON和XML作为通用的格式标准,开源的解析工具已经相当成熟。
使用HTTP传输所占有的字节数,比TCP协议肯定要多,传输效率低一些。通过代码优化和使用GZIP压缩可以缩小这一差距。
4. 服务路由与负载均衡
4.1 方案选择
规模较小:
选择F5或者nignx跟LVS,通过相关配置解决服务路由与负载均衡问题
规模较大:
问题:人工管理维护服务及地址配置信息,越来越困难。单一硬件单点故障问题。
解决方案:需要一个动态注册和获取服务信息的地方,统一管理服务名称和其对应的服务器列表信息,成为服务配置中心。--ZooKeeper
能力:基于ZooKeeper的持久和非持久节点,能够近乎实时感知后端服务器状态(上下线、宕机)。通过zab协议,使服务器配置信息保持一致。
ZooKeeper容错特性和leader选举机制,保障方便扩容。
4.2 负载均衡算法
轮询、随机、源地址哈希、加权轮询、加权随机、最小连接