理论很丰满/落地很骨干-踩坑篇

还是那个徐东强2019-02-12 11:40:58

  1. 封装grpc

最初的思路:

服务端的service实现类上加个注解比如@RemoteService,所有被@RemoteService注解的service实现类上报。

客户端通过注解@GrpcReference装配远程的service实现类(用起来和@Autowire差不多),实际上被该注解@GrpcReference装配的对象,在客户端初始化的时候,设置为代理类,执行方法的时候,实际上是新建了一个客户端链接,然后将调用方法,请求参数等等都发送过去。

大概是下面这样:

想象很美好,实际不可行。

踩坑一:对于grpc而言,客户端的请求都是这样的

它的servcie都是IDL文件生成的,调用都是通过XXGrpc.xxBlockingStub来调用的,而且该类是一个final类型,无法动态代理。

纠结了好长时间,想了各种办法,最后,突然想通了,本身就是代理类的话,干嘛还代理,客户端启动的时候,直接初始化这个实例塞到这个对象的该字段中不就OK了。真是傻


踩坑二:由于要把客户端的调用封装到hystrix中。

这样才好比较之前http+json+hystrix和现在的grpc+hystrix的性能差。XXGrpc.xxBlockingStub这种本身就是动态代理的类,动态某方法,实际就是客户端请求call,想在这层外面再包装一层hystrix,不可行,因为该servcie是IDL文件自动生成的,再加上对grpc源码也不了解。

于是改变调用方式,调用方式 grpcServiceCaller.call(需要的参数); call内部是XXGrpc.xxBlockingStub.method这样,在call方法的外面包装一层hystrix。


踩坑三: xxx.call(需要的参数) 该方法的返回类型必然是一个T, 因为是一个共通的方法,但是由于我们内部调用的是 XXGrpc.xxBlockingStub.method ,对于具体的service返回类型已经明确了,难道需要 先把 结果responseObj转成 jsonStr, 再通过 JSON.parse(jsonStr, xxxClass.class)

对泛型真是了解的糊涂。本来就是运行时才能明确的类型,直接强转T 就可以了啊。傻起来真是没救。


2.http+protostuff+hystrix 主要是切换序列化的方式

客户端调用由于是通过restTemplate调用,确定客户端也已经加了消息转换器ProtostuffHttpMessageConverter。执行发现服务端失败。


踩坑四:服务端没有加该种类型的消息转换器,请求的时候将对象序列化成了protostuff,服务端接收到protostuff的时候,没有消息转换器,无法将protostuff反序列化。嗯很合理,加了如下


踩坑五:发现即使上面配置了,也没用。尴尬不尴尬。

于是debug,从spring mvc的请求入口DispatcherServlet开始到AbstractMessageConverterMethodArgumentResolver的readWithMessageConverters方法

看代码191行,这里的messageConverters的List是配置文件中配置的三个消息转换器,是分别是String,Json,ProtoStuff (字典顺序与配置无关)。当执行converter为jsonConverter的时候,195行的代码 genericConverter.canRead(targetType, contextClass, contentType)竟然为ture, 从而导致用fastjson来反序列化刚才的消息,无法解析,直接报错了。

但是客户端发送请求的时候,明明conent_type指名了application/x-protobuf,195行理论上应该为true才对。

debug发现,jsonConverter由于没有配置supportedMediaTypes,她会默认会所有的*/*,所有的content_type都会用fastjson来转换。于是配置文件中给jsonConverter配置上


3.http2+protostuff+hystrix

踩坑六:

这个厉害了。

发现自己对协议可以说 完! 全!不!了!解!

对tomcat 可以说 完! 全!不!了!解!  how to tomcat works

不知道,http作为应用层协议,各种http客户端底层,传输层怎么样都逃不过socket

不知道, 原来不止有Socket+ServerSocket 原来还有SSLSocket+SSLServerSocket

不知道, https= http+ssl/tls, 各种证书的生成,

更是 掉在http2的坑里,出不来。理论看起来,貌似明白了,一操作貌似不是这么回事呀。

完全白痴!


服务端 tomcat9才支持http2的请求。

升级tomcat? 光升级没用?

还要安装apr,ap-util,openssl,因为目前http2的实际使用场景中,只用于在https的场景下

还需要给tocmat的server.xml 放开8443的connector,配置秘钥路径,另外tomcat启动的时候,只有检查到有apr+放开了8443(秘钥路径存在)两个条件都满足,才能在启动日志中看到

tomcat 8443终于启动好了。https://xxxx.xx.xx.xx:8443


还不行,如何把服务放上去,一般的是war直接扔到tomcat的工作目录下,然后启动。

当然不是这么low的方法l咯。看下服务发布的流程 (以下为我印象笔记本中的笔记):

激动人心的时刻来了:用客户端工具来校验下http2的请求

结果如下:

curl 不支持http2---> 升级curl -->端口是8443的请求,通过查看tomcat的access日志,发现还是http1.1的请求

firfox(RestClient) 插件 ---> 请求8443的post请求 ---> 喜人,access日志中竟然显示http2协议


java客户端如何支持http2的请求?

1.restTemplate貌似不支持http2

2.okhttp3 貌似支持了,通过忽略https证书,https的请求终于也访问通了

然而  协议仍然是http1.1

看上面的199行,使用的Platform为Platorm,结果可能协议是http1.1,返回是null

目测要升级jdk --> 升级jdk到9,绝了 idea setup jdk,直接提示我指定的jdk路径不是jdk,看了下网上说9,10目录结构改了。目前还在坑里


最后,就是要厉害的人碰撞,碰撞再反弹回来,才知道自己有多弱鸡。


Copyright © 丰城计算器学习组@2017