当初建立简书帐号的时候曾立下宏愿,但愿保持周更,无奈现实残酷,整个5月都处于忙忙碌碌的状态,竟然令这个原本并不算太宏伟的目标难觉得继,最终致使5月份交了白卷!【好吧,我认可,是我意志不够坚决,太懒了,;)】java
最终的负罪感致使了本文的诞生,同时也意味着一个新坑的开启。做为Vert.x的使用者,我会按期更新得到的经验,但愿为同好提供一些小小的帮助,扫除前进的障碍。同时,做为一个懒人和见异思迁者,事先声明,我没有办法保证个人兴趣不会发生转移,因此,我也不知道这个坑能开多久,望你们注意。git
那么,让咱们进入主题。github
这是在跟某运营商的NB-IOT平台对接时解决的问题,其实最终的整个代码并不复杂,相似下面(采用双向认证方式):web
httpClient = vertx.createHttpClient(new HttpClientOptions() .setSsl(true) .setPfxKeyCertOptions(new PfxOptions().setPath("xxx.pkcs12").setPassword("xxx")) .setTrustStoreOptions(new JksOptions().setPath("xx.jks").setPassword("xxx")) .setVerifyHost(false));
基本上跟文档上的例子差很少,值得注意的地方就是最后一行代码:setVerifyHost(false),当时这个运营商的平台也处于测试状态,并无域名,是自签证书,设置为false,客户端不验证服务端证书的合法性,则可规避这一点,让整个开发能够不受影响继续下去。后端
随着微服务的流行,JWT也变得流行起来,但有一点开发常常忽视的是直接将生成JWT要用到的证书包含在源代码中。这一点实际上是很是不妥的,有潜在的安全问题。缓存
一个常识是:开发测试用的证书和产品环境的证书要分开,由不一样的人来负责管理!安全
好比,在dgate中,产品环境的证书由运维经过下面的环境变量指定(例子):服务器
export dgate_key_store=./test1.jceks export dgate_key_type=jceks export dgate_key_password=test123
在生成JWT对象时,从环境变量里直接拿这些值,供将来使用。网络
这是在实现dgate遇到的需求,小伙伴们强烈要求支持Form提交和文件上传,因而就有了RelayHandler的诞生。它的实际做用就是请求的透传,即将请求内容原封不动的搬到后端服务那里去。运维
实现很简单,看代码就知道,但在编写测试代码时就遇到了须要发起Form和Upload的问题。这个需求要是放在如今很简单,由于Vert.x从3.4开始提供了WebClient模块,用它能够很轻易的实现这样的需求。
可在当时,这个模块尚未出来咧!那就只能本身动手了,由于并无那么麻烦,本质上就是按照HTTP协议的要求,向Request写入对应格式的内容就好了。这一点能够从RequestUtils的form和upload方法实现里看出来。
这是在另外一个项目中遇到趣事,其实既不是需求也不是问题,而是锦上添花,方便调试。在这个项目中,咱们用Vert.x实现了一个UDP Server,用户的设备会直接向这个Server发包。在必定的条件下,如时钟不对,Server会向设备发起一个校时命令。
做为负责任的开发,咱们固然不会依赖用户的硬件设备来进行调试啦!也就是说,咱们本身是实现了一个MockClient的,它彻底实现了设备和服务器的通讯协议。内测没问题以后就到了联调阶段了,可恰恰咱们已经发出了校时命令(终端有输出),但硬件却说没有收到!
要命的是,经过Linux的tcpdump来抓包,竟然在UDP Server的地址和端口上没有抓到对应的包!这真是浑身是嘴也说不清啊!并且,本身写的Mock与Server老是可以顺畅的通讯!
遇到这么个怪问题那就不得不上网络调试的终极大杀器Wireshark了,看看到底发生了什么。很快,问题定位出来了,下发命令确实已经发出,只不过是从另外一个端口发出去的。这是由于写代码时,以为UDP反正就没有链接的概念,只要有对方的地址信息那就直接发送过去就行了。因而,在发送前从新建立了一个DatagramSocket实例,经过它直接发出去了。
实际的修改也很简单,用UDP Server对应的那个DatagramSocket实例发送就行了。最后的结果固然是皆大欢喜。
我以前不止一次的表达出对于Ignite的喜好,以为它比Redis要好(注:最近有所改变,由于Redis提供了对于HpyerLogLog开箱即用的支持,而Ignite则貌似没有。)。此次,在项目中终于采用了以它为基础的Vert.x集群方案。
整个集成和使用并不复杂,这是咱们作过的事情:
@Override public void beforeStartingVertx(VertxOptions options) { //Force to use cluster mode options.setClustered(true); }
if (ignite == null) { vertxInstance = vertx; ClusterManager clusterManager = ((VertxInternal) vertx).getClusterManager(); String uuid = clusterManager.getNodeID(); ignite = Ignition.ignite(UUID.fromString(uuid)); ... }
有了Ignite实例以后,其余的功能,如Read/Write Through、Cache事件等等,就是按照Ignite文档的指示来作了。这部分的内容已经属于Ignite的领域且文档也有详细的阐述,这里就再也不赘述。
做为服务器应用,怎么能不来一把压测来对其性能摸底呢?在实际过程当中,新手最容易忘记的问题就是:没有修改操做系统的最大可用句柄数,致使压力还没上来就进行不下去了。
除此以外,用Vert.x自写压测代码时也须要注意:
vertx.createDatagramSocket( new DatagramSocketOptions() .setReceiveBufferSize(UDP_RECEIVE_BUFFER_SIZE) .setSendBufferSize(UDP_SEND_BUFFER_SIZE)) .listen(..., "0.0.0.0", asyncResult -> { ... }
vertx.setPeriodic(20000, tid -> { mockClients.forEach((uid, socket) -> { vertx.setTimer(ThreadLocalRandom.current().nextInt(10, 10000) , id -> { logger.info("...", uid); send(...); vertx.cancelTimer(id); }); }); });
自此,这段时间积压下来,以为有必要写写的内容已经所有倾倒完毕,敬请期待下一期(若是真有的话,;))。