如何编写高质量的Java代码

Java代码安全规范

本文目的

向Nasa的《NASA的10条代码编写原则》学习,目的有二:一是约束Java代码的使用、规避较高危的代码,二是code review更易识别。有很多优秀的JAVA规范、如《阿里巴巴JAVA开发手册》等都介绍了编码的一些原则、编程风格等,本文不再赘述;这里更多介绍生产环境易出故障的javacode。

提高生产环境系统的稳定性、可用性并非代码一项,需要有一套结构化的体系、从系统运营角度去通盘考虑;代码是系统基石之一。

故障分析

代码危险程度很难量化分析,从生产环境的故障着手分析。笔者统计了新美大近两年半对交易额有较大损失影响的线上S1故障(日交易额影响比大于5%),发现WEB服务影响最大的是DB、其次CACHE,还有些重复打款、zk重连、专线故障、前端轮询、内存不足、LOG问题等,比较共性的是:资源层级越底层、对交易额的损失越大。因此代码危险程度可以从代码对资源影响程度去衡量。

资源分析

Nasa的编写原则面向航空场景的C语言,与互联网WEB场景相比、1)服务远程通讯更少2)偏硬件打交道得多,对低能耗和安全的要求比较高,既非cpu密集型、也非io密集型 3)代码工程浩大。因此Nasa主要集中在mem及代码工程上。NASA规范总结有3条:限制内存动态分配、限制指针层级、优化C编译器做集成和静态检查。

互联网WEB场景,普通service属于cpu密集型,cpu及network资源容易出现瓶颈;而像mysql、redis等存储系统对碰盘i/o、cpu、network的要求都很高。JAVA耻笑自动档内存的C、JVM在解放程序猿对内存管理的同时,也因将内存管理交给了JVM、比C更容易出现不明所以的故障,当你越不了解它、也就越难真正驾驭它。本文主要针对JAVA互联网WEB、规范单机的三处资源:内存、CPU、网络

本文分类的原则、是从java单机的视角去看待资源(cpu、mem、i/o、network),例如mysql的吐吞率大的sql归在Network资源方面。

安全条目

QPS

  • JOB、MQ、RPC(写入场景及读QPS较高场景)需要限制请求QPS及响应队列,以便保护Write及Read资源。
  • 论询导致后台QPS过大,QPS可能超出人预期的几倍、甚至上百倍;建议有专门的长链集群。
  • 活动Push、大促、秒杀类活动导致后台QPS过大,后端服务容量常被打满、甚至压垮下游核心服务;建议有专门的活动运营机制隔离此类应用场景。

CPU

  • Future、RPC、Redis、Http Connection、MySQL Connection等远程调用必需明确设置Network Timeout Time,防止造成线程积压、增加cpu负载。
  • 大对象、 大集合的序列化耗时明显。几个思路:集合拆分与并行处理、byte代替明文存储、选择合适的序列化协议和框架。

Memory

  • 禁止使用无界的List与Map集合、必须限制MaxSize,防止堆泄漏、FGC。
  • Local Cache、Buffer(MQ、Log、Thrift)、Thread Local等必需明确限制MaxSzie,防止引发FullGC及OOM。(本质是无界集合、突出local cache&buffer的使用场景)
  • 禁止使用自定义线程池、提供统一线程池解决方案(监控、分布式限流、动态调整线程池大小、回收thread local),防止应用线程池失去监管、带来潜在危害(在方法区动态创建thread pool属于常见错误之一)
  • 在线程池的场景下使用Thread Local在回收前需要一个兜底清除的节制,防止线程复用Thread Local反复使用的风险
  • 禁止JOB一次性全量操作、必须取一批、处理一批,防止引发潜在的堆溢出问题
  • 慎用DirectBuffer、注意内存泄漏风险(Netty i/o线程及业务线程)XX:MaxDirectMemorySize=1g
  • 慎用大对象,防止出现FGC、System Load过高、热点TPS过大

磁盘I/O

  • 禁止线上应用出现swap,防止产生I/O中断、秒级GC等风险,JVM明确swap size。出现swap建议深入排查原因看是否需要更换物理机

Network

  • 批量SQL必须Limit限制最大记录条数,防止产生Big Sql、影响MySQL连接数及吞吐率
  • 大表操作场景。禁止大表Join、select count分页方式,慎用order by与where查询场景,避免产生慢SQL、拖累MySQL性能。分页可用id偏移的方式代替"limit n,m"。 
  • 不准Redis对象超过4KB,防止热点KeyValue TPS过高、引发性能问题 
  • 建议提供统一封装的HttpClient解决方案,防止连接池反复创建、未关闭连接、未设置超时时间、无访问链路监控等风险。

·       服务器TCP连接出现大量的TIME_WAIT、CLOSE_WAIT,占用大量fd、导致服务器不可用。优化思路大体是调整保活机制、快速回收,线上故障通过重启机器解决此类问题。

代码工程

  • 不准单类超过1000行代码,防止功能模块耦合、带来不可预知的代码修改危害。

Web安全 

OWASP TOP 10-2017(全球WEB安全10大安全问题排行榜):

  • A1-Injection
  • A2-Broken Authentication and Session Management
  • A3-Cross-Site Scripting (XSS)
  • A4-Broken Access Control
  • A5-Security Misconfiguration
  • A6-Sensitive Data Exposure
  • A7-Insufficient Attack Protection
  • A8-Cross-Site Request Forgery (CSRF)
  • A9-Using Components with Known Vulnerabilities
  • A10-Underprotected APIs

更多细节请详细访问:https://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project

附录

Redis网卡打满参照表

当热点key的QPS超过一定阈值会出现网卡打满的情况。现在redis集群是万兆网卡(10000Mbps),对照表如下: 

传输对象平均大小

打满万兆网卡的qps

打满千兆网卡的qps

备注

1KB

128w/s

12.8w/s

2KB

64w/s

6.4w/s

4KB

32w/s

4.2w/s

8KB

16w/s

1.6w/s

16KB

8w/s

8k/s

32KB

4w/s

4k/s

64KB

2w/s

2k/s

128KB

1w/s

1k/s

256KB

5k/s

500/s

512KB

2.5k/s

250/s

 将cache的大小限制在8k以下会比较安全一些。

参考

https://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project

https://blog.octo.com/en/the-evolution-of-bottlenecks-in-the-big-data-ecosystem/

https://github.com/eishay/jvm-serializers/wiki

http://www.cnblogs.com/sunxucool/p/3449068.html

发布了91 篇原创文章 · 获赞 7 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/Ture010Love/article/details/77618623