Java权威编码规范

Codis

五 、安全规则

  1. 【强制】隶属于用户个人的页面恐怕成效亟须开展权力控制校验。
    表达:防止没有做水平权限校验就可随意走访、操作外人的数码,比如查看、修改旁人的订单。
  2. 【强制】用户敏感数据禁止直接浮现,必须对浮现数据脱敏。
    表明:查看个人手机号码会显得成:158****9119,隐藏中间肆个人,避免隐秘走漏。
    3.
    【强制】用户输入的SQL参数严酷使用参数绑定只怕METADATA字段值限定,幸免SQL注入,禁止字符串拼接SQL访问数据库。
  3. 【强制】用户请求传入的任何参数必须做有效验证。
    表达:忽略参数校验只怕引致:
     page size过大导致内存溢出
     恶意order by导致数据库慢查询
     任意重定向
     SQL注入
     反体系化注入
     正则输入源串拒绝服务ReDoS 表明: Java JavaJava代码用 代码用
    正则来验证客户端的输入,有些正则写法验证普通用户输入没有反常态,但是借使攻击人员利用的是超常规结构的字符串来证实,有或者造成死循环的法力
  4. 【强制】禁止向HTML页面输出未经安全过滤或未正确转义的用户数量。
  5. 【强制】表单、AJAX提交必须履行CS奥迪Q5F安全过滤。 表明:CSRubiconF(Cross-site
    request
    forgery)跨站请求伪造是一类常见编程漏洞。对于存在CS卡宴F漏洞的施用/网站,攻击者可以预先构造好ULX570L,只要受害者用户一做客,后台便在用户不知情情状下对数据库中用户参数进行对应修改。
    7.
    【强制】在运用平台能源,譬如短信、邮件、电话、下单、支付,必须贯彻科学的防回放范围,如数量限制、疲劳度控制、验证码校验,防止被滥刷、资损。

  表达:如注册时发送验证码到手机,倘诺没有限定次数和功效,那么可以动用此效用扰攘到别的用户,并致使短信平台能源浪费。

最后,刘奇还介绍详细的了Codis中Migration、lock (rwlock)等操作的兑现进度和法则,以及从Twemproxy迁移到Codis的详实操作。越多Codis详情可移步Clodis开源页
GitHub

二 、很是日志

图片 1

(二) 日志规约

1.
【强制】应用中不可直接动用日志系统(Log4j、Logback)中的API,而应借助于使用日志框架SLF4J中的API,使用门面形式的日记框架,有利于爱抚和顺序类的日志处理形式统一。
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  private static final Logger logger =
LoggerFactory.getLogger(Abc.class);
2.
【强制】日志文件推荐至太史存15天,因为微微尤其具备以“周”为频次发生的性状。
3.
【强制】应用中的扩充日志(如打点、暂时监控、访问日志等)命名格局:appName_logType_logName.log。logType:日志类型,推荐分类有stats/desc/monitor/visit等;logName:日志描述。那种命名的利益:通过文件名就可见道日记文件属于怎么应用,什么类型,什么目标,也有利于归类查找。

  正例:mppserver应用中单独监控时区转换非凡,如:
mppserver_monitor_timeZoneConvert.log
表达:推荐对日记举办分拣,错误日志和业务日志尽量分开存放,便于开发人员查看,也有利于通过日记对系统进行即时督查。
4.
【强制】对trace/debug/info级其他日记输出,必须运用规则输出方式仍然接纳占位符的方法。

  表达:logger.debug(“Processing trade with id: ” + id + ” symbol: ” +
symbol);
如果日志级别是warn,上述日志不会打印,可是会举办字符串拼接操作,假诺symbol是指标,会执行toString()方法,浪费了系统财富,执行了上述操作,最后日志却尚未打印。

  正例:(条件)
  if (logger.isDebugEnabled()) {
    logger.debug(“Processing trade with id: ” + id + ” symbol: ” +
symbol);
  }
  正例:(占位符)
  logger.debug(“Processing trade with id: {} symbol : {} “, id,
symbol);
5.
【强制】防止再一次打印日志,浪费磁盘空间,务必在log4j.xml中装置additivity=false。

  正例:<logger name=”com.taobao.dubbo.config”
additivity=”false”>
6.
【强制】万分音讯应该包含两类音讯:案发现场音信和分外堆栈消息。即使不处理,那么往上抛。

  正例:logger.error(各种参数只怕目标toString + “_” + e.getMessage(),
e);
7.
【推荐】可以使用warn日志级别来记录用户输入参数错误的气象,防止用户投诉时,惊慌失措。注意日志输出的级别,error级别只记录系统逻辑出错、至极等首要的错误新闻。如非须求,请不要在此景况打出error级别。
8.
【推荐】谨慎地记录日志。生产条件禁止出口debug日志;有拔取地输出info日志;假诺使用warn来记录刚上线时的事情作为音信,一定要留意日志输出量的难题,幸免把服务器磁盘撑爆,并记得当时去除那个观测日志。

  表达:大批量地出口无效日志,不便利系统个性升高,也不便利火速稳定错误点。记录日志时请想想:那个日记真的有人看吗?看到那条日志你能做什么样?能无法给难题排查带来利益?

图片 2

(一) 建表规约

1.
【强制】表达是与否概念的字段,必须利用is_xxx的主意命名,数据类型是unsigned
tinyint( 1代表是,0表示否),此规则平等适用于odps建表。

  表明:任何字段若是为非负数,必须是unsigned。
2.
【强制】表名、字段名必须使用小写字母或数字;禁止出现数字伊始,禁止多个下划线中间只出现数字。数据库字段名的改动代价很大,因为不能开展预揭示,所以字段名称必要从长商议。

  正例:getter_admin,task_config,level3_name

  反例:GetterAdmin,taskConfig,level_3_name

  1. 【强制】表名不选拔复数名词。
    表明:表名应该一味意味着表里面的实体内容,不应当代表实体数量,对应于DO类名也是单数方式,符合表明习惯。
    4.
    【强制】禁用保留字,如desc、range、match、delayed等,请参考MySQL官方保留字。
  2. 【强制】唯一索引名为uk_字段名;普通索引名则为idx_字段名。
    说明:uk_ 即 unique key;idx_ 即index的简称。
  3. 【强制】小数类型为decimal,禁止利用float和double。

  表明:float和double在存储的时候,存在精度损失的难题,很恐怕在值的可比时,拿到不得法的结果。如果存储的数额范围超越decimal的限量,提议将数据拆成整数和小数分开储存。

  1. 【强制】要是存储的字符串长度大概等于,使用char定长字符串类型。
    8.
    【强制】varchar是可变长字符串,不预先分配存储空间,长度不要跨越5000,若是存储长度超越此值,定义字段类型为text,独立出来一张表,用主键来对号入座,防止影响其余字段索引效用。
  2. 【强制】表必备三字段:id, gmt_create, gmt_modified。

  表达:其中id必为主键,类型为unsigned
bigint、单表时自增、步长为1。gmt_create,
gmt_modified的档次均为date_time类型。

  1. 【推荐】表的命名最好是添加“业务名称_表的效果”。 正例:tiger_task /
    tiger_reader / mpp_config
  2. 【推荐】库名与利用名称尽量一致。
    12.
    【推荐】如若改动字段含义或对字段表示的事态追加时,须求立刻更新字段注释。
    13.
    【推荐】字段允许适当冗余,以增强品质,不过必须考虑数据同步的动静。冗余字段应按照:

  1)不是几度修改的字段。 2)不是varchar超长字段,更不大概是text字段。

    正例:商品类目名称使用频率高,字段长度短,名称基本不变,可在相关联的表中冗余存储类目名称,幸免关联查询。

  1. 【推荐】单表行数当先500万行依旧单表体积当先2GB,才推荐举行分库分表。

  表明:借使预测三年后的数据量根本达不到那几个级别,请不要在开立表时就分库分表。
15.
【参考】合适的字符存储长度,不但节约数据库表空间、节约索引存储,更体贴的是提高查找速度。

  正例:人的岁数用unsigned
tinyint(表示范围0-255,人的寿命不会当先2伍十二周岁);水龟就务须是smallint,但万一是日光的年纪,就不可以不是int;即使是兼备恒星的年华府加起来,那么就亟须拔取bigint。

可是,1个新种类的开销并不是件简单的事体,尤其是1个繁杂的分布式系统。刘奇代表,纵然当时公司惟有3位,可是他们大致考量了可以考量的各样细节:

(一) 应用分层

1.
【推荐】图中暗许上层依赖于下层,箭头关系表示可径直正视,如:开放接口层可以器重于Web层,也足以平素倚重于Service层,依此类推:

开放接口层:可直接封装Service接口揭发成中华VPC接口;通过Web封装成http接口;网关控制层等。

终端突显层:各种端的模板渲染并履行突显层。当前根本是velocity渲染,JS渲染,JSP渲染,移动端显示层等。

Web层:紧假使对访问控制进行转账,种种基本参数校验,只怕不复用的事务不难处理等。
 Service层:相对具体的政工逻辑服务层。
 Manager层:通用业务处理层,它有如下特征:

  1) 对第①方平台封装的层,预处理回来结果及转会十分音信;

  2) 对Service层通用能力的下移,如缓存方案、中间件通用处理;

  3) 与DAO层交互,对DAO的工作通用能力的卷入。
 DAO层:数据访问层,与底层MySQL、Oracle、Hbase进行数量交互。

外部接口或第3方平台:包含其它单位中华VPC开放接口,基础平台,其余公司的HTTP接口。

  1. 【参考】
    (分层相当处理规约)在DAO层,暴发的格外类型有不少,不可能用细粒度万分举办catch,使用catch(Exception
    e)形式,并throw new
    DAOException(e),不须求打印日志,因为日志在Manager/Service层一定要求捕获并打到日志文件中去,假如同台服务器再打日志,浪费质量和储存。在Service层出现极度时,必须记录日志消息到磁盘,尽大概带上参数新闻,也等于爱抚案发现场。若是Manager层与Service同机部署,日志形式与DAO层处理一致,即便是独自安排,则动用与Service一致的处理格局。Web层绝不该继承往上抛万分,
    因为已经处于顶层,无再三再四处理卓殊的章程,假使发现到那些特别将促成页面无法符合规律渲染,那么就相应一向跳转到友好错误页面,尽量加上本人的谬误指示新闻。开放接口层要将不胜处理成错误码和错误音信格局赶回。
  2. 【参考】分层领域模型规约:
     DO(Data
    Object):与数量库表结构一一对应,通过DAO层向上传输数据源对象。
     DTO(Data Transfer
    Object):数据传输对象,Service和Manager向外传输的靶子。
     BO(Business
    Object):业务对象。可以由Service层输出的包裹业务逻辑的对象。

    QUE福睿斯Y:数据查询对象,各层接收上层的询问请求。注:超越一个参数的查询封装,禁止行使Map类来传输。
     VO(View Object):彰显层对象,日常是Web向模板渲染引擎层传输的目的。

Redis
Cluster(官方):无中央化设计,程序难以编写;代码有点骇人传说,clusterProcessPacket函数有426行,人脑难以处理全部的情况切换;迟迟没有正经版本,等了4年之久;近期还贫乏最佳实践,没有人编写Redis
Cluster的若干条注意事项;整个连串中度耦合,升级困难。

(四) OOP规约

1.
【强制】幸免通过三个类的目标引用访问此类的静态变量或静态方法,无谓增添编译器解析花费,直接用类名来访问即可。

  1. 【强制】全体的覆写方法,必须加@Override注脚。

  反例:getObject()与get0bject()的难点。1个是字母的O,三个是数字的0,加@Override可以精确判断是不是覆盖成功。此外,假使在抽象类中对艺术签名举办改动,其已毕类会立时编译报错。
3.
【强制】相同参数类型,相同业务含义,才可以应用Java的可变参数,幸免选拔Object。

  表达:可变参数必须放置在参数列表的最后。(提倡同学们尽只怕不用可变参数编程)

  正例:public User getUsers(String type, Integer… ids)
4.
【强制】对外暴光的接口签名,原则上不允许修改章程签名,幸免对接口调用方暴发潜移默化。接口过时必须加@Deprecated评释,并清晰地证实采纳的新接口只怕新劳动是怎么着。

  1. 【强制】不能采取老式的类或艺术。

  表明:java.net.U奇骏LDecoder 中的方法decode(String encodeStr)
这一个形式已经不合时宜,应该拔取双参数decode(String source, String
encode)。接口提供方既然明显是老式接口,那么有分文不取同时提供新的接口;作为调用方来说,有义务去考证过时方法的新已毕是何许。
6.
【强制】Object的equals方法简单抛空指针万分,应使用常量或规定有值的目标来调用equals。

  正例: “test”.equals(object); 反例: object.equals(“test”);

  表明:推荐使用java.util.Objects#equals (JDK7引入的工具类)
7.
【强制】全部的一模一样档次的包装类对象之间值的相比,全体应用equals方法相比。

  表明:对于Integer
var=?在-128至127时期的赋值,Integer对象是在IntegerCache.cache暴发,会复用已有目的,那么些距离内的Integer值可以直接利用==举办判定,不过那几个间隔之外的有所数据,都会在堆上发生,并不会复用已有目的,那是七个大坑,推荐使用equals方法举办判断。

  1. 【强制】关于宗旨数据类型与包装数据类型的采取规范如下:

  1) 全数的POJO类属性必须使用包装数据类型。

  2) 汉兰达PC方法的重临值和参数必须运用包装数据类型。

  3) 全部的片段变量【推荐】使用基本数据类型。

  表明:POJO类属性没有初值是提醒使用者在须要使用时,必须团结显式地拓展赋值,任何NPE难点,或然入库检查,都由使用者来保险。
正例:数据库的询问结果只怕是null,因为电动拆箱,用为重数据类型接收有NPE危害。

  反例:比如显示成交总额涨跌情状,即正负x%,x为主干数据类型,调用的智跑PC服务,调用不成事时,再次来到的是暗中同意值,页面展现:0%,那是不客观的,应该突显成中写道-。所以包装数据类型的null值,可以代表额外的消息,如:远程调用失利,至极退出。

  1. 【强制】定义DO/DTO/VO等POJO类时,不要设定任何属性暗中认同值。

  反例:POJO类的gmtCreate专断认同值为new
Date();然而这么些天性在数据提取时并没有置入具体值,在更新任何字段时又顺手更新了此字段,导致创立时间被涂改成当下时间。
10.
【强制】系列化类新增属性时,请不要涂改serialVersionUID字段,防止反系列失利;假如完全不合营升级,防止反体系化混乱,那么请修改serialVersionUID值。

  表明:注意serialVersionUID差异会抛出系列化运维时那多少个。
11.
【强制】构造方法里面禁止进入此外工作逻辑,如若有起始化逻辑,请放在init方法中。

  1. 【强制】POJO类必须写toString方法。使用IDE的中工具:source>
    generate
    toString时,即使三番五次了另1个POJO类,注意在前面加一下super.toString。

  表达:在艺术执行抛出十二分时,可以从来调用POJO的toString()方法打印其属性值,便于排查难题。
13.
【推荐】使用索引访问用String的split方法拿到的数组时,需做最终三个相隔符后有无内容的自笔者批评,否则会有抛IndexOutOfBoundsException的高危机。
  说明:
    String str = “a,b,c,,”;
    String[] ary = str.split(“,”);
    //预期大于3,结果是3
    System.out.println(ary.length);
14.
【推荐】当一个类有八个构造方法,只怕多个同名方法,那几个方法应该按顺序放置在联合,便于阅读。

  1. 【推荐】 类内方法定义顺序依次是:公有方法或保安方法 > 私有办法
    > getter/setter方法。
    表达:公有方法是类的调用者和资助者最关切的措施,首屏浮现最好;爱慕格局就算只是子类关注,也或者是“模板设计情势”下的主干措施;而个人方法外部一般不必要特地关注,是3个黑盒达成;因为方法音讯价值较低,全体Service和DAO的getter/setter方法放在类体最终。
    16.
    【推荐】setter方法中,参数名称与类成员变量名称相同,this.成员名=参数名。在getter/setter方法中,尽量不要增加工作逻辑,伸张排查问题的难度。

  反例:

public Integer getData() {
        if (true) {
            return data + 100;
        } else {
            return data - 100;
        }
    }

17.
【推荐】循环体内,字符串的对接格局,使用StringBuilder的append方法开展扩展。
反例:

String str = "start";
for (int i = 0; i < 100; i++) {
    str = str + "hello";
}

证实:反编译出的字节码文件突显每回循环都会new出三个StringBuilder对象,然后举办append操作,最终经过toString方法重回String对象,造成内存能源浪费。

  1. 【推荐】final可增强程序响应效用,评释成final的状态:

  1) 不需求再度赋值的变量,包含类属性、局地变量。

  2) 对象参数前加final,表示不容许修改引用的针对。

  3) 类方法鲜明不允许被重写。

  1. 【推荐】慎用Object的clone方法来拷贝对象。

  表达:对象的clone方法默许是浅拷贝,若想完毕深拷贝必要重写clone方法达成属性对象的正片。

  1. 【推荐】类成员与办法访问控制从严:

  1) 要是不允许外部直接通过new来创设对象,那么构造方法必须是private。

  2) 工具类不容许有public或default构造方法。

  3) 类非static成员变量并且与子类共享,必须是protected。

  4) 类非static成员变量并且仅在本类使用,必须是private。

  5) 类static成员变量假如仅在本类使用,必须是private。

  6) 即便static成员变量,必须考虑是还是不是为final。

  7) 类成员方法只供类内部调用,必须是private。

  8) 类成员方法只对继承类公开,那么限制为protected。

  表明:任何类、方法、参数、变量,严控访问范围。过广泛的访问范围,不便于模块解耦。

  思考:假设是三个private的不二法门,想删除就删除,不过一个public的Service方法,或然2个public的积极分子变量,删除一下,不得手心冒点汗吗?变量像本身的娃儿,尽量在和谐的视线内,变量功能域太大,倘若无界定的处处跑,那么您会担心的。

Codis紧要包涵Codis Proxy(codis-proxy)、Codis Manager(codis-config)、Codis Redis(codis-server)和ZooKeeper四大组件,各种部分都可动态扩容。

(二) 索引规约

1.
【强制】业务上享有唯一特点的字段,尽管是构成字段,也无法不建成唯一索引。

  表明:不要以为唯一索引影响了insert速度,那一个速度损耗可以忽略,但增强查找速度是分明的;此外,固然在应用层做了至极周密的校验和操纵,只要没有唯一索引,根据Murphy定律,必然有脏数据暴发。

  1. 【强制】
    超越多个表禁止join。须求join的字段,数据类型保持相对平等;多表关联查询时,保障被波及的字段须要有目录。

  表明:即便双表join也要专注表索引、SQL质量。
3.
【强制】在varchar字段上树立目录时,必须钦赐索引长度,没须要对全字段建立目录,根据实际文本区分度决定索引长度。

  表明:索引的长度与区分度是一对争辩体,一般对字符串类型数据,长度为20的目录,区分度会高达9/10以上,可以采纳count(distinct
left(列名, 索引长度))/count(*)的区分度来分明。

  1. 【强制】页面搜索严禁左模糊大概全模糊,假诺要求请走搜索引擎来缓解。

  表达:索引文件具有B-Tree的最左前缀匹配本性,假使左边的值未规定,那么不可以采用此索引。

  1. 【推荐】如若有order by的光景,请留心使用索引的有序性。order by
    最终的字段是构成索引的一某个,并且位居索引组合顺序的末段,防止出现file_sort的图景,影响查询品质。

  正例:where a=? and b=? order by c; 索引:a_b_c

  反例:索引中有限定查找,那么索引有序性不大概运用,如:WHERE a>10
O劲客DEPAJERO BY b; 索引a_b不或然排序。

  1. 【推荐】利用覆盖索引来进行查询操作,来防止回表操作。

  表明:固然一本书要求通晓第②1章是如何标题,会翻动第三1章对应的那一页吗?目录浏览一下就好,这么些目录就是起到覆盖索引的功用。

  正例:可以确立目录的档次:主键索引、唯一索引、普通索引,而覆盖索引是一种查询的一种作用,用explain的结果,extra列会出现:using
index。

  1. 【推荐】利用延迟关联或许子查询优化超多分页场景。

  表达:MySQL并不是跳过offset行,而是取offset+N行,然后返重舍弃前offset行,再次回到N行,这当offset特别大的时候,作用就可怜的放下,要么控制重回的总页数,要么对超越一定阈值的页数进行SQL改写。

  正例:先迅速稳定要求得到的id段,然后再涉及: SELECT a.* FROM 表1 a,
(select id from 表1 where 条件 LIMIT 100000,20 ) b where a.id=b.id

  1. 【推荐】 SQL品质优化的对象:至少要达到 range
    级别,须要是ref级别,如若得以是consts最好。

  说明:

    1)consts
单表中最五只有二个匹配行(主键可能唯一索引),在优化阶段即可读取到数据。

    2)ref 指的是应用普通的目录(normal index)。

    3)range 对索引举行限制检索。

  反例:explain表的结果,type=index,索引物理文件全扫描,速度特别慢,那些index级别相比range还低,与全表扫描是小巫见大巫。

  1. 【推荐】建组合索引的时候,区分度最高的在最左侧。 正例:如若where a=?
    and b=? ,a列的大概接近于唯一值,那么只必要单建idx_a索引即可。

  表明:存在非等号和等号混合判断标准时,在建索引时,请把等号规则的列前置。如:where
a>? and b=? 那么尽管a的区分度更高,也不可以不把b放在索引的最前列。

  1. 【参考】创立索引时避免有如下极端误解:

  1)误认为2个查询就须求建二个索引。

  2)误认为索引会消耗空间、严重拖慢更新和新增速度。

  3)误认为唯一索引一律须求在应用层通过“先查后插”方式缓解。

尽管我们有众多的选项,比如Tair、Couchbase等,不过一旦你需求更复杂和非凡的数据结构,Redis可称之为不二之选。基于那一个原因,在Redis之上,豌豆荚设计了Codis,并将之开源。

(七) 控制语句

1.
【强制】在二个switch块内,逐个case要么通过break/return等来终止,要么注释表达程序将继续执行到哪3个case甘休;在2个switch块内,都不恐怕不包括一个default语句并且位居最后,尽管它什么代码也并未。
2.
【强制】在if/else/for/while/do语句中务必运用大括号,即便唯有一行代码,避免选用上边的样式:if
(condition) statements;

  1. 【推荐】推荐尽量少用else, if-else的办法得以改写成:
      if(condition){
        …
        return obj;
      }
      // 接着写else的作业逻辑代码;
      表明:若是非得利用if()…else
    if()…else…情势表达逻辑,【强制】请勿当先3层,超越请使用状态设计方式。
      正例:逻辑上超过3层的if-else代码可以应用卫语句,可能状态情势来贯彻。
    4.
    【推荐】除常用方法(如getXxx/isXxx)等外,不要在标准化判断中施行别的复杂的话语,将复杂逻辑判断的结果赋值给三个有意义的布尔变量名,以增强可读性。

  表明:很多if语句内的逻辑十二分复杂,阅读者要求分析条件表达式的末尾结出,才能分明怎么着的尺度执行如何的言语,那么,即便阅读者分析逻辑表达式错误啊?

  正例:
    //伪代码如下
    boolean existed = (file.open(fileName, “w”) != null) && (…) ||
(…);
    if (existed) {
      …
    }
  反例:
    if ((file.open(fileName, “w”) != null) && (…) || (…)) {
      …
    }
5.
【推荐】循环体中的语句要勘验质量,以下操作尽量移至循环体外处理,如定义对象、变量、获取数据库连接,举行不要求的try-catch操作(那一个try-catch是还是不是足以移至循环体外)。

  1. 【推荐】接口入参尊敬,那种现象常见的是用于做批量操作的接口。
  2. 【参考】方法中须要举办参数校验的景观:

  1) 调用频次低的不二法门。

  2)
执行时间支出很大的办法,参数校验时间大致可以忽略不计,但只要因为参数错误造成中间执行回退,可能失实,那贪小失大。
  3) 需求极高稳定和可用性的艺术。

  4) 对外提供的绽开接口,不管是瑞虎PC/API/HTTP接口。
  5) 敏感权限入口。

  1. 【参考】方法中不需求参数校验的情形:

  1)
极有只怕被循环调用的艺术,不提议对参数举办校验。但在措施求证里总得注明外部参数检查。

  2)
底层的主意调用频度都相比较高,一般不校验。毕竟是像纯净水过滤的终极一道,参数错误不太恐怕到底层才会揭穿难题。一般DAO层与Service层都在同1个用到中,部署在同一台服务器中,所以DAO的参数校验,可以简简单单。

  3)
被声称成private只会被本身代码所调用的章程,如果可以鲜明调用方法的代码传入参数已经做过检查恐怕自然不会不平常,此时可以不校验参数。

codis-server。Codis 项目维护的三个Redis分支,参预了slot的襄助和原子的数目迁移指令。

(九) 其它

1.
【强制】在行使正则表达式时,利用好其预编译功用,可以使得加速正则匹配速度。

  表达:不要在艺术体钦命义:Pattern pattern = Pattern.compile(规则);
2.
【强制】velocity调用POJO类的属性时,指出直接行使属性名取值即可,模板引擎会自行按正统调用POJO的getXxx(),借使是boolean基本数据类型变量(boolean命名不需求加is前缀),会活动调用isXxx()方法。

  表达:注意如若是Boolean包装类对象,优先调用getXxx()的主意。

  1. 【强制】后台输送给页面的变量必须加$!{var}——中间的惊讶号。

  表明:若是var=null可能不存在,那么${var}会平昔显示在页面上。

  1. 【强制】注意 Math.random() 那一个点子重临是double类型,注意取值的限量
    0≤x<1(可以取到零值,注意除零极度),如果想赢得整数项目标自由数,不要将x放大10的好多倍然后取整,直接动用Random对象的nextInt或许nextLong方法。
  2. 【强制】获取当前阿秒数System.currentTimeMillis(); 而不是new
    Date().getTime();

  表达:如果想博得越发规范的阿秒级时间值,用System.nanoTime()。在JDK8中,针对计算时间等现象,推荐使用Instant类。
6.
【推荐】尽量不要在vm中进入变量申明、逻辑运算符,更毫不在vm模板中插足其余复杂的逻辑。
7.
【推荐】任何数据结构的结构或开始化,都应钦定大小,防止数据结构无限拉长吃光内存。
8.
【推荐】对于“分明截止使用的代码和布局”,如方法、变量、类、配置文件、动态配置属性等要坚决从程序中清理出去,防止造成过多垃圾。

  • 尽或许拆分,简化逐个模块,同时不难升级
  • 各类组件只负责自个儿的事体
  • Redis只看做存储引擎
  • Proxy的状态
  • Redis故障判定是或不是置于外部,因为分布式系统存活的论断卓殊复杂
  • 提供API让外部调用,当Redis Master丢失时,升高Slave为Master
  • 图形化监控全部:slot状态、Proxy状态、group状态、lock、action等等

(二) 常量定义

  1. 【强制】不容许现身其余魔法值(即未经定义的常量)直接出现在代码中。

  反例: String key=”Id#taobao_”+tradeId;

     cache.put(key, value);
2.
【强制】long恐怕Long开头赋值时,必须使用大写的L,不可以是小写的l,小写容易跟数字1模糊,造成误会。

  表明:Long a = 2l; 写的是数字的21,依旧Long型的2?
3.
【推荐】不要使用2个常量类敬重有着常量,应该按常量效能举办分拣,分开维护。如:缓存相关的常量放在类:CacheConsts下;系统安顿相关的常量放在类:ConfigConsts下。

  表达:大而全的常量类,非得利用查找成效才能固定到修改的常量,不便宜掌握和维护。
4.
【推荐】常量的复用层次有五层:跨应用共享常量、应用内共享常量、子工程内共享常量、包内共享常量、类内共享常量。

  1)
跨应用共享常量:放置在二方库中,平时是client.jar中的constant目录下。

  2) 应用内共享常量:放置在一方库的modules中的constant目录下。

    反例:易懂变量也要统一定义成应用内共享常量,两位攻城师在多个类中分头定义
了表示“是”的变量:

       类A中:public static final String YES = “yes”;

       类B中:public static final String YES = “y”;
A.YES.equals(B.YES),预期是true,但实际上重返为false,导致爆发线上难点。
  3) 子工程内部共享常量:即在当前子工程的constant目录下。

  4) 包内共享常量:即在时下包下单独的constant目录下。

  5) 类内共享常量:直接在类内部private static final定义。
5.
【推荐】如果变量值仅在3个限制内变化用Enum类。即使还富含名称之外的延伸属性,必须使用Enum类,上边正例中的数字就是延伸消息,表示星期几。

  正例:public Enum{ MONDAY(1), TUESDAY(2), WEDNESDAY(3), THURSDAY(4),
FRIDAY(5), SATURDAY(6), SUNDAY(7);}

图片 3

(二) 二方库规约

  1. 【强制】定义GAV听从以下规则:

  1) GroupID格式:com.{公司/BU }.业务线.[子业务线],最多4级。

    表明:{公司/BU}
例如:alibaba/taobao/tmall/aliexpress等BU一流;子业务线可选。

    正例:com.taobao.jstorm 或 com.alibaba.dubbo.register

  2)
ArtifactID格式:产品线名-模块名。语义不重复不遗漏,先到库房中央去考察一下。

    正例:dubbo-client / fastjson-api / jstorm-tool 3)
Version:详细规定参考下方。

  1. 【强制】二方库版本号命名形式:主版本号.次版本号.修订号

  1) 主版本号:当做了不包容的API
修改,恐怕增添了能改变产品趋势的新功效。

  2) 次版本号:当做了向下包容的作用性新增(新增类、接口等)。

  3) 修订号:修复bug,没有改动章程签名的出力增强,保持 API 包容性。

    表达: 初步版本号 必须 为: 1.0.0,而不是 0.0.1
3.
【强制】线上使用不要着重SNAPSHOT版本(安全包除外);正式发布的类库必须接纳RELEASE版本号升级+1的艺术,且版本号不一样意覆盖升级,必须去核心仓库举行调查。

  表明:不看重SNAPSHOT版本是保险应用公布的幂等性。其余,也得以加快编译时的打包创设。
4.
【强制】二方库的骤增或升官,保持除功效点之外的任何jar包仲裁结果不变。如果有转移,必须精通评估和验证,提议开展dependency:resolve前后音信比对,借使决策结果完全不同,那么通过dependency:tree命令,找出差别点,举办<excludes>排除jar包。
5.
【强制】二方Curry可以定义枚举类型,参数能够应用枚举类型,不过接口重临值不容许行使枚举类型或许隐含枚举类型的POJO对象。
6.
【强制】依赖于2个二方库群时,必须定义七个联结版本变量,幸免版本号差距。

  表明:倚重springframework-core,-context,-beans,它们都以同3个本子,可以定义一个变量来保存版本:${spring.version},定义器重的时候,引用该版本。
7.
【强制】禁止在子项目标pom依赖中出现雷同的GroupId,相同的ArtifactId,可是差距的Version。

  表明:在本地调试时会使用各子项目钦赐的版本号,但是合并成二个war,只可以有二个版本号出现在结尾的lib目录中。曾经出现过线下调试是不易的,宣布到线上出故障的判例。
8.
【推荐】全体pom文件中的重视表明放在<dependencies>语句块中,全体版本仲裁放在<dependencyManagement>语句块中。

  表明:<dependencyManagement>里只是宣称版本,并不完成引入,因而子项目必要显式的扬言正视,version和scope都读取自父pom。而<dependencies>全体宣称在主pom的<dependencies>里的借助都会活动引入,并暗许被有着的子项目继承。

  1. 【推荐】二方库尽量不要有计划项,最低限度不要再充实安插项。
    10.
    【参考】为防止拔取二方库的借助争辩难题,二方库揭橥者应当比照以下条件:

  1)精简可控条件。移除一切不须要的API和依靠,只包蕴 ServiceAPI、必要的天地模型对象、Utils类、常量、枚举等。如果依靠其余二方库,尽量是provided引入,让二方库使用者去正视具体版本号;无log具体贯彻,只依靠日志框架。

  2)稳定可追溯原则。每一种版本的生成应该被记录,二方库由哪个人爱抚,源码在哪里,都要求能方便查到。除非用户主动升高版本,否则公共二方库的行事不应有发生变化。

Redis在豌豆荚的施用进度——单实例==》多实例,业务代码中做sharding==》单个Twemproxy==》七个Twemproxy==》Codis,豌豆荚自个儿费用的分布式Redis服务。在大面积的Redis使用进程中,他们发觉Redis受限于两个地方:单机内存有数、带宽压力、单点难题、不可能动态扩容以及磁盘损坏时的数额抢救。

(四) ORM规约

  1. 【强制】在表查询中,一律不要接纳 *
    作为查询的字段列表,必要什么样字段必须鲜明写明。

  说明:

    1)扩展查询分析器解析开销。

    2)增减字段不难与resultMap配置不均等。
2.
【强制】POJO类的boolean属性无法加is,而数据库字段必须加is_,要求在resultMap中举办字段与特性之间的照耀。

  表明:参见定义POJO类以及数据库字段定义规定,在sql.xml伸张映射,是必须的。
3.
【强制】不要用resultClass当重回参数,即使拥有类属性名与数据库字段一一对应,也亟需定义;反过来,每三个表也一定有1个与之相应。

  表达:配置映射关系,使字段与DO类解耦,方便维护。

  1. 【强制】xml配置中参数注意采用:#{},#param# 不要使用${}
    此种格局简单出现SQL注入。
  2. 【强制】iBATIS自带的queryForList(String statementName,int start,int
    size)不推荐使用。

  表达:其促成方式是在数据库取到statementName对应的SQL语句的具有记录,再通过subList取start,size的子集合,线上因为这些缘故现已出现过OOM。
正例:在sqlmap.xml中引入 #start#, #size#
  Map<String, Object> map = new HashMap<String,
Object>();
  map.put(“start”, start);
  map.put(“size”, size);

  1. 【强制】差异意间接拿HashMap与Hashtable作为查询结果集的输出。
    7.
    【强制】更新数据表记录时,必须同时更新记录对应的gmt_modified字段值为目前岁月。
    8.
    【推荐】不要写2个大而全的数量更新接口,传入为POJO类,不管是还是不是团结的对象更新字段,都举办update
    table set c1=value1,c2=value2,c3=value3;
    那是难堪的。执行SQL时,尽量不要更新无更改的字段,一是易出错;二是效用低;三是binlog扩大存储。
    9.
    【参考】@Transactional事务不要滥用。事务会潜移默化数据库的QPS,别的利用工作的地方须求考虑各市方的回滚方案,蕴涵缓存回滚、搜索引擎回滚、音信补偿、总括纠正等。
    10.
    【参考】<isEqual>中的compareValue是与属性值相比的常量,一般是数字,表示相当时带上此条件;<isNotEmpty>表示不为空且不为null时实施;<isNotNull>表示不为null值时进行。

ZooKeeper。Codis倚重ZooKeeper来存放数据路由表和codis-proxy节点的元新闻,codis-config发起的命令会通过 ZooKeeper同步到各种存活的codis-proxy。

四 、工程规约

codis-proxy 客户端连接的Redis代理服务,本人达成了Redis协议,表现很像原生的Redis (就像是 Twemproxy)。2个事务可以计划七个 codis-proxy,其本人是无状态的。

(三) 格式规约

1.
【强制】大括号的选取约定。若是是大括号内为空,则简洁地写成{}即可,不需要换行;假如是非空代码块则:

  1) 左大括号前不换行。

  2) 左大括号后换行。

  3) 右大括号前换行。

  4) 右大括号后还有else等代码则不换行;表示终止右大括号后必须换行。

  1. 【强制】
    左括号和后3个字符之间不出现空格;同样,右括号和前二个字符之间也不出现空格。详见第4条下方正例提醒。
  2. 【强制】if/for/while/switch/do等保留字与左右括号之间都无法不加空格。
  3. 【强制】任何运算符左右必须加多少个空格。

  表达:运算符包括赋值运算符=、逻辑运算符&&、加减乘除符号、三目运营符等。

  1. 【强制】缩进采纳陆个空格,禁止利用tab字符。
    注解: 若是运用 tab 缩进,必须安装 缩进,必须设置 缩进,必须设置
    缩进,必须安装 缩进,必须安装 缩进,必须安装 1个 tab 为 5个空格。 IDEA
    设置 tab 为 5个空格时, 请勿勾选 Use tab character ;而在 eclipse
    中,必须勾选 insert spaces for tabs 。
    正例: (涉及1-5点)

    public static void main(String args[]) {

         // 缩进4个空格
         String say = "hello";
         // 运算符的左右必须有一个空格
         int flag = 0;
         // 关键词if与括号之间必须有一个空格,括号内的f与左括号,0与右括号不需要空格
         if (flag == 0) {
             System.out.println(say);
         }
         // 左大括号前加空格且不换行;左大括号后换行
         if (flag == 1) {
             System.out.println("world");
             // 右大括号前换行,右大括号后有else,不用换行
         } else {
             System.out.println("ok");
             // 在右大括号后直接结束,则必须换行
         }
     }
    
  2. 【强制】单行字符数限不超过 120 个,超出须求换行时 个,超出须要换行时
    听从如下原则:

  1) 第贰行相对一缩进 四个空格,从第叁行先导不再接续缩进参考示例。

  2) 运算符与下文一起换行。

  3) 方法调用的点符号与下文一起换行。

  4) 在多少个参数超长,逗号后开展换行。

  5) 在括号前不要换行,见反例。

  正例:
    StringBuffer sb = new StringBuffer();
    //超越1二十个字符的图景下,换行缩进几个空格,并且方法前的点符号一起换行
    sb.append(“zi”).append(“xin”)…
    .append(“huang”)…
    .append(“huang”)…
    .append(“huang”);
  反例:
    StringBuffer sb = new StringBuffer();
    //超越1十九个字符的状态下,不要在括号前换行
    sb.append(“zi”).append(“xin”)…append
    (“huang”);
    //参数很多的不二法门调用只怕当先1十八个字符,不要在逗号前换行
    method(args1, args2, args3, …
    , argsX);

  1. 【强制】方法参数在概念和扩散时,多少个参数逗号前边必须加空格。

  正例:下例中实参的”a”,后面必需要有二个空格。
    method(“a”, “b”, “c”);

  1. 【强制】IDE的text file encoding设置为UTF-8;
    IDE中文件的换行符使用Unix格式,不要使用windows格式。
  2. 【推荐】没有需要扩展多少空格来使某一行的字符与上一行的附和字符对齐。

  正例:

int a = 3;
long b = 4L;
float c = 5F;
StringBuffer sb = new StringBuffer();

证实:增添sb这一个变量,即使需求对齐,则给a、b、c都要追加多少个空格,在变量相比较多的境况下,是一种累赘的作业。
10.
【推荐】方法体内的实施语句组、变量的概念语句组、不相同的政工逻辑之间如故不相同的语义之间插入2个空行。相同业务逻辑和语义之间不要求插入空行。

  说明:没有必要插入多行空格举行隔开。

图片 4

(一) 命名规约

  1. 【强制】
    代码中的命名均不可以以下划线或美金符号发轫,也无法以下划线或韩元符号为止。

  反例: _nam / __name / $Object / name_  / name$ / Object$

  1. 【强制】
    代码中的命名严禁利用拼音与英文混合的点子,更分裂意直接动用汉语的主意。

  表明:正确的英文拼写和语法可以让阅读者易于精通,防止歧义。注意,即便纯拼音命名格局也要制止使用。

  反例: DaZhePromotion [打折] / getPingfenByName() [评分] / int
某变量 = 3

  正例: alibaba / taobao / youku / hangzhou
等国际通用的称号,可视同英文。
3.
【强制】类名使用UpperCamelCase风格,必须听从驼峰格局,但以下处境差距:(领域模型的相干命名)DO
/ BO / DTO / VO等。

  正例:MarcoPolo / UserDO / XmlService / TcpUdpDeal / TaPromotion

  反例:macroPolo / UserDo / XMLService / TCPUDPDeal / TAPromotion
4.
【强制】方法名、参数名、成员变量、局地变量都合并运用lowerCamelCase风格,必须遵守驼峰方式。

  正例: localValue / getHttpMessage() / inputUserId
5.
【强制】常量命名全体大写,单词间用下划线隔开,力求语义表明完整清楚,不要嫌名字长。

  正例: MAX_STOCK_COUNT

  反例: MAX_COUNT
6.
【强制】抽象类命名使用Abstract或Base开始;相当类命名使用Exception结尾;测试类命名以它要测试的类的名目开端,以Test结尾。

  1. 【强制】中括号是数组类型的一某些,数组定义如下:String[] args;

  反例:请勿使用String args[]的方式来定义。
8.
【强制】POJO类中布尔类型的变量,都毫不加is,否则部分框架解析会引起种类化错误。

  反例:定义为主导数据类型boolean
isSuccess;的性质,它的不二法门也是isSuccess(),奥德赛PC框架在反向解析的时候,“以为”对应的性情名称是success,导致属性获取不到,进而抛出相当。
9.
【强制】包名统一运用小写,点分隔符之间有且仅有2个自然语义的土耳其共和国(Türkiye Cumhuriyeti)语单词。包名统一行使单数格局,不过类名假若有复数含义,类名可以行使复数格局。

   正例:
应用工具类包名为com.alibaba.open.util、类名为MessageUtils(此规则参考spring的框架结构)

  1. 【强制】杜绝完全不规范的缩写,防止望文不知义。

  反例: AbstractClass“缩写”命名成AbsClass;condition“缩写”命名成
condi,此类随意缩写严重降低了代码的可阅读性。

  1. 【推荐】如若接纳到了设计情势,指出在类名中展示出具体形式。

  表明:将设计情势突显在名字中,有利于阅读者飞速掌握架构设计思想。

  正例:public class OrderFactory;

     public class LoginProxy;

     public class ResourceObserver;

  1. 【推荐】接口类中的方法和性质不要加别的修饰符号(public
    也休想加),保持代码的简洁性,并累加有效的Javadoc注释。尽量不要在接口里定义变量,假诺一定要定义变量,肯定是与接口方法有关,并且是整套应用的基础常量。

  正例:接口方法签名:void f(); 接口基础常量表示:String COMPANY =
“alibaba”;

  反例:接口方法定义:public abstract void f();
表达:JDK8中接口允许有默许已毕,那么那些default方法,是对具备落成类都有价值的暗许完毕。

  1. 接口和兑现类的命名有两套规则:

  1)【强制】对于Service和DAO类,基于SOA的意见,暴光出来的劳务一定是接口,内部的兑现类用Impl的后缀与接口不同。

  正例:CacheServiceImpl实现CacheService接口。

   2) 【推荐】
假诺是描摹能力的接口名称,取对应的形容词做接口名(平常是–able的款式)。

  正例:AbstractTranslator实现 Translatable。
14.
【参考】枚举类名指出带上Enum后缀,枚举成员名称须要全大写,单词间用下划线隔开。

  表达:枚举其实就是例外的常量类,且构造方法被专擅认同强制是私有。

  正例:枚举名字:DealStatusEnum,成员名称:SUCCESS /
UNKOWN_REASON。

  1. 【参考】各层命名规则:

   A) Service/DAO层方法命名规则

    1) 获取单个对象的措施用get做前缀。

    2) 获取多少个对象的形式用list做前缀。

    3) 获取计算值的办法用count做前缀。

    4) 插入的法门用save(推荐)或insert做前缀。

    5) 删除的艺术用remove(推荐)或delete做前缀。

    6) 修改的方法用update做前缀。

  B) 领域模型命名规则

    1) 数据对象:xxxDO,xxx即为数据表名。

    2) 数据传输对象:xxxDTO,xxx为工作领域相关的称呼。

    3) 浮现对象:xxxVO,xxx一般为网页名称。

    4) POJO是DO/DTO/BO/VO的统称,禁止命名成xxxPOJO。

Redis常常有三个利用途径:客户端静态分片,一致性哈希;通过Proxy分片,即Twemproxy;还有就是合法的Redis
Cluster,但时至明天无2个新本子。随后刘奇更详实的解析了为啥不使用Twemproxy和Redis
Cluster:

(一) 格外处理

1.
【强制】不要捕获Java类库中定义的持续自RuntimeException的运行时十二分类,如:IndexOutOfBoundsException
/ NullPointerException,那类卓殊由程序员预检查来躲避,保证程序健壮性。

  正例:if(obj != null) {…}

  反例:try { obj.method() } catch(NullPointerException e){…}
2.
【强制】格外不要用来做流程控制,条件决定,因为拾壹分的拍卖功能比标准分支低。
3.
【强制】对大段代码进行try-catch,那是不负义务的显示。catch时请分清稳定代码和非稳定代码,稳定代码指的是无论怎样不会出错的代码。对于非稳定代码的catch尽或许举行区分万分类型,再做相应的那多少个处理。
4.
【强制】捕获非常是为了处理它,不要捕获了却怎么都不处理而废弃之,如若不想处理它,请将该尤其抛给它的调用者。最外层的事情使用者,必须处理分外,将其转会为用户可以知晓的故事情节。
5.
【强制】有try块放到了政工代码中,catch非凡后,假设急需回滚事务,一定要留意手动回滚事务。
6.
【强制】finally块必须对财富对象、流对象举行倒闭,有特别也要做try-catch。

  表明:假使JDK7,可以拔取try-with-resources形式。
7.
【强制】不能在finally块中行使return,finally块中的return重返后措施为止执行,不会再实践try块中的return语句。
8.
【强制】捕获至极与抛非常,必须是截然协作,大概捕获相当是抛十分的父类。

  说明:若是预想对方抛的是绣球,实际吸收的是铅球,就会发出意料之外处境。
9.
【推荐】方法的再次回到值可以为null,不强制重回空集合,或许空对象等,必须添加注释丰裕表明什么状态下会回去null值。调用方须求开展null判断避免NPE难题。

  表达:本规约显明防止NPE是调用者的义务。即便被调用方法重临空集合恐怕空对象,对调用者来说,也并非高枕无忧,必须考虑到长途调用失利,运转时十一分等情景重临null的景色。

  1. 【推荐】避免NPE,是程序员的为主修养,注意NPE爆发的景观:

  1) 再次回到类型为包装数据类型,有只怕是null,返回int值时注意判空。

    反例:public int f(){ return Integer对象};
如果为null,自动解箱抛NPE。

  2) 数据库的询问结果只怕为null。

  3) 集合里的要素就是isNotEmpty,取出的数码成分也说不定为null。
  4) 远程调用再次回到对象,一律需求进行NPE判断。

  5) 对于Session中获得的数码,提议NPE检查,防止空指针。

  6) 级联调用obj.getA().getB().getC();一而再串调用,易暴发NPE。
11.
【推荐】在代码中采取“抛至极”照旧“重回错误码”,对于店铺外的http/api开放接口必须使用“错误码”;而利用内部推荐分外抛出;跨应用间LacrossePC调用优先考虑接纳Result格局,封装isSuccess、“错误码”、“错误简短音讯”。
表达:关于SportagePC方法重返形式利用Result形式的说辞:

  1)使用抛格外再次回到格局,调用方即便没有捕获到就会发生运维时不当。

  2)若是不加栈新闻,只是new自定义很是,加入本身的敞亮的error
message,对于调用端化解难题的声援不会太多。若是加了栈音信,在反复调用出错的景观下,数据种类化和传导的性质损耗也是难点。

  1. 【推荐】定义时区分unchecked / checked
    非凡,防止直接利用RuntimeException抛出,更不容许抛出Exception可能Throwable,应采纳有工作含义的自定义非常。推荐业界已定义过的自定义分外,如:DAOException
    / ServiceException等。
  2. 【参考】防止出现重复的代码(Don’t Repeat Yourself),即D奥德赛Y原则。
    表达:随意复制和粘贴代码,必然会促成代码的重新,在后头需要修改时,必要修改全体的副本,简单遗漏。要求时抽取共性方法,或然抽象公共类,甚至是共用模块。

  正例:2个类中有多个public方法,都急需进行数行相同的参数校验操作,这么些时候请抽取:
  private boolean checkParam(DTO dto){…}

codis-config。Codis 的管理工具,援助添加/删除Redis节点、添加/删除Proxy节点、发起数据迁移等操作。codis-config自带了2个http server,会运维一个dashboard,用户可以在浏览器上观赛 Codis 集群的运维意况。

(六) 并发处理

  1. 【强制】获取单例对象需要有限援救线程安全,其中的办法也要力保线程安全。

  表达:财富驱动类、工具类、单例工厂类都急需专注。

  1. 【强制】创造线程或线程池时请钦赐有含义的线程名称,方便出错时回想。

  正例:

public class TimerTaskThread extends Thread {
    public TimerTaskThread(){
    super.setName("TimerTaskThread"); 
    ...
}
  1. 【强制】线程能源必须通过线程池提供,不容许在利用中自行显式创造线程。

  表达:使用线程池的益处是减掉在开立和销毁线程上所花的日子以及系统财富的支付,化解能源缺乏的标题。假使不使用线程池,有或者造成系统创建大气同类线程而招致消耗完内存照旧“过度切换”的标题。

  1. 【强制】线程池不相同意行使
    Executors去成立,而是经过ThreadPoolExecutor去创立,那样的处理格局让写同学越来越明朗线程池运营规则,避财富耗尽危机。

  表达: Executors再次回到的线程池对象的流弊如下 :

  1)FixedThreadPool和 SingleThread:

    允许的央浼队列长度为
Integer.MAX_VALUE,只怕会积聚大量的伸手,从而造成 OOM。

  2)CachedThreadPool和 ScheduledThreadPool: 允许的创办线程数量为
Integer.MAX_VALUE,只怕会创建大气的线程,从而造成 OOM。

  1. 【强制】SimpleDateFormat
    是线程不安全的类,一般不要定义为static变量,倘使定义为static,必须加锁,大概应用DateUtils工具类。

  正例:注意线程安全,使用DateUtils。亦推荐如下处理:

private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {
    @Override
    protected DateFormat initialValue() {
        return new SimpleDateFormat("yyyy-MM-dd");
    }
 }

证实:如果是JDK8的使用,可以使用Instant代替Date,LocalDateTime代替Calendar,Date提姆eFormatter代替Simpledateformatter,官方给出的诠释:simple
beautiful strong immutable thread-safe。

6.
【强制】高并发时,同步调用应该去考量锁的质量损耗。能用无锁数据结构,就不用用锁;能锁区块,就无须锁整个方法体;能用对象锁,就毫无用类锁。
7.
【强制】对多个财富、数据库表、对象同时加锁时,要求保持一致的加锁顺序,否则大概会促成死锁。

  表明:线程一需求对表A、B、C依次百分百加锁后才方可拓展更新操作,那么线程二的加锁顺序也不可能不是A、B、C,否则只怕出现死锁。
8.
【强制】并发修改同一记录时,幸免更新丢失,要么在应用层加锁,要么在缓存加锁,要么在数量库层使用乐观锁,使用version作为立异依照。

  表明:假如老是访问争辨可能率小于1/5,推荐使用乐观锁,否则使用悲观锁。乐观锁的重试次数不得低于1遍。
9.
【强制】四线程并行处理定时义务时,Timer运营多少个TimeTask时,只要其中之一没有捕获抛出的尤其,其它职责便会自动截至运维,使用ScheduledExecutorService则没有这么些标题。
10.
【推荐】使用CountDownLatch举行异步转同步操作,每种线程退出前务必调用countDown方法,线程执行代码注意catch分外,确保countDown方法可以推行,幸免主线程不大概履行至countDown方法,直到超时才回去结果。

  表达:注意,子线程抛出尤其堆栈,无法在主线程try-catch到。
11.
【推荐】避免Random实例被四线程使用,即便共享该实例是线程安全的,但会因竞争同一seed
导致的特性下降。
  表达:Random实例包罗java.util.Random 的实例大概 Math.random()实例。

  正例:在JDK7之后,可以向来运用API ThreadLocalRandom,在
JDK7从前,可以做到各种线程二个实例。

  1. 【推荐】通过重复检查锁(double-checked
    locking)(在产出场景)完毕延迟起先化的优化难题隐患(可参考 The
    “Double-Checked Locking is Broken”
    Declaration),推荐难题消除方案中较为简单一种(适用于JDK5及以上版本),将目的属性声明为
    volatile型。

反例:

class Foo {
    private Helper helper = null;

    public Helper getHelper() {
        if (helper == null)
            synchronized (this) {
                if (helper == null)
                    helper = new Helper();
            }
        return helper;
    }
    // other functions and members...
}

13.
【参考】volatile消除三十二线程内存不可知难题。对于一写多读,是足以消除变量同步难点,然则只要多写,同样无法缓解线程安全难题。即便是count++操作,使用如下类达成:AtomicInteger
count = new AtomicInteger(); count.addAndGet(1);
尽管是JDK8,推荐使用LongAdder对象,比AtomicLong质量更好(裁减乐观锁的重试次数)。

  1. 【参考】
    HashMap在体积不够进行resize时由于高并发可能出现死链,导致CPU飙升,在支付进度中注意避开此风险。
    15.
    【参考】ThreadLocal不能化解共享对象的更新难题,ThreadLocal对象提出利用static修饰。那么些变量是指向2个线程内享有操作共有的,所以设置为静态变量,全部此类实例共享此静态变量
    ,约等于说在类首回被采取服装载,只分红一块存储空间,全体此类的目的(只如若以此线程钦定义的)都足以操控那些变量。

Twemproxy:最大的痛点是不能够平滑的扩容大概缩容,甚至修改配置都急需重启服务;其次,不可运行,甚至不曾Dashboard。

(八) 注释规约

1.
【强制】类、类性质、类措施的注释必须运用Javadoc规范,使用/**内容*/格式,不得选取//xxx格局。

  表明:在IDE编辑窗口中,Javadoc格局会唤醒相关怀释,生成Javadoc可以正确输出相应注释;在IDE中,工程调用方法时,不进来艺术即可上浮提醒方法、参数、再次来到值的含义,升高阅读功效。
2.
【强制】全数的虚幻方法(包蕴接口中的方法)必须求用Javadoc注释、除了再次来到值、参数、非凡表明外,还必须指出该措施做什么样业务,达成如何功效。

  表达:对子类的贯彻须要,或然调用注意事项,请一并表明。

  1. 【强制】全部的类都必须抬高创制者音信。
    4.
    【强制】方法内部单行注释,在被诠释语句上方另起一行,使用//注释。方法内部多行注释使用/*
    */注释,注意与代码对齐。
  2. 【强制】全体的枚举类型字段必必要有注释,表明各个数据项的用处。
    6.
    【推荐】与其“半吊子”英文来诠释,不如用汉语注释把题目说明白。专有名词与首要字保持英文原文即可。

  反例:“TCP连接超时”解释成“传输控制协议连接超时”,掌握反而费脑筋。
7.
【推荐】代码修改的还要,注释也要进行对应的修改,尤其是参数、重临值、相当、主题逻辑等的改动。

  表明:代码与注释更新不联合,就好像路网与导航软件更新不一致步一样,即使导航软件严重滞后,就错过了领航的意义。

  1. 【参考】注释掉的代码尽量要协作说明,而不是大致的注释掉。

  表明:代码被诠释掉有三种大概:

    1)后续会还原此段代码逻辑。

    2)永久不用。前者即使没有备注消息,难以了然注释动机。后者建议直接删掉(代码仓库保存了历史代码)。

  1. 【参考】对于注释的须求:

  第3 、能够规范反应设计思想和代码逻辑;

  第二 、可以描述业务含义,使别的程序员可以很快领会到代码背后的音讯。完全没有注释的大段代码对于阅读者形同天书,注释是给自己看的,固然隔十分短日子,也能清晰精通当下的思路;注释也是给后者看的,使其可以神速接替本身的行事。
10.
【参考】好的命名、代码结构是自解释的,注释力求提纲挈领准确、表明到位。幸免现身注释的三个极其:过多过滥的注释,代码的逻辑一旦修改,修改注释是一对一大的承负。

反例:
  // put elephant into fridge
  put(elephant, fridge);
措施名put,加上多少个有意义的变量名elephant和fridge,已经认证了那是在干什么,语义清晰的代码不要求十分的注释。
11.
【参考】特殊注释标记,请评释标记人与标记时间。注意及时处理这几个标记,通过标记扫描,平常清理此类标记。线上故障有时候即使缘于这个标记处的代码。

  1) 待办事宜(TODO):( 标记人,标记时间,[揣测处理时间])
表示需求贯彻,但近期还未落到实处的效益。那实质上是一个Javadoc的标签,方今的Javadoc还尚无兑现,但一度被大面积拔取。只好采取于类,接口和方法(因为它是1个Javadoc标签)。
  2) 错误,不或然办事(FIXME):(标记人,标记时间,[展望处理时间])
在诠释中用FIXME标记某代码是荒唐的,而且无法办事,必要立刻矫正的意况。

而在勘察了任何事情后,另二个争议摆在了前方——Proxy恐怕是斯马特 Client:Proxy拥有更好的督察和控制,同时其后端音信亦不易揭露,易于升级;而Smart Client拥有更好的性质,及更低的延时,不过升级起来却比较忙碌。相比种种优劣,他们最终选取了Proxy,不以为奇,在codis开源后,twitter的三个享受提到他们也是依照proxy的宏图。

(三) SQL规约

1.
【强制】不要采用count(列名)或count(常量)来取代count(*),count(*)就是SQL92概念的正规总计行数的语法,跟数据库无关,跟NULL和非NULL无关。

  说明:count(*)会总括值为NULL的行,而count(列名)不会计算此列为NULL值的行。

  1. 【强制】count(distinct col) 统计该列除NULL之外的不另行数量。注意
    count(distinct col1, col2)
    如若中间一列全为NULL,那么即便另一列有分歧的值,也回到为0。
    3.
    【强制】当某一列的值全是NULL时,count(col)的归来结果为0,但sum(col)的回来结果为NULL,由此拔取sum()时需注意NPE难题。

  正例:能够应用如下方式来幸免sum的NPE难点:SELECT
IF(ISNULL(SUM(g)),0,SUM(g)) FROM table;
4.
【强制】使用ISNULL()来判断是或不是为NULL值。注意:NULL与任何值的直白相比较都为NULL。

  表达: 1) NULL<>NULL的回来结果是NULL,而不是false。

      2) NULL=NULL的回来结果是NULL,而不是true。

        3) NULL<>1的回到结果是NULL,而不是true。

  1. 【强制】
    在代码中写分页查询逻辑时,若count为0应间接回到,防止执行后边的分页语句。
  2. 【强制】不得采用外键与级联,一切外键概念必须在应用层消除。
    表明:(概念解释)学生表中的student_id是主键,那么战绩表中的student_id则为外键。即使更新学生表中的student_id,同时触发成绩表中的student_id更新,则为级联更新。外键与级联更新适用于单机低并发,不适合分布式、高并发集群;级联更新是强阻塞,存在数据库更新龙卷风的高风险;外键影响数据库的插入速度。
  3. 【强制】禁止使用存储进度,存储进度难以调试和扩充,更不曾移植性。
    8.
    【强制】数据矫正时,删除和修改记录时,要先select,幸免出现误删除,确认无误才能实施更新语句。
    9.
    【推荐】in操作能幸免则防止,若实在防止不了,须要仔细评估in前边的集合成分数量,控制在一千个以内。
    10.
    【参考】倘若有整个世界化必要,全体的字符存储与代表,均以utf-8编码,那么字符计数方法注意:

  表明: SELECT LENGTH(“轻松工作”); 重临为12 SELECT
CHARACTE奥德赛_LENGTH(“轻松工作”); 再次回到为4
尽管要动用表情,那么使用utfmb4来举办仓储,注意它与utf-8编码的区分。

  1. 【参考】 TRUNCATE TABLE 比 DELETE
    速度快,且使用的体系和作业日志能源少,但TRUNCATE无事务且不触发trigger,有或然引致事故,故不提议在开发代码中运用此语句。

  表明:TRUNCATE TABLE 在听从上与不带 WHERE 子句的 DELETE 语句相同。

既是重新设计,那么Codis首先必须满足自动扩容和缩容的须求,其次则是必须幸免单点故障和单点带宽不足,做2个高可用的种类。在那事后,基于原有的遗留系统,还必须可以轻松地将数据从Twemproxy迁移到Codis,并落实理想的运营和监理。基于那一个,Codis的计划性跃然纸面:

三、MySQL规约

一 、编程规约

(三) 服务器规约

  1. 【推荐】高并发服务器提出调小TCP协议的time_wait超时时间。
    表明:操作系统默许240秒后,才会倒闭处于time_wait状态的接连,在高并发访问下,服务器端会因为处在time_wait的连接数太多,可能不可以建立新的连年,所以须要在服务器上调小此等待值。

  正例:在linux服务器上请通过变更/etc/sysctl.conf文件去修改该缺省值(秒):
net.ipv4.tcp_fin_timeout = 30

  1. 【推荐】调大服务器所支撑的最大文件句柄数(File
    Descriptor,简写为fd)。

  表明:主流操作系统的宏图是将TCP/UDP连接使用与公事一律的措施去管理,即一个一而再对应于3个fd。主流的linux服务器暗中同意所协理最大fd数量为1024,当并发连接数很大时很简单因为fd不足而出现“open
too many files”错误,导致新的连日不能树立。
指出将linux服务器所扶助的最大句柄数调高数倍(与服务器的内存数量相关)。
3.
【推荐】给JVM设置-XX:+HeapDumpOnOutOfMemoryError参数,让JVM遇到OOM场景时输出dump音讯。

  表明:OOM的发生是有可能率的,甚至有规律地相隔数月才出现一例,出现时的现场新闻对查错相当有价值。
4.
【参考】服务器内部重定向使用forward;外部重定向地址使用U锐界L拼装工具类来扭转,否则会带来U奥迪Q5L维护不等同的题目和潜在的吴忠风险。

(五) 集合处理

  1. 【强制】关于hashCode和equals的处理,遵循如下规则:

  1) 只要重写equals,就亟须重写hashCode。

  2)
因为Set存储的是不重复的对象,根据hashCode和equals举办判定,所以Set存储的目标必须重写那三个形式。

  3) 若是自定义对象做为Map的键,那么必须重写hashCode和equals。

    正例:String重写了hashCode和equals方法,所以我们得以充足欣喜地动用String对象作为key来行使。

  1. 【强制】
    ArrayList的subList结果不可强转成ArrayList,否则会抛出ClassCastException很是:java.util.RandomAccessSubList
    cannot be cast to java.util.ArrayList ;

  表明:subList 再次来到的是 ArrayList 的内部类 SubList,并不是 ArrayList
,而是 ArrayList
的3个视图,对于SubList子列表的富有操作最终会反映到原列表上。

  1. 【强制】
    在subList场景中,高度注意对原集合成分个数的改动,会导致子列表的遍历、扩张、删除均发生ConcurrentModificationException
    分外。
  2. 【强制】使用集合转数组的主意,必须运用集合的toArray(T[]
    array),传入的是连串完全一样的数组,大小就是list.size()。

  反例:直接使用toArray无参方法存在难点,此办法重临值只好是Object[]类,若强转其余项目数组将出现ClassCastException错误。

  正例:

List<String> list = new ArrayList<String>(2);
list.add("guan");
list.add("bao");
String[] array = new String[list.size()];
array = list.toArray(array);

表达:使用toArray带参方法,入参分配的数组空间不够大时,toArray方法内部将重新分配内存空间,并赶回新数组地址;如若数组成分大于实际所需,下标为[
list.size()
]的数组成分将被置为null,其它数组元素保持原值,由此最好将艺术入参数组大小定义与集合成分个数一致。

5.
【强制】使用工具类Arrays.asList()把数组转换来集合时,无法接纳其修改集合相关的点子,它的add/remove/clear方法会抛出UnsupportedOperationException卓殊。

  表明:asList的回到对象是五个Arrays内部类,并没有完毕集合的改动章程。Arrays.asList浮现的是适配器形式,只是转换接口,后台的数码仍是数组。
String[] str = new String[] { “a”, “b” }; List list =
Arrays.asList(str);

  第3种情况:list.add(“c”); 运转时特别。

  第②种情景:str[0]= “gujin”; 那么list.get(0)也会跟着修改。

  1. 【强制】泛型通配符<? extends
    T>来采用重回的数目,此写法的泛型集合不能利用add方法。

  表达:苹果装箱后回去一个<? extends
Fruits>对象,此目的就不可以往里加其余水果,包括苹果。
7.
【强制】不要在foreach循环里举办成分的remove/add操作。remove成分请使用Iterator格局,假诺出现操作,必要对Iterator对象加锁。

  反例:

List<String> a = new ArrayList<String>();
a.add("1");
a.add("2");
for (String temp : a) {
    if ("1".equals(temp)) {
        a.remove(temp);
    }
}

表明:以上代码的施行结果一定会高于我们的意料,那么试一下把“1”换到“2”,会是一致的结果吗?
正例:

Iterator<String> it = a.iterator();
while (it.hasNext()) {
    String temp = it.next();
    if (删除元素的条件) {
        it.remove();
    }
}
  1. 【强制】
    在JDK7版本以上,Comparator要满足自反性,传递性,对称性,不然Arrays.sort,Collections.sort会报IllegalArgumentException十分。

  说明:

  1) 自反性:x,y的可比结实和y,x的可比结实相反。

  2) 传递性:x>y,y>z,则x>z。

  3) 对称性:x=y,则x,z比较结实和y,z比较结实一致。

  反例:下例中从未处理相等的情事,实际行使中或然会出现分外:

new Comparator<Student>() {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.getId() > o2.getId() ? 1 : -1;
    }
}
  1. 【推荐】集合伊始化时,尽量钦命集合开端值大小。
    表达:ArrayList尽量使用ArrayList(int initialCapacity) 发轫化。

  2. 【推荐】使用entrySet遍历Map类集合KV,而不是keySet形式展开遍历。

  表明:keySet其实是遍历了1回,一次是转为Iterator对象,另一遍是从hashMap中取出key所对应的value。而entrySet只是遍历了一回就把key和value都放到了entry中,作用更高。倘诺是JDK8,使用Map.foreach方法。

  正例:values()重临的是V值集合,是一个list集合对象;keySet()再次回到的是K值集合,是三个Set集合对象;entrySet()再次回到的是K-V值组合集合。

  1. 【推荐】高度注意Map类集合K/V能无法储存null值的事态,如下表格:
集合类 Key Value Super 说明
Hashtable 不允许为null 不允许为null Dictionary 线程安全
ConcurrentHashMap 不允许为null 不允许为null AbstractMap 分段锁技术
TreeMap 不允许为null 允许为null AbstractMap 线程不安全
HashMap 允许为null 允许为null AbstractMap 线程不安全

 

 

 

 

  反例:
由于HashMap的烦扰,很两人认为ConcurrentHashMap是足以置入null值,注意存储null值时会抛出NPE卓殊。
12.
【参考】合理利用好集合的有序性(sort)和平静(order),防止集合的无序性(unsort)和不安静(unorder)带来的负面影响。

  表达:稳定性指集合每一趟遍历的成分次序是早晚的。有序性是指遍历的结果是按某种相比规则依次排列的。如:ArrayList是order/unsort;HashMap是unorder/unsort;TreeSet是order/sort。
13.
【参考】利用Set成分唯一的性状,可以快捷对贰个聚集举行去重操作,幸免选择List的contains方法开展遍历、相比、去重操作。

发表评论

电子邮件地址不会被公开。 必填项已用*标注