编码规范总结

编码规约

命名风格

  • 类名(除VO、DTO、PO外),方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格
  • 常量类以Constant结尾,枚举类以Enum结尾、异常类以Exception 结尾,测试类以测试的类的名称开始以 Test 结尾。常量、枚举属性命名全部大写,单词间用下划线隔开,力求语义表达完整清楚
  • 避免在子父类的成员变量之间、或者不同代码块的局部变量之间采用完全相同的命名
  • 在常量与变量命名时,表示类型的名词放在词尾,以提升辨识度,例:startTime / workQueue / nameList / TERMINATED_THREAD_COUNT。如果模块、接口、类、方法使用了设计模式,在命名时要体现出具体模式,例public class OrderFactory;public class LoginProxy;public class ResourceObserver
  • 各层命名规约:
    A)Service / DAO 层方法命名规约:
    1)获取单个对象的方法用 get 做前缀。
    2)获取多个对象的方法用 list 做前缀,复数结尾,如:listObjects
    3)获取统计值的方法用 count 做前缀。
    4)插入的方法用 save / insert 做前缀。
    5)删除的方法用 remove / delete 做前缀。
    6)修改的方法用 update 做前缀。
    B)领域模型命名规约:
    1)数据对象:xxxDO,xxx 即为数据表名。
    2)数据传输对象:xxxDTO,xxx 为业务领域相关的名称。
    3)展示对象:xxxVO,xxx 一般为网页名称。

常量定义

  • 不要使用一个常量类维护所有常量,要按常量功能进行归类,分开维护
  • 跨应用共享常量放置在二方库中

代码格式

  • 括号、保留字(if / for / while / switch / do)间的空格与换行
// 左大括号前加空格且不换行;左大括号后换行
if (flag == 1) {
System.out.println("world");
// 右大括号前换行,右大括号后有 else,不用换行
} else {
System.out.println("ok");
// 在右大括号后直接结束,则必须换行

// 注释的双斜线与注释内容之间有且仅有一个空格
String commentString = new String("demo");

// 在进行类型强制转换时,右括号与强制转换值之间不需要任何空格隔开
double first = 3.2D;
int second = (int)first + 2;
}

// 多个参数逗号后面必须加空格
method(args1, args2, args3);
  • 单行字符数限制不超过 120 个,超出需要换行,换行时遵循如下原则:
    1)第二行相对第一行缩进 4 个空格,从第三行开始,不再继续缩进,参考示例。
    2)运算符与下文一起换行。
    3)方法调用的点符号与下文一起换行。
    4)方法调用中的多个参数需要换行时,在逗号后进行。
    5)在括号前不要换行。
  • 单个方法的总行数不超过 80 行。 说明:除注释之外的方法签名、左右大括号、方法内代码、空行、回车及任何不可见字符的总行数不超过 80 行
  • 不同逻辑、不同语义、不同业务的代码之间插入一个空行以提升可读性,但是没有必要插入多个空行进行隔开。

OOP规约

  • 所有整型包装类对象之间值的比较全部使用 equals
  • BigDecimal
    1)值比较应使用 compareTo() 方法
    2)Double转BigDecimal
BigDecimal recommend1 = new BigDecimal("0.1");
BigDecimal recommend2 = BigDecimal.valueOf(0.1);
  • 基本数据类型与包装数据类型的使用标准:
    1)所有的 POJO 类属性、RPC方法的返回值和参数必须使用包装数据类型。
    2)所有的局部变量使用基本数据类型。
  • 定义POJO类时,不要设定任何属性默认值
  • 禁止在 POJO 类中,同时存在对应属性 xxx 的 isXxx() 和 getXxx() 方法。框架在调用属性 xxx 的提取方法时,并不能确定哪个方法一定是被优先调用到,神坑之一
  • 使用索引访问用 String 的 split 方法得到的数组时,需做最后一个分隔符后有无内容的检查,否则会有抛 IndexOutOfBoundsException 的风险
// 预期大于 3,结果等于 3 
String str = "a,b,c,,";
String[] ary = str.split(",");
System.out.println(ary.length);
  • 类内方法定义的顺序依次是:公有方法或保护方法 > 私有方法 > getter / setter 方法。当一个类有多个构造方法,或者多个同名方法,这些方法应该按顺序放置在一起

日期时间

  • 获取当前毫秒数:System.currentTimeMillis();而不是 new Date().getTime()
  • 使用枚举值来指代月份

集合处理

  • 使用集合转数组的方法,必须使用集合的 toArray(T[] array),传入的是类型完全一致、长度为0 的空数组。直接使用 toArray 无参方法存在问题,此方法返回值只能是 Object[]类,若强转其它类型数组将出现ClassCastException 错误
List<String> list = new ArrayList<>(2);
list.add("guan");
list.add("bao");
String[] array = list.toArray(new String[0]);
  • 使用工具类 Arrays.asList() 把数组转换成集合时,后台的数据仍是数组,不能使用其修改集合相关的方法,它的 add/ remove / clear 方法会抛出 UnsupportedOperationException 异常
 String[] str = new String[]{ "yang", "guan", "bao" };
 List list = Arrays.asList(str);
 第一种情况:list.add("yangguanbao"); 运行时异常。
 第二种情况:str[0] = "change"; list 中的元素也会随之修改,反之亦然。
  • 不要对正在被遍历的集合进行remove / add 操作
  • 遍历Map使用Map.forEach 方法,否则使用entrySet而不是 keySet 使用 entrySet 遍历 Map 类集合 KV,而不是 keySet 方式进行遍历。 说明:keySet 其实是遍历了 2 次,一次是转为 Iterator 对象,另一次是从 hashMap 中取出 key 所对应的 value。而
    entrySet 只是遍历了一次就把 key 和 value 都放到了 entry 中,效率更高

并发处理

  • SimpleDateFormat 是线程不安全的类,JDK8中可以使用DateTimeFormatter代替
  • 高并发时,同步调用应该去考量锁的性能损耗。能用无锁数据结构,就不要用锁;能锁区块,就不要锁整个方法体;能用对象锁,就不要用类锁。尽可能使加锁的代码块工作量尽可能的小,避免在锁代码块中调用 RPC 方法
  • 对多个资源、数据库表、对象同时加锁时,需要保持一致的加锁顺序,否则可能会造成死锁。线程一需要对表 A、B、C 依次全部加锁后才可以进行更新操作,那么线程二的加锁顺序也必须是 A、B、C,否则可能出现死锁
  • 在使用阻塞等待获取锁的方式中,必须在 try 代码块之外,并且在加锁方法与 try 代码块之间没有任何可能抛出异常的方法调用,避免加锁成功后,在 finally 中无法解锁
    说明一:在 lock 方法与 try 代码块之间的方法调用抛出异常,无法解锁,造成其它线程无法成功获取锁。
    说明二:如果 lock 方法在 try 代码块之内,可能由于其它方法抛出异常,导致在 finally 代码块中,unlock 对未加锁的对
    象解锁,它会调用 AQS 的 tryRelease 方法(取决于具体实现类),抛出 IllegalMonitorStateException 异常。
    说明三:在 Lock 对象的 lock 方法实现中可能抛出 unchecked 异常,产生的后果与说明二相同。
正例:
Lock lock = new XxxLock();
// ...
lock.lock();
try {
doSomething();
doOthers();
} finally {
lock.unlock();
}
反例:
Lock lock = new XxxLock();
// ...
try {
// 如果此处抛出异常,则直接执行 finally 代码块
doSomething();
// 无论加锁是否成功,finally 代码块都会执行
lock.lock(); 
doOthers();
} finally {
lock.unlock();
}
  • 在使用尝试机制来获取锁的方式中,进入业务代码块之前,必须先判断当前线程是否持有锁。 锁的释放规则与锁的阻塞等待方式相同
    说明:Lock 对象的 unlock 方法在执行时,它会调用 AQS 的 tryRelease 方法(取决于具体实现类),如果当前线程不
    持有锁,则抛出 IllegalMonitorStateException 异常。
正例:
Lock lock = new XxxLock();
// ...
boolean isLocked = lock.tryLock();
if (isLocked) {
try {
doSomething();
doOthers();
} finally {
lock.unlock();
} 
}
  • 并发修改同一记录时,避免更新丢失,需要加锁。要么在应用层加锁,要么在缓存加锁,要么在数据库层使用乐观锁,使用 version 作为更新依据。
    说明:如果每次访问冲突概率小于 20%,推荐使用乐观锁,否则使用悲观锁。乐观锁的重试次数不得小于 3 次。
  • 资金相关的金融敏感信息,使用悲观锁策略。
    说明:乐观锁在获得锁的同时已经完成了更新操作,校验逻辑容易出现漏洞,另外,乐观锁对冲突的解决策略有较复杂
    的要求,处理不当容易造成系统压力或数据异常,所以资金相关的金融敏感信息不建议使用乐观锁更新。
    正例:悲观锁遵循一锁二判三更新四释放的原则。

控制语句

  • 在一个 switch 块内,每个 case 要么通过 continue / break / return 等来终止,要么注释说明
    程序将继续执行到哪一个 case 为止;在一个 switch 块内,都必须包含一个 default 语句并且放在最
    后,即使它什么代码也没有。
  • 当 switch 括号内的变量类型为 String 并且此变量为外部参数时,必须先进行 null 判断。
public class SwitchString {
public static void main(String[] args) { method(null);
}
public static void method(String param) {
switch (param) {
// 肯定不是进入这里
case "sth":
System.out.println("it's sth");
break;
// 也不是进入这里
case "null":
System.out.println("it's null");
break;
// 也不是进入这里
default:
System.out.println("default");
} 
}
}
  • 在 if / else / for / while / do 语句中即使只有一行代码,也要采用大括号。
  • 三目运算符 condition ? 表达式 1:表达式 2 中,高度注意表达式 1 和 2 在类型对齐时,可能抛出因自动拆箱导致的 NPE 异常。
    说明:以下两种场景会触发类型对齐的拆箱操作:
    1)表达式 1 或 表达式 2 的值只要有一个是原始类型。
    2)表达式 1 或 表达式 2 的值的类型不一致,会强制拆箱升级成表示范围更大的那个类型。
Integer a = 1;
Integer b = 2;
Integer c = null;
Boolean flag = false;
// a*b 的结果是 int 类型,那么 c 会强制拆箱成 int 类型,抛出 NPE 异常
Integer result = (flag ? a * b : c);
  • .在高并发场景中,容易产生等值判断被“击穿”的情况避免使用“等于”判断作为中断或退出的条件。
  • 如果非使用 if()…else if()…else…方式表达逻辑,避免后续代码维护困难,请勿超过 3 层。超过 3 层的 if-else 的逻辑判断代码可以使用卫语句、策略模式、状态模式等来实现
  • 除常用方法(如 getXxx / isXxx)等外不要在条件判断中执行其它复杂的语句,将复杂逻辑判断的结果赋值给一个有意义的布尔变量名,以提高可读性。
  • 循环体中的语句要考量性能,以下操作尽量移至循环体外处理,如定义对象、变量、获取数据库连接,进行不必要的 try-catch 操作(这个 try-catch 是否可以移至循环体外)。
  • 避免采用取反逻辑运算符。
  • 公开接口需要进行入参保护,尤其是批量操作的接口。
    反例:某业务系统,提供一个用户批量查询的接口,API 文档上有说最多查多少个,但接口实现上没做任何保护,导致
    调用方传了一个 1000 的用户 id 数组过来后,查询信息后,内存爆了。
  • 下列情形,需要进行参数校验:
    1)调用频次低的方法。
    2)执行时间开销很大的方法。此情形中,参数校验时间几乎可以忽略不计,但如果因为参数错误导致中间执行回
    退,或者错误,那得不偿失。
    3)需要极高稳定性和可用性的方法。
    4)对外提供的开放接口,不管是 RPC / API / HTTP 接口。
    5)敏感权限入口。
  • 下列情形,不需要进行参数校验:
    1)极有可能被循环调用的方法。但在方法说明里必须注明外部参数检查。
    2)底层调用频度比较高的方法。毕竟是像纯净水过滤的最后一道,参数错误不太可能到底层才会暴露问题。一般 DAO
    层与 Service 层都在同一个应用中,部署在同一台服务器中,所以 DAO 的参数校验,可以省略。
    3)被声明成 private 只会被自己代码所调用的方法,如果能够确定调用方法的代码传入参数已经做过检查或者肯定不
    会有问题,此时可以不校验参数。

注释规约

  • 类、类属性、类方法的注释必须使用/** 内容 */ 格式,不得使用 // xxx方式。
  • 日期的设置统一为 yyyy/MM/dd 的格式。
  • .方法内部单行注释,在被注释语句上方另起一行,使用 // 注释。方法内部多行注释使用 /* */注释,注意与代码对齐。
  • 特殊注释标记
    1)待办事宜(TODO):(标记人,标记时间,[预计处理时间])
    2)错误,不能工作(FIXME):(标记人,标记时间,[预计处理时间])
  • 对于暂时被注释掉,后续可能恢复使用的代码片断,在注释代码上方,统一规定使用三个斜杠(///)来说明注释掉代码的理由:
public static void hello() {
/// 业务方通知活动暂停
// Business business = new Business();
// business.active();
System.out.println("it's finished");
}

前后端规约

  • 前后端数据列表相关的接口返回,如果为空,则返回空数组[]或空集合{}。这样可以减少前端很多琐碎的 null 判断。
  • 服务端发生错误时,返回给前端的响应信息必须包含 HTTP 状态码,errorCode、errorMessage、用户提示信息(user_tip)四个部分。其中输出给用户的提示信息要求:简短清晰、提示友好,引导用户进行下一步操作或解释错误原因,提示信息可以包括错误原因、上下文环境、推荐操作等。
  • 对于需要使用超大整数的场景(订单号),服务端一律使用 String 字符串类型返回,禁止使用 Long 类型。Long 类型能表示的最大值是 263-1,在取值范围之内,超过 253(9007199254740992)的数值转化为 Javascript 的 Number 时,有些数值会产生精度损失。
  • HTTP 请求通过 URL 传递参数时,不能超过 2048 字节。2048 字节是取所有浏览器的最小值。
  • HTTP 请求通过 body 传递内容时,必须控制长度,超出最大长度后,后端解析会出错。nginx 默认限制是 1MB,tomcat 默认限制为 2MB,当确实有业务需要传较大内容时,可以调大服务器端的限制。
  • 在翻页场景中,用户输入参数的小于 1,则前端返回第一页参数给后端;后端发现用户输入的参数大于总页数,直接返回最后一页。
  • 前后端的时间格式统一为"yyyy-MM-dd HH:mm:ss",统一为 GMT。

异常日志

错误码

  • 全部正常,但不得不填充错误码时返回五个零:00000。
  • 错误码为字符串类型,共 5 位,分成两个部分:错误产生来源+四位数字编号。
    说明:错误产生来源分为 A/B/C,A 表示错误来源于用户,比如参数错误,用户安装版本过低,用户支付超时等问题;
    B 表示错误来源于当前系统,往往是业务逻辑出错,或程序健壮性差等问题;C 表示错误来源于第三方服务,比如 CDN
    服务出错,消息投递超时等问题;四位数字编号从 0001 到 9999,大类之间的步长间距预留 100,参考附表 3。
  • 编号不与公司业务架构,更不与组织架构挂钩,以先到先得的原则在统一平台上进行,审批生效,编号即被永久固定。
  • 在获取第三方服务错误码时,向上抛出允许本系统转义,由 C 转为 B,并且在错误信息上带上原有的第三方错误码。

异常处理

  • 异常捕获后不要用来做流程控制,条件控制。异常设计的初衷是解决程序运行中的各种意外情况,且异常的处理效率比条件判断方式要低很多。
  • 不要在 finally 块中使用 return。
反例:
public int checkReturn() {
try {
// x 等于 1,此处不返回
return ++x; 
} finally {
// 返回的结果是 2
return ++x;
}
}
  • 方法的返回值可以为 null,不强制返回空集合,或者空对象等,必须添加注释充分说明什么情况下会返回 null 值。
  • 定义时区分 unchecked / checked 异常,避免直接抛出 new RuntimeException(),更不允许抛出 Exception 或者 Throwable,应使用有业务含义的自定义异常。推荐业界已定义过的自定义异常,如:DAOException / ServiceException 等。

日志规约

  • 日志文件至少保存 15 天,因为有些异常具备以“周”为频次发生的特点。对于当天日志,以 “应用名.log”来保存,保存在/{统一目录}/{应用名}/logs/目录下,过往日志格式为:{logname}.log.{保存日期},日期格式:yyyy-MM-dd
    正例:以 mppserver 应用为例,日志保存/home/admin/mppserver/logs/mppserver.log,历史日志名称
    为 mppserver.log.2021-11-28
  • 应用中的扩展日志(如打点、临时监控、访问日志等)命名方式:
    appName_logType_logName.log。logType:日志类型,如 stats / monitor / access 等;
    logName:日志描述。这种命名的好处:通过文件名就可知道日志文件属于什么应用,什么类型,什么目的,也有利于归类查找。
    说明:推荐对日志进行分类,将错误日志和业务日志分开放,便于开发人员查看,也便于通过日志对系统进行及时监控。
    正例:mppserver 应用中单独监控时区转换异常,如:mppserver_monitor_timeZoneConvert.log
  • 在日志输出时,字符串变量之间的拼接使用占位符的方式。
    说明:因为 String 字符串的拼接会使用 StringBuilder 的 append() 方式,有一定的性能损耗。使用占位符仅是替换动
    作,可以有效提升性能。
    正例:logger.debug(“Processing trade with id : {} and symbol : {}”, id, symbol);
  • 避免重复打印日志,浪费磁盘空间,务必在日志配置文件中设置 additivity=false
    正例:
  • 可以使用 warn 日志级别来记录用户输入参数错误的情况,避免用户投诉时,无所适从。如非必要,请不要在此场景打出 error 级别,避免频繁报警。
    说明:注意日志输出的级别,error 级别只记录系统逻辑出错、异常或者重要的错误信息。

安全规约

  • 在使用平台资源,譬如短信、邮件、电话、下单、支付,必须实现正确的防重放的机制,如数量限制、疲劳度控制、验证码校验,避免被滥刷而导致资损。
  • 对于文件上传功能,需要对于文件大小、类型进行严格检查和控制。
    说明:攻击者可以利用上传漏洞,上传恶意文件到服务器,并且远程执行,达到控制网站服务器的目的。
  • 发贴、评论、发送等即时消息,需要用户输入内容的场景。必须实现防刷、内容违禁词过滤等风控策略。

mysql数据库

建表规约

  • 表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是 tinyint( 1 表示是,0 表示否)。
  • 表名不使用复数名词。
  • 主键索引名为 pk_字段名;唯一索引名为 uk_字段名;普通索引名则为 idx_字段名。
    说明:pk_即 primary key;uk_即 unique key;idx_即 index 的简称。
  • 小数类型为 decimal,禁止使用 float 和 double。 储的数据范围超过 decimal 的范围,建议将数据拆成整数和小数并分开存储。
  • 如果存储的字符串长度几乎相等,使用 char 定长字符串类型。
  • varchar 是可变长字符串,不预先分配存储空间,长度不要超过 5000,如果存储长度大于此 值,定义字段类型为 text,独立出来一张表,用主键来对应,避免影响其它字段索引率。
  • 在数据库中不能使用物理删除操作,要使用逻辑删除。
    说明:逻辑删除在数据删除后可以追溯到行为操作。不过会使得一些情况下的唯一主键变得不唯一,需要根据情况来酌
    情解决。
  • 表的命名最好是遵循“业务名称_表的作用”。
  • 库名与应用名称尽量一致。
  • 字段允许适当冗余,以提高查询性能,但必须考虑数据一致。冗余字段应遵循
    1)不是频繁修改的字段。 2)不是唯一索引的字段。
    3)不是 varchar 超长字段,更不能是 text 字段。
    正例:各业务线经常冗余存储商品名称,避免查询时需要调用 IC 服务获取。
  • 单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表
    说明:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。
  • 不得使用外键与级联,一切外键概念必须在应用层解决。

索引规约

  • 业务上具有唯一特性的字段,即使是组合字段,也必须建成唯一索引。 说明:不要以为唯一索引影响了 insert 速度,这个速度损耗可以忽略,但提高查找速度是明显的;另外,即使在应用层做了非常完善的校验控制,只要没有唯一索引,根据墨菲定律,必然有脏数据产生。
  • 超过三个表禁止 join。需要 join 的字段,数据类型保持绝对一致;多表关联查询时,保证被关联的字段需要有索引。
    说明:即使双表 join 也要注意表索引、SQL 性能。
  • 在 varchar 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据实际文本区分度决定索引长度。
    说明:索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为 20 的索引,区分度会高达 90%以上,可以使
    用 count(distinct left(列名,索引长度)) / count(*) 的区分度来确定。
  • 页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。
  • 如果有 order by 的场景,请注意利用索引的有序性。order by 最后的字段是组合索引的一部分,并且放在索引组合顺序的最后,避免出现 filesort 的情况,影响查询性能。
    正例:where a = ? and b = ? order by c;索引:a_b_c
    反例:索引如果存在范围查询,那么索引有序性无法利用,如:WHERE a > 10 ORDER BY b;索引 a_b 无法排序。
  • 建组合索引的时候,区分度最高的在最左边。
    正例:如果 where a = ? and b = ?,a 列的几乎接近于唯一值,那么只需要单建 idx_a 索引即可。
    说明:存在非等号和等号混合判断条件时,在建索引时,请把等号条件的列前置。如:where c > ? and d = ? 那么即使
    c 的区分度更高,也必须把 d 放在索引的最前列,即建立组合索引 idx_d_c。

sql语句

  • 不要使用 count(列名) 或 count(常量) 来替代 count(),count() 是 SQL92 定义的标准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关。
    说明:count(*) 会统计值为 NULL 的行,而 count(列名) 不会统计此列为 NULL 值的行。
  • 使用 ISNULL() 来判断是否为 NULL 值。
    说明:而 ISNULL(column) 是一个整体,简洁易懂。从性能数据上分析,ISNULL(column) 执行效率更快一些。
  • SQL 语句中表的别名前加 as,并且以 t1、t2、t3、…的顺序依次命名。
    说明:
    1)别名可以是表的简称,或者是依照表在 SQL 语句中出现的顺序,以 t1、t2、t3 的方式命名。
    2)别名前加 as 使别名更容易识别。
  • in 操作能避免则避免,若实在避免不了,需要仔细评估 in 后边的集合元素数量,控制在1000 个之内。

ORM 映射

  • 在表查询中,一律不要使用 * 作为查询的字段列表,需要哪些字段必须明确写明。
    说明:
    1)增加查询分析器解析成本。
    2)增减字段容易与 resultMap 配置不一致。
    3)无用字段增加网络消耗,尤其是 text 类型的字段。
  • 不要用 resultClass 当返回参数,即使所有类属性名与数据库字段一一对应,也需要定义;反过来,每一个表也必然有一个与之对应。
    说明:配置映射关系,使字段与 DO 类解耦,方便维护。
  • 不要写一个大而全的数据更新接口。传入为 POJO 类,不管是不是自己的目标更新字段,都进行update table set c1 = value1 , c2 = value2 , c3 = value3;这是不对的。执行 SQL 时,不要更新无改动的字段,一是易出错;二是效率低;三是增加 binlog 存储。

工程结构

二方库依赖

  • 定义 GAV 遵从以下规则:
    1)GroupId 格式:com.{公司/BU}.业务线.[子业务线],最多 4 级。
    说明:{公司/BU}例如:alibaba / taobao / tmall / kaikeba 等 BU 一级;子业务线可选。
    正例:com.taobao.jstorm 或 com.alibaba.dubbo.register
    2)ArtifactId 格式:产品线名-模块名。语义不重复不遗漏,先到中央仓库去查证一下。
    正例:dubbo-client / fastjson-api / jstorm-tool
    3)Version:详细规定参考下方。
  • 】为避免应用二方库的依赖冲突问题,二方库发布者应当遵循以下原则:
    1) 精简可控原则。移除一切不必要的 API 和依赖,只包含 Service API、必要的领域模型对象、Utils 类、常量、枚举
    等。如果依赖其它二方库,尽量是 provided 引入,让二方库使用者去依赖具体版本号;无 log 具体实现,只依赖日志
    框架。
    2) 稳定可追溯原则。每个版本的变化应该被记录,二方库由谁维护,源码在哪里,都需要能方便查到。除非用户主动
    升级版本,否则公共二方库的行为不应该发生变化。

服务器

  • 调用远程操作必须有超时设置。
  • 高并发服务器建议调小 TCP 协议的 time_wait 超时时间。
    说明:操作系统默认 240 秒后,才会关闭处于 time_wait 状态的连接,在高并发访问下,服务器端会因为处于
    time_wait 的连接数太多,可能无法建立新的连接,所以需要在服务器上调小此等待值。
    正例:在 linux 服务器上请通过变更/etc/sysctl.conf 文件去修改该缺省值(秒):net.ipv4.tcp_fin_timeout=30
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值