微服务实践之路--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=xxxx@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服务吧,一定要有一个完美的合适的解决办法,那会是什么呢。。。
微服务实践之路--RPC的更多相关文章
- Openstack+Kubernetes+Docker微服务实践之路--RPC
重点来了,本文全面阐述一下我们的RPC是怎么实现并如何使用的,跟Kubernetes和Openstack怎么结合. 在选型一文中说到我们选定的RPC框架是Apache Thrift,它的用法是在Ma ...
- SFDC 微服务实践之路 2016.12.10 杭州(整理)--转
原文地址:http://mp.weixin.qq.com/s/8cC4Ewt6yPjnxdYxuNZlFQ 微服务是什么? 微服务是一种细粒度(Fine-Grain)的SOA 或许在座的高朋了解过其概 ...
- Openstack+Kubernetes+Docker微服务实践之路--选型
上一篇博文中我们选定Openstack做为我们的基础设施IAAS平台,本文将明确我们用什么技术做为微服务平台的技术选型. 经过对微服务的特性总结和添加一些个性需求后对微服务平台的基本要求 PRC远程调 ...
- Openstack+Kubernetes+Docker微服务实践之路--基础设施
近两年微服务在网上聊的如此的如火如荼,备受关注,我在去年下半年的一个项目中也用到了阿里云的EDAS.HSF,深有体会,最近时间空闲出于好奇,决定一探究竟打算自建微服务平台,基本实现EDAS.HSF的功 ...
- Spring Cloud微服务实践之路-起始
由于各种原因,公司要对现有的营销产品进行微服务化,如果可以,则对公司所有产品逐步进行微服务化. 而本人将探索这条路,很艰难,但干劲十足.整个过会记录下来,以便以后查阅. 感谢公司!感谢领导! 相关书籍 ...
- Openstack+Kubernetes+Docker微服务实践之路--弹性扩容
服务上线就要顶的住压力.扛的住考验,不然挨说的还是我们这帮做事的兄弟,还记得上图这个场景吗 老办法是服务集群部署,但总归有个上限,之前跟阿里合作的时候他们有个弹性计算可以通过设置CPU的阀值来动态扩展 ...
- Openstack+Kubernetes+Docker微服务实践之路--服务发布
结合上文,我们的服务已经可以正常运行了,但它的访问方式只能通过服务器IP加上端口来访问,如何通过域名的方式来访问到我们服务,本来想使用Kubernetes的Ingress来做,折腾一天感觉比较麻烦,I ...
- Openstack+Kubernetes+Docker微服务实践之路--Kubernetes
经过几番折腾终于搞定Kubernetes了,我们要在Openstack上部署Kubernetes集群,使用最新工具Kubeadm来安装,由于不能直接访问Kubernetes的源,我们需要一台可以穿墙的 ...
- Openstack+Kubernetes+Docker微服务实践之路--Docker和Registry2
渐入佳境,我们开始比较具体的工作,由于Docker是一个基础组件,所以本文的主题是Docker和Registry2. 底层系统基于Centos7,先在一台云主机上安装Docker,Docker的安装非 ...
随机推荐
- 在sublime text 3中安装中文支持 分类: C_OHTERS 2015-04-24 22:04 229人阅读 评论(0) 收藏
1.安装package control 使用control+~打开终端,然后输入以下内容并确定: import urllib.request,os;pf='Package Control.subli ...
- 29、从零写USB摄像头驱动之通过urb接受数据后上报数据是函数中fid的作用
原因分析如下: 视频数据是由一帧一帧数据组成,为了防止数据错乱,会给每一帧数据分配一个frameid,从第0帧开始,接着是第1帧,接着又是第0帧这样交错进行的,对usb摄像头来说每一帧数据来源于多个包 ...
- embed-it_Integrator memory compile工具使用之一
embed-it_Integrator memory compile工具使用之一 主要内容 使用Integrator compile memory 使用Integrator 对比筛选适合的memory ...
- C#操作SqlServer MySql Oracle通用帮助类
C#操作SqlServer MySql Oracle通用帮助类 [前言] 作为一款成熟的面向对象高级编程语言,C#在ADO.Net的支持上已然是做的很成熟,我们可以方便地调用ADO.Net操作各类关系 ...
- HTTP请求头与响应头
http://m.blog.csdn.net/article/details?id=48918857 本篇文章中,将学习一下HTTP请求头与响应头的知识. 一.HTTP头引入: 正确的设置HTTP头部 ...
- iOS开发之Quartz2D 六 绘制UIImageView
#import <UIKit/UIKit.h> @interface XMGImageView : UIView /** <#注释#> */ @property (nonato ...
- C运行时库(C Run-time Library)详解(提供的另一个最重要的功能是为应用程序添加启动函数。Visual C++对控制台程序默认使用单线程的静态链接库,而MFC中的CFile类已暗藏了多线程)
一.什么是C运行时库 1)C运行时库就是 C run-time library,是 C 而非 C++ 语言世界的概念:取这个名字就是因为你的 C 程序运行时需要这些库中的函数. 2)C 语言是所谓的“ ...
- 有关下拉列表、复选框、单选按钮、iframe等jquery处理方法
1.jquery验证复选框互斥选项,代码如下: //验证复选框中的互斥选项 function checkData(name, val1, val2){ //获取所有checkbox值 var chec ...
- ssh登录很慢,登录上去后速度正常问题的解决方法
1. DNS反向解析的问题 OpenSSH在用户登录的时候会验证IP,它根据用户的IP使用反向DNS找到主机名,再使用DNS找到IP地址,最后匹配一下登录的IP是否合法.如果客户机的IP没有域名,或者 ...
- 配置Apache支持PHP5
环境:window 7.Apache/2.2.19 (Win32) PHP/5.2.9-1 1.配置server名称 将里面的 #ServerName localhost:80 凝视去掉就可以. 又一 ...