ellios's blog

ellios's trivial story.

Vrs Hedwig入门

| Comments

hedwig(Harry Potter’s owl. A messager.)是一个分布式服务的框架,用户使用它可以很方便的开发分布式服务,并使用这些服务。它主要有以下功能:

  • 统一的服务注册中心
  • 统一的服务管理平台
  • 统一的服务监控平台
  • 使用protocol buffer或者thrift作为消息格式,支持多种语言调用。
  • 服务可动态扩展
  • 负载均衡
  • 服务的容错容灾

下面对hedwig的使用做一个简单的入门介绍.

hedwig支持[protocol buffer]和thrift作为消息格式,两种格式的服务开发和调用略有不同,下面分别讲述。

Protocol bufffe服务

服务Provider

  1. 定义消息格式
example.proto
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.qiyi.vrs.hedwig.examples.pb;

option java_package = "com.qiyi.vrs.hedwig.examples.pb";
option java_outer_classname = "Calculator";

message CalcRequest {
    required int32 num1 = 1;
    required int32 num2 = 2;
    required Operation op = 3;

    enum Operation {
      ADD = 1;
      SUBTRACT = 2;
      MULTIPLY = 3;
      DIVIDE = 4;
    }
}

message CalcResponse {
    required int32 result = 1;
}
  1. 使用protoc生成代码
1
protoc --java_out=../java example.proto
  1. 定义服务接口
CalculatorService.java
1
2
3
4
public interface CalculatorService {

    Calculator.CalcResponse calculate(Calculator.CalcRequest request);
}
  1. 实现服务
CalculatorServiceImpl.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class CalculatorServiceImpl implements CalculatorService{

    @Override
    public Calculator.CalcResponse calculate(Calculator.CalcRequest request) {
        int num1 = request.getNum1();
        int num2 = request.getNum2();
        Calculator.CalcRequest.Operation op = request.getOp();
        System.out.println("calculate(, {" + op + "," + num1 + "," + num2 + "})");
        int val = 0;
        switch (op) {
            case ADD:
                val = num1 + num2;
                break;
            case SUBTRACT:
                val = num1 - num2;
                break;
            case MULTIPLY:
                val = num1 * num2;
                break;
            case DIVIDE:
                if (num2 == 0) {
                    throw new IllegalArgumentException("num2 is zero for divide operation");
                }
                val = num1 / num2;
                break;
            default:
                throw new IllegalArgumentException("unknown operation");
        }
        return Calculator.CalcResponse.newBuilder().setResult(val).build();
    }
}
  1. 启动服务,服务启动时会自动在服务中心注册
CalculatorServiceImpl.java
1
2
3
4
5
6
7
8
9
public class PbCalServer {

    public static void main(String... args){
        HedwigServer server = HedwigServer.getServer();
        server.registerService(ServiceConfigFactory.createServiceConfig(CalculatorService.class,
                CalculatorServiceImpl.class));
        server.start();
    }
}

服务调用

调用服务前你需要获取服务的接口类和接口名称,然后就可以调用服务了。

CalculatorServiceImpl.java
1
2
3
4
5
6
7
8
public class PbCalClient {

    public static void main(String... args){
        CalculatorService service = ServiceHelper.getPbService(CalculatorService.class);
        Calculator.CalcRequest request = Calculator.CalcRequest.newBuilder().setNum1(10).setNum2(20).setOp(Calculator.CalcRequest.Operation.ADD).build();
        System.out.println(service.add(request));
    }
}

Thrift服务

Thrift服务Provider

一. 定义服务接口

example.thrift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
* example.thrift
* show how to use thrift rpc
*/
namespace java com.qiyi.vrs.hedwig.examples.thrift
namespace py com.qiyi.vrs.hedwig.examples.thrift

enum Operation {
  ADD = 1,
  SUBTRACT = 2,
  MULTIPLY = 3,
  DIVIDE = 4
}

exception InvalidOperation {
  1: i32 what,
  2: string why
}

service Calculator {

   i32 calculate(1:i32 num1, 2:i32 num2, 3:Operation op) throws (1:InvalidOperation ouch),

}

二. 生成代码,thrift提供了代码生成工具,执行下面的命令生成java代码

example.thrift
1
thrift -gen java -out ../java exmaple.thrift
  1. 实现服务

thrift的代码生成工具会自动生成接口类,直接实现接口就可以了

example.thrift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class CalculatorServiceImpl implements Calculator.Iface{

    @Override
    public int calculate(int num1, int num2, Operation op) throws InvalidOperation{
        System.out.println("calculate({" + op + "," + num1 + "," + num2 + "})");
        int val = 0;
        switch (op) {
            case ADD:
                val = num1 + num2;
                break;
            case SUBTRACT:
                val = num1 - num2;
                break;
            case MULTIPLY:
                val = num1 * num2;
                break;
            case DIVIDE:
                if (num2 == 0) {
                    InvalidOperation io = new InvalidOperation();
                    io.what = op.getValue();
                    io.why = "Cannot divide by 0";
                    throw io;
                }
                val = num1 / num2;
                break;
            default:
                InvalidOperation io = new InvalidOperation();
                io.what = op.getValue();
                io.why = "Unknown operation";
                throw io;
        }
        return val;
    }
}
  1. 启动服务
example.thrift
1
2
3
4
5
6
7
8
9
10
11
public class ThriftCalServer {

    public static void main(String... args){
        HedwigServer server = HedwigServer.getServer();
        server.registerService(ServiceConfigFactory.createServiceConfig("ThriftCalculatorService", 8886,
                ServiceConfig.ServiceSchema.TCP,
                 ServiceConfig.ServiceType.THRIFT, Calculator.Iface.class,
                CalculatorServiceImpl.class));
        server.start();
    }
}

thrift服务调用

example.thrift
1
2
3
4
5
6
7
public class ThriftCalClient {

    public static void main(String... args) throws TException {
        Calculator.Iface service = ServiceHelper.getThriftService("ThriftCalculatorService", Calculator.Iface.class);
        System.out.println(service.calculate(10, 20, Operation.ADD));
    }
}

其他

  1. 服务端支持spring,需要在配置文件hedwig.properties中填加如下内容
1
2
hedwig.spring.enable=true
hedwig.spring.config=spring/vrs_all.xml

hedwig.spring.config可不填,默认会从META-INf/spring/下读取所有的配置文件

Comments