用norbert来写高并发分布式服务框架

来源:互联网 发布:日照万象mac专柜 编辑:程序博客网 时间:2024/06/06 11:49

用norbert来写高并发分布式服务框架

本来计划将sensei的相关源码系列搞完,但最近一段时间由于工作需求先调研了几种分布式的服务框架,做了简要的对比测试。根据我们自己的实际需要选取了norbert来做我们后台提供分布式服务的框架。因此,先整理一篇关于norbert框架的博文,也给自己留下个印记,以便以后来查阅。

Norbert简介
      “Norbert is a library that provides easy cluster management and workload distribution. With Norbert, you can quickly distribute a simple client/server architecture to create a highly scalable architecture capable of handling heavy traffic. ”
      这个是官方的描述,没有比这个更精准的了,norbert是一个提供分布式集群服务的开发框架,具备集群管理功能,对开发简单的通信架构,易扩展能承受高吞吐量的框架。
     其中集群管理的功能利用了zookeeper来进行node状态的感知,通讯采用了nio的netty server,序列化采用的是protobuf。整体而言来做分布式的服务,应该是非常合适的。linkedin在他们的架构里面都用到了这个框架。其实现是scala来写的,但我们使用java版的调用。
     下面是我给team同事做的一次介绍性的ppt,比较简单,从使用层面来讲的,仅供参考。

 

三种框架的对比
     在进行技术选型的时候,我们主要考察了hessian,thrift,norbert:
1. hessian是相对最成熟,最可靠的方式,在很多工程里面都用到,在异构java应用间的调用也还比较高效,已经有一些关于它的序列化测试。 但由于是http的协议,在连接数上受制于resin或者其他web服务器的链接数。
2. thrift  facebook开源的一个rpc的框架,主要特点是跨语言,现在贡献给了apache,市场上使用较多,在多语言开发的场景下很适合。走socket协议,没有集成zookeeper的管理,需要自己实现连接池之类。
3. norbert linkedin开源的框架,支持集群管理(zookeeper),走socket协议,protobuf的序列化支持。scala语言开发,不支持其他多语言,成熟度相对较低。
     测试环境: 输入为一片文章,服务进行分词和统计词数,并且返回。
    测试结果显示,在thread设置100,300,500,1000 并发进行压力测的时候,norbert与hessian相差无几;而当thread上1k的时候,hessian受限于resin的连接数抛出链接的异常。 thrift由另一同事进行同样的业务测试,测试结果与norbert稍逊,同样能撑1000以上的thread。
     在选型的时候,我们的目标是能够撑住新鲜事的服务,搜索更新的服务。并发链接数可能很大,因此更倾向于socket协议的norbert和thrift,而进行开发过程中,暂无支持其他语言的需求,但如果能支持集群服务,则开发更加简单。
      因此,打算采用norbert。

对Norbert的简易封装
     目的:让其他开发同事只关注于业务的实现,而将服务调用的开发流程更加简化。默认支持一致性hash的负责均衡。
     首先,对于一致性hash的使用,参考了xmemcahed客户端的KETAMA_HASH和redis客户端的MurmurHash。并且根据两种包装了一下,测试了两种在节点增减的情况下的负载性能和效率:
     测试环境: 在原本的固定节点数  n=2,5,10,50  ,并且分别增加一个节点,减少一个节点,导致miss的比率。
   50,51,49
  Ketamahash: 
 Total Same percent in added case : 97.728035%
Total Same percent in reduced case : 97.91693%
 used time:  ---   815  miliseconds!
  murmurhash:  
 Total Same percent in added case : 97.97288%
Total Same percent in reduced case : 98.00935%
 used time:  ---   664  miliseconds!
 
 10,11,9
  Ketamahash: 
 Total Same percent in added case : 91.03272%
Total Same percent in reduced case : 90.187935%
 used time:  ---   762  miliseconds!
  murmurhash:  
 Total Same percent in added case : 90.67101%
Total Same percent in reduced case : 90.65535%
 used time:  ---   596  miliseconds
 
 5,6,4
 Ketamahash:
 Total Same percent in added case : 83.67601%
Total Same percent in reduced case : 79.67246%
 used time:  ---   753  miliseconds!
 murmurhash:
 Total Same percent in added case : 82.390625%
Total Same percent in reduced case : 78.72605%
 used time:  ---   581  miliseconds!
 
 2.3.1
  Ketamahash
 Total Same percent in added case : 70.222466%
Total Same percent in reduced case : 50.81403%
 used time:  ---   723  miliseconds!
murmurhash:
 Total Same percent in added case : 68.841545%
Total Same percent in reduced case : 50.361725%
 used time:  ---   542  miliseconds!
    结论:

Ketamahash 和 murmurhash 在节点少的情况下,Ketamahash的增减节点的均衡性能稍高,
                         在节点多的情况下,MurmurHash 均衡性能高。
 总体而言,差异也不大,在1个百分点以内,执行hash的效率上,MurmurHash 计算比Ketamahash 快。
 建议,在少节点的情况下,直接使用Ketamahash的loadbalaceFactory。
封装后的server端代码:
        PropertiesConfiguration serverConf = new PropertiesConfiguration();
        try {
            serverConf.load(new File("D:\\workspace\\rpc\\resources", "server.properties"));
        } catch (ConfigurationException e) {
            e.printStackTrace();
        }
        final JingweiServer server = new JingweiServer(serverConf);
        HelloService hservice = new HelloServiceImpl();
        HelloServiceMessageHandler hmessageHandle = new HelloServiceMessageHandler(
                hservice);
        server.registerHandler(Person.getDefaultInstance(),
                RetStr.getDefaultInstance(), hmessageHandle);
        Runtime.getRuntime().addShutdownHook(new Thread() {
            public void run() {
                server.shutdown();
            }
        });
        server.start(true);
 仅需要初始化配置,提供服务的实现,以及注册,便可以启动服务。

客户端代码:
        LoadBalancerFactory factory = new MurmurHashLoadBalancerFactory();
        JingweiClient client = new JingweiClient(
                "D:\\workspace\\rpc\\resources", factory);
        client.registerRequest(Person.getDefaultInstance(),
                RetStr.getDefaultInstance());
        Person.Builder builder = Person.newBuilder();
        builder.setEmail("johnnychenjun@163.com");
        builder.setName("alex");
        RetStr ret = (RetStr) client.handleMessage(builder.build(), "alex");
        System.out.println("Ret String:" + ret.getVal());
        client.shutdown();
同样也是通过配置文件的读入,提供loadbalance的factory,注册消息,即可进行服务的调用了。