当初创建简书账号的时候曾立下宏愿,希望保持周更,无奈现实残酷,整个5月都处于忙忙碌碌的状态,居然令这个本来并不算太宏伟的目标难以为继,最终导致5月份交了白卷!【好吧,我承认,是我意志不够坚定,太懒了,;)】

最终的负罪感导致了本文的诞生,同时也意味着一个新坑的开启。作为Vert.x的使用者,我会定期更新获得的经验,希望为同好提供一些小小的帮助,扫除前进的障碍。同时,作为一个懒人和见异思迁者,事先声明,我没有办法保证我的兴趣不会发生转移,所以,我也不知道这个坑能开多久,望大家注意。

那么,让我们进入主题。

HTTPS请求

这是在跟某运营商的NB-IOT平台对接时解决的问题,其实最终的整个代码并不复杂,类似下面(采用双向认证方式):

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也变得流行起来,但有一点开发经常忽视的是直接将生成JWT要用到的证书包含在源代码中。这一点其实是非常不妥的,有潜在的安全问题。

一个常识是:开发测试用的证书和产品环境的证书要分开,由不同的人来负责管理!

比如,在dgate中,产品环境的证书由运维通过下面的环境变量指定(例子):

export dgate_key_store=./test1.jceks
export dgate_key_type=jceks
export dgate_key_password=test123

在生成JWT对象时,从环境变量里直接拿这些值,供未来使用。

HTTP Form/Upload请求

这是在实现dgate遇到的需求,小伙伴们强烈要求支持Form提交和文件上传,于是就有了RelayHandler的诞生。它的实际作用就是请求的透传,即将请求内容原封不动的搬到后端服务那里去。

实现很简单,看代码就知道,但在编写测试代码时就遇到了需要发起Form和Upload的问题。这个需求要是放在现在很简单,因为Vert.x从3.4开始提供了WebClient模块,用它可以很轻易的实现这样的需求。

可在当时,这个模块还没有出来咧!那就只能自己动手了,因为并没有那么麻烦,本质上就是按照HTTP协议的要求,向Request写入对应格式的内容就行了。这一点可以从RequestUtils的form和upload方法实现里看出来。

UDP的Socket

这是在另一个项目中遇到趣事,其实既不是需求也不是问题,而是锦上添花,方便调试。在这个项目中,我们用Vert.x实现了一个UDP Server,用户的设备会直接向这个Server发包。在一定的条件下,如时钟不对,Server会向设备发起一个校时命令。

作为负责任的开发,我们当然不会依赖用户的硬件设备来进行调试啦!也就是说,我们自己是实现了一个MockClient的,它完全实现了设备和服务器的通信协议。内测没问题之后就到了联调阶段了,可偏偏我们已经发出了校时命令(终端有输出),但硬件却说没有收到!

要命的是,通过Linux的tcpdump来抓包,居然在UDP Server的地址和端口上没有抓到对应的包!这真是浑身是嘴也说不清啊!而且,自己写的Mock与Server总是能够顺畅的通信!

遇到这么个怪问题那就不得不上网络调试的终极大杀器Wireshark了,看看到底发生了什么。很快,问题定位出来了,下发命令确实已经发出,只不过是从另一个端口发出去的。这是因为写代码时,觉得UDP反正就没有连接的概念,只要有对方的地址信息那就直接发送过去就好了。于是,在发送前重新创建了一个DatagramSocket实例,通过它直接发出去了。

实际的修改也很简单,用UDP Server对应的那个DatagramSocket实例发送就好了。最后的结果当然是皆大欢喜。

与Ignite的集成

我之前不止一次的表达出对于Ignite的喜爱,觉得它比Redis要好(注:最近有所改变,因为Redis提供了对于HpyerLogLog开箱即用的支持,而Ignite则貌似没有。)。这次,在项目中终于采用了以它为基础的Vert.x集群方案。

整个集成和使用并不复杂,这是我们做过的事情:

  1. 引入依赖和ignite.xml
  2. 在Launcher中强制设置为Cluster模式,简化命令行启动:
@Override
public void beforeStartingVertx(VertxOptions options) {//Force to use cluster modeoptions.setClustered(true);
}
  1. 为了方便后续获得配置里的缓存,需要对ignite在启动时进行初始化,于是我们写了一个工具类,其主要用处就是在启动前从Vert.x中获得Ignite并保存起来,方便后续按名字获取缓存时直接使用。初始化代码如下(同样是在Laucher里面,但由于要获得Vertx实例,故放在afterStartingVertx里):
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自写压测代码时也需要注意:

  1. 对于UDP服务器来讲,注意设置足够大小的接收缓存,否则会导致Client的包被丢弃,且没有任何错误提示。表象就仿佛服务器挂了或没有能力处理一样,而实际的压力其实远远没有达到服务器的极限。参见下面的代码:
vertx.createDatagramSocket(new DatagramSocketOptions().setReceiveBufferSize(UDP_RECEIVE_BUFFER_SIZE).setSendBufferSize(UDP_SEND_BUFFER_SIZE)).listen(..., "0.0.0.0", asyncResult -> { ... }
  1. 在压测发起端,避免为每个Client生成一个长时间存在的周期Timer。相反,使用一个周期Timer,但针对每个Client生成一个一次性的Timer,模拟随机发送。同时,要记得用完之后立即释放。类似的结构如下:
vertx.setPeriodic(20000, tid -> {mockClients.forEach((uid, socket) -> {vertx.setTimer(ThreadLocalRandom.current().nextInt(10, 10000), id -> {logger.info("...", uid);send(...);vertx.cancelTimer(id);});});
});

自此,这段时间积压下来,觉得有必要写写的内容已经全部倾倒完毕,敬请期待下一期(如果真有的话,;))。

Vert.x入坑须知(2)相关推荐

  1. Vert.x入坑须知(3)

    随着Vert.x进化到3.5.0,本系列也迎来了新篇章. CORS的新变化 对于CORS,搞Web开发(不论你是前端,还是后端)的同志应该不陌生,尤其是如今微服务盛行的时代,CORS更是最常用的配置项 ...

  2. 剑与远征服务器维护,剑与远征:海岛版本入坑须知注意点,少走弯路!

    哈喽,大家好!欢迎大家收看,不肝不游戏!我是疯子~ 最近疯子后台私信收到挺多小伙伴,想要一些新手向的攻略.等等!别问"这游戏还有人玩"的睿智提问,<剑与远征>能玩到现在 ...

  3. 我的世界java萌新须知_《原神》萌新入坑须知(全网最全,50个玩原神必备诀窍)...

    1.收集神瞳要标点. 如果你记忆力不好,也不够肝,那么在收集每一个风神瞳和岩神瞳的时候要标点,但是地图标点有100个上限,所以,131个岩神瞳收集,建议在米哈游社区的模拟器上标点.1.1版本有查找器, ...

  4. 万象物语一直显示服务器更新,《万象物语》新手入门攻略 入坑必看指南

    一.入坑须知 不管是这个游戏哪方面吸引了你决定入坑,想长期玩下去并享受到游戏的乐趣,请将这个游戏作为『休闲策略』游戏来对待. ※由于游戏内容尚未完善,大量玩法还在开发中,无体力的设定以及抽奖概率.运营 ...

  5. 新兵入坑 ——回顾NOIP2018

    新兵入坑--回顾NOIP2018 在这金秋时节,一年一度的NOIP来了,经过一年的学习,顺利通过初赛后,终于要展现新兵真正的技术了. 11月10日,所有竞赛班的同学乘大巴前往广州二中,一顿美味的午餐过 ...

  6. 发布开源框架到CocoaPods入坑指南

    个人原文博客地址: 发布开源框架到CocoaPods入坑指南 在开发过程中一定会用到一些第三方框架, 只要安装了CocoaPods, 然后通过pod install命令, 就可以集成框架到项目中了 可 ...

  7. 资源 |“从蒙圈到入坑”,推荐新一波ML、DL、RL以及数学基础等干货资源

    向AI转型的程序员都关注了这个号☝☝☝ 编译 | AI科技大本营(rgznai100) 参与 | suiling 此前营长曾发过一篇高阅读量.高转发率,高收藏量的文章<爆款 | Medium上6 ...

  8. 魔兽世界多玩服务器位置,选择服务器也有大学问?新手入坑《魔兽世界》该在哪里“扎根”...

    <魔兽世界:暗影国度>开服至今已经五个多月了,圈内圈外都在讨论新版本的话题,不少萌新与老玩家都选择了在这个版本中加入探索暗影界的行列.但面对茫茫多的区服,许多玩家都犯起了"选择困 ...

  9. 2020《图像分割》从入坑到出坑指南

    本文经授权转载自机器之心(almosthuman2014),来源:medium,作者:Jakub Czakon,编译:小舟.Racoon.张倩,未经授权禁止二次转载与摘编. 本文长度为2400字,建议 ...

最新文章

  1. Java数据结构——有序链表
  2. 团队软件库_新环节!新设备!新软件! ——天津市物流大赛创新大揭秘!
  3. TXSQL企业级特性揭秘:加密与审计
  4. python有大括号吗_只有我一个人觉得Python取消了大括号而显得结构更加混乱了吗?...
  5. spss22.0统计分析从入门到精通_数据分析最全资料:SPSS/MATLAB/SQL/SAS/EXCEL经典教材+视频教程,快速入门!...
  6. @ta,一起过节吧!
  7. eth java,一个轻量级的Java实现的ETH库
  8. 设置 CSDN 博文里代码块的颜色
  9. java creat sql,java 实体类 生成 create sql
  10. RTP载荷H264视频流
  11. python verilog就业_[持续演进] 应届生 FPGA 就业,一点微小的看法
  12. 计算机相关的著名的期刊和会议
  13. nginx代理百度地图,实现内网展示百度地图
  14. 刘德华郑秀文喜剧大片《魔幻厨房》DVD国语中字
  15. uniapp H5端使用高德地图完成路线规划
  16. 2021-01-22学习记录 || 通过二维数组初始化窗体并进行代码重构
  17. 谷歌colab“几键”运行图像超分辨率模型-ESRGAN,操作详解
  18. 常见的压力面试题及面试技巧
  19. 阿里云ECS服务器CentOS6.5vnc连接时报错Failed to connect to socket /tmp/dbus-xxxxxxx: Connection refused
  20. matlab产生均匀白噪声,各种分布白噪声的产生matlab.pdf

热门文章

  1. kpu 处理器_首轮融资即估值过亿,中科驭数用全新专用计算架构让芯片也能“私人订制”...
  2. HH的项链 HYSBZ - 1878 (莫队/ 树状数组)
  3. layui jquery ajax,url,type,async,dataType,data
  4. php-常量、运算符
  5. Doctype的作用
  6. 逻辑斯蒂(logistic)回归深入理解、阐述与实现
  7. 如何设置python的编码格式为utf-8
  8. linux下libpcap抓包分析
  9. c#中将HTML文件转换成PDF文件
  10. 使用函数指针实现父类函数调用子类函数的两种方式