微服务实践之路--RPC

微服务实践之路--RPC

重点来了,本文全面阐述一下我们的RPC是怎么实现并如何使用的,跟Kubernetes和Openstack怎么结合。 
在选型一文中说到我们选定的RPC框架是Apache Thrift,它的用法是在Main方法中重启服务,在Client端连接服务去调用,

而我的想法是要跟Dubblo、HSF的用法一样,因为很多人都熟习这两个框架的用法,特别是我们好几个项目都是基于EDAS开发的,而且世面上用Dubbo的公司也很多。

顺便再说一下我们对于RPC的几点要求:

  • 1,兼容Dubbo和HSF的使用方法,支持版本和服务分组,支持项目隔离
  • 2,客户端重试机制,可以配置次数和间隔时间
  • 3,客户端线程池
  • 4,服务端可以平滑无缝升级而不影响客户端的使用

兼容Dubbo就必然要使用Spring框架,那我们就直接上Spring Boot好了,号称Spring Boot为微服务开发而生,一步到位,将Thrift跟Spring Boot整合。

版本和服务分组可以通过Kubernetes的Service的Label来实现,我们客户端在查找服务的时候通过这两个标签再加上接口类的Label来定位Service的Cluster IP,这里不直接使用Service名称来调用服务的原因是通过Label查询Servcie更加灵活一些,Service的名称不受限制,随时可以启动一个带有相同Label的新Service来替换旧的Service.
项目隔离可以用Kubernetes的namespace来实现,一个namespace是一个项目,当然项目之间也可以互相调用,默认情况下是整个Kubernetes集群的服务都是可以被调用到的如果在没有指定namespace的情况下。

客户端重试机制用代理Thrift连接的方式来实现,在连接或接口方法调用异常时发起重新连接,参考:https://liveramp.com/engineering/reconnecting-thrift-client/

客户端连接池是由于在WEB项目中每次用户发起请求是在一个独立的线程中,而Thrift的Client Socket连接不是线程安全的,因此要为每个用户准备一个Socket连接,有点像数据库的连接池,这个可以用apache的commons pool2来实现,这个有很多网友的文章可以参考,本文就不在赘述了。

服务端平滑升级可以使用Kubernetes的Kubectl rolling-update来实现,它的机制是先创建一个RC,然后新建一个新版本Pod,停掉一个旧版本Pod,逐步来完成整个RC的更新,最后删除旧的RC,把新的RC名称改为旧的RC名称,升级过程如下图:

这里会有一个问题,因为有一个时间段会新旧RC共存,由于Service是基于RC的Label建立的,那过来的请求是不是会得到两种结果?


如果是的话要防止这样的情况发生就要像上面说的,将整个Service替换,先启动一个新的Service跟旧的Service有相同Label,然后删除旧的Service以及RC,在发生服务请求的时候Thrift Client在找不到旧的服务的时候根据Label重新查找Service就会切换到新的Service上。

下面展示一下大概的实现及使用方法,假设你熟习Kubernetes或者简单了解,熟习Docker。

服务端

配置


    <bean class="io.masir.testcloud.thrift.HelloImpl" id="helloImpl"/>
    <bean class="io.masir.testcloud.thrift.ThriftSpringProviderBean" init-method="init" id="providerBean">
        <property name="serviceInterface" value="io.masir.testcloud.thrift.HelloService"/>
        <property name="serviceVersion" value="1.0.0"/>
        <property name="serviceGroup" value="testServiceGroup"/>
        <property name="target" ref="helloImpl"/>
    </bean>

ThriftSpringProviderBean核心代码 这是Thrift和Spring整合的核心代码,可以借鉴其它网友的Thrift Spring实例。


public class ThriftSpringProviderBean  extends Thread {
 

    private int port = 10809;
    private String serviceInterface;
    private String serviceVersion;
    private String serviceGroup;
    private Object target;
 
    public void run() {
        try {
            TServerSocket serverTransport = new TServerSocket(getPort());
            Class Processor = Class.forName(getServiceInterface() + "$Processor");

            Class Iface = Class.forName(getServiceInterface() + "$Iface");

            Constructor con = Processor.getConstructor(Iface);

            TProcessor processor = (TProcessor) con.newInstance(getTarget());

            TBinaryProtocol.Factory protFactory = new TBinaryProtocol.Factory(true, true);
            TThreadPoolServer.Args args = new TThreadPoolServer.Args(serverTransport);
            args.protocolFactory(protFactory);

            args.processor(processor);
            TServer server = new TThreadPoolServer(args);
            logger.info("Starting server on port " + getPort() + " ...");
            server.serve();
        } catch (TTransportException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
    public void init() {
        start();
    }
 
    public String getServiceInterface() {
        if(serviceInterface.endsWith(".Iface")){
            serviceInterface = serviceInterface.replace(".Iface","");
        }
        return serviceInterface;
    }

}

客户端

考虑到Kubernetes是有负载和服务发现的功能,那我们如何跟Thrift整合在一起使用是我们要解决的问题

配置


    <bean class="io.masir.testcloud.thrift.ThriftClientBeanProxyFactory">
        <property name="k8sAPIServer" value="http://100.0.1.5:8080/"/>
        <property name="interfaceName" value="io.masir.testcloud.thrift.HelloService"/>
        <property name="version" value="0.0.1"/>
        <property name="group" value="thrifttest"/>
    </bean>

k8sAPIServer 是Kubernetes的API地址,用来根据 group、version、interfaceName 三个参数查找服务的集群地址

ThriftClientBeanProxyFactory 的实现请参考 http://blog.csdn.net/muyuxuebao/article/details/51556066  ,包括重新机制也有了。

另外推荐一个Kubernetes Api访问的Java组件,非常好用和灵活


        <dependency>
            <groupId>io.fabric8</groupId>
            <artifactId>kubernetes-client</artifactId>
            <version>1.4.14</version>
        </dependency>

生成Image

服务的Dockerfile

FROM  registry2.io/public/java:7
Copy jn-boot-0.0.1.jar /jn-boot.jar
EXPOSE 10809
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo Asia/Shanghai > /etc/timezone
ENV TZ Asia/Shanghai
ENTRYPOINT   java -jar /jn-boot.jar

消费者Dockerfile

FROM  registry2.io/public/java:7
COPY jn-boot-client-0.0.2.jar /jn-boot-client.jar
EXPOSE 10809
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo Asia/Shanghai > /etc/timezone
ENV TZ Asia/Shanghai
ENTRYPOINT   java -jar /jn-boot-client.jar

需要有两个地方注意一下,使用Copy,每次都要覆盖拷贝到Image中,另一个是日期应该放在基础Image中,Build生成Image后Push到我们Registry中。

部署到Kubernetes

程序开发或者说开发思路基本实现了,下面就是部署上线测试,Kubernetes的Pods基于Docker运行,那就会用到Registry,一个Pod会是一个Docker容器,所以Kubernetes的流程是从Registry中拿到Image然后启动一个Dokcer容器,由于我们配置的Registry是有权限的,所以要先生成Kubernetes的Secrets,

kubectl create secret docker-registry registry2key --docker-server=registry2.io --docker-username=admin --docker-password=1 --docker-email=[email protected]163.com --namespace=thrift-demo

然后在yaml中配置:

apiVersion: v1
kind: ReplicationController
metadata:
  name: thrift-c
  namespace: thrift-demo
spec:
  replicas:1
  selector:
    app: thrift-c
  template:
    metadata:
      name: thrift-c
      labels:
        app: thrift-c
    spec:
      containers:
      - name: thrift-c
        image: registry2.io/thrift/thrift-c:0.0.2
        imagePullPolicy: Always
        ports:
        - containerPort: 9091
      imagePullSecrets:
        - name: registry2key

注意里面的 imagePullSecrets registry2key

{
    "kind": "Service",
    "apiVersion": "v1",
    "metadata": {
        "name": "thrift-c-app",
        "namespace": "thrift-demo"
    },
    "spec": {
        "selector": {
            "app": "thrift-c"
        },
        "ports": [
            {
                "protocol": "TCP",
                "port": 9091,
                "targetPort": 9091
            }
        ]
    }
}

Kubernetes的配置网上有很多,大家分头去参考,这里不过多说明,这是一个Thrift客户端的Kubenetes RC和Service配置,在Kubernetes Master云主机上通过Kubectl运行并启动这个RC

另外还需要部署Thrift服务端的RC、Service,如图:

(请注意服务端的Service的Label)

下面是Replication Controllers

调用测试,查看服务的访问地址,我们的客户端服务使用的是Nodeport,查看Nodeport的方式,或者在Dashboard上查看

然后通过Kubernetes集群中的任意一台机器加上NodePort端口就可以访问我们的Thrift客户端服务了。

在本文中我们可以看到使用了大量的Kubernetes特性,服务发现、服务负载(基于Service)、滚动升级等等,其中服务发现是在我们添加了Pods数量后会被Service自动发现,包括后面要说的自动扩容,而负载就是Service会在所有Pods中通过某种机制选择某个Pod来调用,事实上还有很多Kubernetes的特性等待我们去使用和发掘,Kubernetes真是一个得力的容器助手,希望我们能把它用好,也希望Kubernetes越来越完善。

在下文中我们将说一说服务的发布,总不能都通过IP+NodePort的方式来访问所有WEB服务吧,一定要有一个完美的合适的解决办法,那会是什么呢。。。

时间: 2024-10-10 17:19:36

微服务实践之路--RPC的相关文章

微服务实践之路-起始

由于各种原因,公司要对现有的营销产品进行微服务化,如果可以,则对公司所有产品逐步进行微服务化. 而本人将作为主力去探索这条路,很艰难,但干劲十足.整个过会记录下来,以便以后查阅. 感谢公司!感谢领导! 相关书籍 https://book.douban.com/subject/26772677/ 技术栈 Spring cloud redis RabbitMq

Spring Cloud微服务实践之路- Eureka Server 中的第一个异常

EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE

微服务实践:什么是微服务

微服务实践:什么是微服务 微服务 微服务是一种软件架构风格,该词来源于Martin Fowler 的一篇博客.他在自己博客中阐述了微服务六个特点 一组小的服务.微服务主张把单体应用拆开成一个个小的服务单元. 基于业务能力.比如购物网站,可以有订单服务.商品服务.推荐服务等等. 微服务运行在独立的进程.比如现在的容器技术,容器可以部署在物理机上,以进程的方式进行横向扩展. 轻量级通信机制.比如HTTP通讯协议&JSON消息格式. 独立部署.每个团队在应用交付过程中,独立地开发.测试和部署自己的微服

微服务实践(总)-原文

本系列文章为 dockone.io 首发,转载请标明出处,以示尊重!! http://dockone.io/people/hokingyang   希望读者通过本系列文章对微服务优缺点有一个比较好的理解,以及何时使用这种架构.也许微服务架构比较适合你的应用.也许你正在开发一个大型.复杂单体式应用,日常开发和部署经验非常缓慢和痛苦,而微服务看起来是远方一个极乐世界.幸运的是,有可以参考的脱离苦海的策略,本篇文章中,我将描述如何逐步将单体式应用迁移到微服务架构. 本系列七篇文章列表如下: 微服务实战

.Net微服务实践(五)[服务发现]:Consul介绍和环境搭建

目录 介绍 服务发现 健康检查.键值存储和数据中心 架构 Consul模式 环境安装 HTTP API 和Command CLI 示例API介绍 最后 在上篇.Net微服务实践(四)[网关]:Ocelot限流熔断.缓存以及负载均衡中介绍Ocelot的限流.熔断.缓存.负载均衡以及其他一些特性,Ocelot的基本配置和功能都已经介绍完了.本篇我们会介绍服务发现Consul. 介绍 Consul是一款简单.易用.可伸缩性强的服务治理系统.主要核心功能有:服务发现.健康检查.键值存储和多数据中心. 服

京东、宅急送的微服务实践分享(下)| 架构师小组交流会

架构师小组交流会是由国内知名公司技术专家参与的技术交流会,每期选择一个时下最热门的技术话题进行实践经验分享. 第一期:来自沪江.滴滴.蘑菇街.扇贝架构师的 Docker 实践分享 第二期:来自滴滴.微博.唯品会.魅族.点评关于高可用架构的实践分享 第三期:京东.宅急送的微服务实践分享(上)第三期小组交流会邀请到了国内电商领头羊京东.宅急送技术负责人,在上篇京东.宅急送的微服务实践分享(上)中他们介绍了各自产品的微服务实践,本次他们就 API 网关的设计.服务的 Docker 化.服务测试.持续集

Java微服务实践—Spring Boot系列

Java微服务实践-Spring Boot系列网盘地址:https://pan.baidu.com/s/1aMqPO4pXLeXDHvRuze-JWw 密码: j62z备用地址(腾讯微云):https://share.weiyun.com/c74335d7e383158ee3c4aaf193d471ed 密码:r5gqsk 原文地址:http://blog.51cto.com/12218470/2088359

免费领取 | 微服务实践沙龙-上海站 大咖演讲资料分享

本文来自网易云社区. 9月1日,网易云联合谐云在上海InnoSpace举办了"微服务实践沙龙",邀请到了携程和蚂蚁金服等微服务的先行者,共同分享了落地实践过程中总结的干货经验.感谢讲师和上海小伙伴们的支持,这里将演讲资料分享给大家.网易云还会继续举办易经布道系列的活动,欢迎大家的关注和参与~ 议题1:配置中心,让微服务更『智能』 讲师:携程框架架构研发部技术专家 宋顺 宋老师的PPT暂时不能公开,这里分享他写的文章给大家学习:配置中心,让微服务更"智能" 议题2:微

2019年微服务实践第一课,网易&amp;谐云&amp;蘑菇街&amp;奥思技术大咖深度分享

微服务的概念最早由Martin Fowler与James Lewis于2014年共同提出,核心思想是围绕业务能力组织服务,各个微服务可被独立部署,服务间是松耦合的关系,以及数据和治理的去中心化管理.微服务能够帮助企业应对业务复杂.频繁更新以及团队规模庞大带来的挑战,实现IT对业务创新的驱动. 1月12日,网易云主办的"微服务实践沙龙"将走进深圳,邀请业界微服务的先行者,分享落地实践过程中总结的干货经验. 报名地址:点击报名 时间:2019年1月12日 13:30-17:00 地点:广东