Swagger

Swagger

WebService提供了WSDL来描述提供的WS调用接口,还提供了其它工具来生成WS客户端代码。REST则可以使用Swagger规则来描述Restful接口,以及通过Swagger UI来测试Restful接口。

Swagger2是通过在接口上提供一系统注解来描述接口,而Swagger3则是通过一个swagger规范的json文件来描述。

Swagger使用指南
https://my.oschina.net/dlam/blog/808315
swagger2常用注解说明
https://blog.csdn.net/u014231523/article/details/76522486

Spring boot项目,使用maven打包包含本地jar
http://www.jianshu.com/p/4f88837945c9

swagger2markup

1.单独启动要输出文档的swagger服务。
2.在@Test中编写Swagger2MarkupConverter部分代码,或在pom.xml中配置。
3.运行mvn test,生成.adoc文件。
4.在Maven视图中,运行Plugins下的asciidoctor:process-asciidoc,生成html文件。
http://blog.didispace.com/swagger2markup-asciidoc/

进程管理工具

pm2

pm2 = P (rocess) M (anager)2,是可以用于生产环境的Nodejs的进程管理工具,它内置一个负载均衡,可以保证服务不会中断一直在线,并且提供0秒reload功能,还有其他一系列进程管理、监控功能。

pm2的安装和使用

npm install -g pm2
pm2 start app.js
pm2 startup, pm2 save 两条命令,用来保证服务器启动时,pm2管理的程序自动运行。
pm2 reload all
pm2 restart [id]
pm2 logs [id]
pm2 delete [id]
pm2 list
pm2 show [id] 或者 # pm2 info [id]  #查看进程详细信息

更多pm2常用的命令用法介绍
http://i5ting.github.io/node-deploy-practice/
http://www.111cn.net/sys/linux/120062.htm
http://www.pangjian.info/2016/12/02/deploy-nodejs-pm2-1/?utm_medium=referral

可以通过自定义启动文件,来管理jar包。创建xx.json,示例内容如下:

{
    "name": "cogrowth-api",
    "script": "java",
    "args": [
        "-Xms64m",
        "-Xmx512m",
        "-Dspring.profiles.active=pub",
        "-jar",
        "cogrowth-api-1.0.jar",
    ],
    "exec_interpreter": "",
    "exec_mode": "fork"
}
pm2 start xx.json

exec_interpreter: NodeJs解析器,本文不适用
exec_mode: 执行模式[cluster|fork]这个针对NodeJs应用的配置,非NodeJs应用统一fork
日志路径在~/.pm2/logs,stdout和stderr被分开存放,程序中的所有stdout和stderr都被收集方便查错。

Java开发库

Guava

Guava是一种基于开源的Java库,其中包含谷歌正在由他们很多项目使用的很多核心库。这个库是为了方便编码,并减少编码错误。这个库提供用于集合,缓存,支持原语,并发性,常见注解,字符串处理,I/O和验证的实用方法。

生成PDF

freemarker

使用freemarker从模板+数据,生成html文件。

Configuration cfg = new Configuration(Configuration.VERSION_2_3_28);
        try {
            cfg.setClassForTemplateLoading(this.getClass(), "/static/");
            Template template=cfg.getTemplate("content.html");
            PrintWriter pw = new PrintWriter(new File(destPath));
            template.process(params, pw);
            pw.close();//关闭流
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException e) {
            e.printStackTrace();
        }

生成Docker镜像的Dockerfile

FROM kenkoooo/ubuntu-openjdk8

RUN apt-get update \
    && apt-get install -y \
        curl \
        xfonts-base \
        xfonts-75dpi \
    && apt-get clean

#安装wkhtmltox(0.12.5版本没有生成目录,改用wkhtmltox_0.12.6版本)
#可以在https://builds.wkhtmltopdf.org/0.12.6-dev/中寻找对应系统的版本
RUN curl "https://builds.wkhtmltopdf.org/0.12.6-dev/wkhtmltox_0.12.6-0.20180618.3.dev.e6d6f54.xenial_amd64.deb" -L -o "wkhtmltopdf.deb"
RUN dpkg -i ./wkhtmltopdf.deb
RUN apt-get install -f
RUN rm -rf wkhtmlto*
ENV LANG C.UTF-8

#安装chrome-headless
RUN apt-get install --assume-yes libxss1 libappindicator1 libindicator7
RUN wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
RUN apt install --assume-yes ./google-chrome*.deb
RUN rm -rf google-chrome*

#安装chrome-driver
#可以在线下载chromedriver_linux64.zip
#RUN wget https://chromedriver.storage.googleapis.com/73.0.3683.68/chromedriver_linux64.zip
#也可以拷贝下载好的chromedriver_linux64.zip
COPY chromedriver_linux64.zip .
RUN unzip chromedriver_linux64.zip
RUN cp chromedriver /usr/local/bin/chromedriver
RUN chmod 755 /usr/local/bin/chromedriver
RUN rm -rf chromedriver_linux64*

CPU架构

iPhone CPU架构

架构对应的设备:

 armv6 设备: iPhone, iPhone2, iPhone3G, 第一代、第二代 iPod Touch
 armv7 设备: iPhone3GS, iPhone4, iPhone4S;iPad, iPad2, iPad3(The New iPad), iPad mini;iPod Touch 3G, iPod Touch4
 armv7s设备: iPhone5, iPhone5C, iPad4(iPad with Retina Display)
 arm64 设备: iPhone5S, iPad Air, iPad mini2(iPad mini with Retina Display)

Android CPU架构

ABI:ApplicationBinary Interface 应用程序二进制接口,定义了二进制文件(尤其是.so文件),如何运行在相应的系统平台上,从使用的指令集、内存对齐到可用的系统函数库。
EABI:Embedded application binary interface 嵌入式应用二进制接口。

armeabi: 第5代、第6代的ARM处理器,是针对所有的arm cpu,只要支持arm的指令集就可以,早期的手机用的比较多。v7a,v8a是针对arm后来出的指令集版本制定的cpu如符合arm7指令集的cpu。
armeabi-v7a: 第7代及以上的 32位ARM 处理器,是针对有浮点运算或高级扩展功能的arm v7 cpu,2011年15月以后的生产的大部分Android设备都使用它.
arm64-v8a: 第8代、64位ARM处理器,很少设备,三星 Galaxy S6是其中之一。
x86: 平板、模拟器用得比较多。
x86_64: 64位的平板。

项目包含总结

如果项目只包含了 armeabi,那么在所有Android设备都可以运行;
如果项目只包含了 armeabi-v7a,除armeabi架构的设备外都可以运行;
如果项目只包含了 x86,那么armeabi架构和armeabi-v7a的Android设备是无法运行的; 
如果同时包含了 armeabi, armeabi-v7a和x86,所有设备都可以运行,程序在运行的时候去加载不同平台对应的so,这是较为完美的一种解决方案,同时也会导致包变大。

例如,如果只想支持armeabi-v7a,需要在gradle中配置

    defaultConfig {
        ndk {
            abiFilters "armeabi-v7a"
        }
    }

默认情况下,打包后会自动生成armeabi 到 x86的所有文件夹。这就有可能导致一些x86的设备因为在x86文件夹下找不到so文件,而使应用崩溃。

Spring Cloud

Spring官方在spring boot的基础上,对Netflix开源组件进一步封装,提供了一个名为Spring Cloud的开源的一套云应用开发工具,一个非常优秀的服务治理框架。另一个非常优秀的服务治理框架 Dubbo。
Spring Cloud专注于提供良好的开箱即用经验的典型用例和可扩展性机制覆盖。

Netflix公司和Pivotal公司

Netflix是一家视频网站,该网站上的美剧应该是最火的。Netflix的微服务大规模的应用,在技术上毫无保留的把一整套微服务架构核心技术栈开源了出来,叫做Netflix OSS。

Pivotal把Netflix开源的一整套核心技术产品线做了一系列的封装,就变成了Spring Cloud,Spring Cloud到现在为止不只有Netflix提供的方案可以集成,但其中Netflix是最成熟的。

Spring Cloud微服务架构

在Spring Cloud微服务系统中,一种常见的负载均衡方式是:客户端的请求首先经过负载均衡(zuul、Ngnix),再到达服务网关(zuul集群),然后再到具体的服务。服务统一注册到高可用的服务注册中心集群,服务的所有的配置文件由配置服务管理,配置服务的配置文件放在git仓库,方便开发人员随时改配置。

Spring Cloud微服务架构中的几个基础服务治理组件:

  • 服务注册中心:Eureka Server
  • 注册服务:Eureka Client
  • 发现服务:Discovery Client
  • 负载均衡:Load Balance、RestTemplate、Ribbon,Feign
  • 断路器:Hystrix,另外Feign自带断路器功能。断路打开后,可以避免连锁故障,fallback方法可以直接返回一个固定值。Turbine可以汇聚监控信息,并提供给Hystrix Dashboard集中展示和监控。
  • 分布式配置中心:Spring Cloud Config,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。两个角色,config server config client。
  • 消息总线:Spring Cloud Bus,将分布式节点加入消息总线,利用轻量的消息代理(message broker 经纪人)使得应用程序可以高效地解耦通信过程。在众多的开源消息中间件产品中,当前版本的spring cloud bus仅支持两款中间件产品:rabbitmq和kafka两个binder,也可以自己写binder扩展。
  • Api gateway:微服务场景下,将细粒度的服务组合起来提供一个粗粒度的服务,所有请求都导入一个统一的入口,那么整个服务只需要暴露一个api,对外屏蔽了服务端的实现细节,也减少了客户端与服务器的网络调用次数。与业务关系并不大的通用处理逻辑可以从Api gateway中剥离出来,Api gateway仅仅负责服务的编排与结果的组装。这样对一些后端微服务进行了代理,避免了各个后端服务独立管理CORS和验证问题。
  • 路由网关转发和过滤器:zuul,zuul还能过滤做一些安全验证,zuul默认和Ribbon结合实现了负载均衡的功能。Zuul是Netflix 提供的一个开源组件,是致力于在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架。zuul静态路由配置规则:
    分布式系统中未使用注册服务时,service1的名称可更换,下面的配置中.path中的**会被添加到.url的后面。若不配置.url,可直接使用service1作为请求路径。

    zuul.routes.service1.url=http://localhost:8002/storage/
    zuul.routes.service1.path=/proxy/**
    
  • 动态路由
    动态路由需要达到配置持久化和动态刷新的效果。即不仅要能满足从spring的配置文件properties加载路由信息,还需要从数据库加载配置。另外一点是,在容器启动后,能动态刷新内存中的路由信息,达到不停机维护路由信息的效果。
  • 数据监控,Spring Boot Actuator 提供了强大的应用自省功能,提供了丰富的 Endpoints 的信息,覆盖 Spring Boot 应用程序运行的方方面面。这些指标都是以 JSON 接口数据的方式呈现。而使用 Spring Boot Admin 可以实现这些 JSON 接口数据的界面展现,结合可视化的 Spring Boot Admin 管理界面,一切显得如此“高大上”。
  • 链路追踪:Sleuth。

Ribbon、Feign与Nginx

Feign与Ribbon区别之一是调用方式不同。Ribbon需要自己构建http请求使用RestTemplate发送给其它服务,步骤繁琐。Feign则是在Ribbon的基础上进行了改进,采用接口的方式将需要调用的其他服务的方法定义成抽象方法。Feign 是一个声明web服务客户端,Feign 是一个使用起来更加方便的HTTP 客戶端,使用起来就像是调用自身工程的方法。Feign包含了ribben,feign是远程调用的,ribbon是做负载均衡。

Nginx是服务端负载均衡,即请求由 nginx 服务器端进行转发。负载均衡、反向代理,代理后端服务器。隐藏真实地址,防火墙,不能外网直接访问,安全性较高。

Ribbon是客户端负载均衡, 是从 eureka 注册中心服务器端上获取服务注册信息列表,缓存到本地,然后在本地实现轮询负载均衡策略,即在客户端实现负载均衡。

应用场景的区别:Nginx 适合于服务器端实现负载均衡 比如 Tomcat ,Ribbon 适合与在微服务中 RPC 远程调用实现本地服务负载均衡,比如 Dubbo、SpringCloud 中都是采用本地负载均衡。

Cloud与Boot与微服务的关系

微服务是一种架构的理念,提出了微服务的设计原则,从理论为具体的技术落地提供了指导思想。
Spring Boot是一套快速配置脚手架,可以基于Spring Boot快速开发单个微服务。Spring Cloud是一个基于Spring Boot实现的服务治理工具包。Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架。Spring Boot/Cloud是微服务实践的最佳落地方案。

Cloud版本变化

  • Spring Cloud Finchley 在2018年 06 月 19 日正式发布,这次的重大发布主要带来了以下 4 项重大更新。
    (1)新增 Spring Cloud Gateway 组件
    Spring Cloud Gateway 是一个基于 Spring Webflux 和响应式 Netty 的下一代 API 网关,用来替换 Spring Cloud Netflix Zuul。它提供了更加简单的动态路由,以及针对每个路由的过滤器(如地址重写、断路器、添加/删除请求头、限流和安全等)。
    (2)新增 Spring Cloud Function 组件
    Spring Cloud Function 的主要功能如下:
    通过一系列函数推进业务逻辑的实现;
    将业务逻辑的开发生命周期从任何特定运行目标中分离,以便相同的代码可以作为一个 Web 端点、一个流处理器或一个任务来运行;
    支持一个跨 serverless providers 的统一编程模型,并拥有独立运行的能力(本地或 PaaS 平台);
    支持在 serverless providers 上面启用 Spring Boot 特性,如自动配置、依赖注入、指标等;
    (3)兼容 Spring Boot 2.0.x
    Finchley 版本是基于 Spring Boot 2.0.x 构建的,官方建议不要与 Spring Boot 1.5.x 及之前的版本一起工作。
    (4)最低支持 JDK 1.8
    JDK 门槛提高了,1.8 毕竟是现在的主流。
  • Camden。
  • Dalston将于 2018 年 12 月结束生命周期。
  • Edgware伴随着 Spring Boot 1.5.x 的结束而结束生命周期。

参考:
《Spring Cloud微服务实战》
http://blog.didispace.com/
http://blog.csdn.net/forezp/article/details/70148833
http://blog.csdn.net/u010066934/article/details/54232622

Spring Cloud 文档
http://cloud.spring.io/spring-cloud-static/spring-cloud.html#_features

PiggyMetrics微服务编译运行解析
http://blog.csdn.net/nihaomanihao11/article/details/73822681
http://blog.csdn.net/rickiyeat/article/details/60792925

中小型互联网公司微服务实践-经验和教训
http://www.ityouknow.com/springcloud/2017/10/19/micro-service-practice.html

Spring Cloud各个微服务之间用HTTP通信的效率的讨论

Spring cloud的http从几个方面可以优化:1、换成okhttp3。2、应用中不要做异步传输,防止异步等待,如果遇到异步场景,一定要利用好消息队列和缓存。3、如果http1.1,有些场景利用keep-alive,减少连接损耗。4、可以考虑尝试HTTP/2。替换原有的Jackson序列化为更快的或者更适合的序列化方式(例如fastJson,kryo);还有http连接池替换实现等都会有可观的性能提升。
一般场景下spring cloud的性能足以满足大多数需求,最终要看服务拆分是否合理和业务场景的实际需求。
rpc固然速度比http快,但是稳定性、数据传输的可靠性、熔断保护、更方便的链路监控和追踪,这时候HTTP的优势就体现了。
http传输内容上比rpc多了几十字节的头,对于一般都是几k到几十上百k的数据,几十个字节的头影响不大。
如果使用feign,会默认加keepalive也是长链接,就多了http的20字节报文头,但是开发效率却提升了几个档次。
目前很多大型项目多语言共存,http是最通用的协议,可以很好地解决跨语言跨平台兼容性。比如Dubbo协议,无法简单地实现跨语言。http交互只是协议比较重,但不会慢太多,追求单机极致性能的确可以考虑换协议。
微服务的一个重要理念就是水平扩展,慢这个问题通过业务设计还有多实例部署可以很好地提速。http协议很成熟,并且特点熟知:1.支持客户/服务器模式。2.简单快速。3.灵活。4.无连接。5.无状态。也是一个速度与开发成本还有兼容性相互妥协兼顾的结果。

https://www.zhihu.com/question/270355472

spring cloud与dubbo性能对比
http://www.cnblogs.com/chen110xi/p/6349580.html

Eureka配置

eureka.client.register-with-eureka: 表示是否将自己注册到Eureka Server, 默认为true。 如果当前应用就是Eureka Server,则设为 false。
eureka.client.fetch-registry: 表示是否从Eureka Server获取注册信息,默认为true。如果这是一个单点的 Eureka Server,不需要同步其他节点的数据,可以设为false。
eureka.client.serviceUrl.defaultZone:在client端可以指定多个eureka服务,用逗号分隔。
https://www.jianshu.com/p/67fa6bbdbadf

在eureka中注册的服务能互通的前提是各服务间的网络本来就是通的。
主机服务程序在eureka中默认使用哈希值代替ip来作为识别码,可以配置eureka.instance.preferIpAddress=true来指定使用IP来作为识别码。

是纯正的 servlet 应用,需部署到web容器中。

Hystrix

使用feign时断路器不起作用,检查在引入了openfeign依赖后,不要再引入ribbon、hystrix。

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>

Mysql

Mysql存储引擎

MyISAM

MyISAM:官方提供的存储引擎,基于传统的ISAM类型,ISAM是Indexed Sequential Access Method (有索引的顺序访问方法) 的缩写,它是存储记录和文件的标准方法。不是事务安全的,不支持外键。

  • 查询效率高,执行大量的查询MyISAM比较适合。
  • 不支持事务,回滚将造成不完全回滚,不具有原子性。
  • 不支持外键
  • 只支持表级锁,不支持行锁定,这样同一个表上的读锁和写锁是互斥的,MyISAM并发读写时如果等待队列中既有读请求又有写请求,默认写请求的优先级高,即使读请求先到,所以MyISAM不适合于有大量查询和修改并存的情况,那样查询进程会长时间阻塞。因为MyISAM是锁表,所以某项读操作比较耗时会使其他写进程饿死。在操作myisam表时,select,update,delete,insert语句都会给表自动加锁,如果加锁以后的表满足insert并发的情况下,可以在表的尾部插入新的数据。表锁开销小,加锁快,不会出现死锁,粒度大,锁冲突概率高,并发效率低。
  • 支持全文搜索,全文索引是指对char、varchar和text中的每个词(停用词除外)建立倒排序索引。MyISAM的全文索引其实没啥用,因为它不支持中文分词,必须由使用者分词后加入空格再写到数据表里,而且少于4个汉字的词会和停用词一样被忽略掉。

DELETE 表时,先drop表,然后重建表
MyISAM 表被存放在三个文件:frm 文件存放表格定义,数据文件是MYD (MYData) ,索引文件是MYI (MYIndex)引伸。
跨平台很难直接拷贝
MyISAM中可以使AUTO_INCREMENT类型字段建立联合索引
表格可以被压缩。
MyISAM支持GIS数据,InnoDB不支持。GIS数据是指空间数据对象:Point,Line,Polygon,Surface等。
MyISAM保存表的具体行数,在查询不带where时,直接返回保存的行数。所以没有where的count(*)使用MyISAM要比InnoDB快得多。因为MyISAM内置了一个计数器,count(*)时它直接从计数器中读;而InnoDB必须扫描全表。所以在InnoDB上执行count(*)时一般要伴随where,且where中要包含主键以外的索引列。这里特别强调“主键以外”,是因为InnoDB中primary index是和raw data存放在一起的,而secondary index则是单独存放,然后有个指针指向primary key。所以只是count(*)的话使用secondary index扫描更快,而primary key则主要在扫描索引同时要返回raw data时的作用较大。

InnoDB

InnoDB,支持外键、行锁、事务是他的最大特点。如果有大量的update和insert,建议使用InnoDB,特别是针对多个并发和QPS较高的情况。5.5版本后成为默认存储引擎。

  • 支持ACID事务,InnoDB的AUTOCOMMIT默认是打开的,即每条SQL语句会默认被封装成一个事务自动提交,这样会影响速度,所以最好是把多条SQL语句显示放在begin和commit之间,组成一个事务去提交。
  • 支持外键
  • 支持行级锁

update、insert、delete自动加隐式排它锁,或者select for update显示排它锁。不加锁读取

在Mysql5.6版本开始支持FullText类型的索引,5.7.6版本支持了中文索引。
DELETE 表时,是一行一行的删除
InnoDB 把数据和索引存放在表空间里面
跨平台可直接拷贝使用
InnoDB中必须包含AUTO_INCREMENT类型字段的索引
表格很难被压缩
InnoDB的主键范围更大,最大是MyISAM的2倍
innodb属于索引组织表,有两种存储方式,共享表空间存储和多表空间存储,两种存储方式的表结构和myisam一样,以表名开头,扩展名是.frm。如果使用共享表空间,那么所有表的数据文件和索引文件都保存在一个表空间里,一个表空间可以有多个文件,通过innodb_data_file_path和innodb_data_home_dir参数设置共享表空间的位置和名字,一般共享表空间的名字叫ibdata1-n。如果使用多表空间,那么每个表都有一个表空间文件用于存储每个表的数据和索引,文件名以表名开头,以.ibd为扩展名。

TokuDB

第三方开发的存储引擎,写速度快,

支持数据压缩存储,适合访问频率低的数据,历史数据归档。不适合大量读取

支持在线添加索引不影响读写操作,

3.对比选择:
MyISAM相对简单,在效率上要优于InnoDB。从效率上来看,如果系统读多写少,对原子性要求低,那么MyISAM最好的选择,且MyISAM恢复速度快,可直接用备份覆盖恢复。如果系统读少写多,尤其是高并发写入,InnoDB就是首选了。

MyISAM与InnoDB两者之间区别与选择,详细总结,性能对比
https://www.cnblogs.com/y-rong/p/8110596.html

数据库锁级别

  • 表级锁:开销小,加锁快,不会出现死锁,粒度大,锁冲突概率高,并发效率低。
  • 行级锁:开锁大,加锁慢,可能出现死锁,粒度小,锁冲突概率低,并发效率高。
  • 共享锁:读锁。其它事务可读不可写。
  • 排它锁:写锁。其它事务不可读不可写。

存储过程与函数

在Mysql服务器中运行,减少网络数据传输。

  • 存储过程实现复杂数据库操作,是独立的sql语句调用。与数据库实现绑定,降低了程序的可移植性。
  • 函数实现针对性强的功能,例如按特殊策略求和。用户定义函数不能修改数据库全局状态。

Mysql8.0新特性

  • 默认字符集修改为了utf-8
  • 增加了隐式索引,隐藏后的索引不会被查询优化器使用,这个特性可用了性能调试。
  • 通用表表达式,复杂查询中的嵌入语句表达更清晰。
  • 窗口函数,与集合函数类似,可实现新的查询方式。不会将多行查询结果合并,不需要group by

Mysql索引

需要额外磁盘空间来保存索引,插入更新删除会增加额外的开销,索引适合读多写少的场景。

索引类型:

  • 唯一索引:值可为NULL。
  • 主键索引:不允许出现空值。
  • 普通索引
  • 联合索引:最左原则即查询条件中的字段必须符合在索引字段中从左开始连续
  • 全文索引:只能在char、varchar、text类型字段上使用。

索引实现:

  • B-Tree:mysql中普遍使用B+Tree索引,但在实现方式上又分为聚簇索引和非聚簇索引。
  • R-Tree
  • Hash
  • FullText:倒排索引,关键字与文档关系。

聚簇索引和非聚簇索引

  • 聚簇索引:指主索引文件和数据文件为同一份文件,聚簇索引主要用在Innodb存储引擎中。在该索引实现方式中B+Tree的叶子节点上的data就是数据本身,key为主键。
  • 非聚簇索引:指B+Tree的叶子节点上的data并不是数据本身,而是数据存放的地址。主索引和辅助索引没啥区别,只是主索引中的key一定得是唯一的。主要用在MyISAM存储引擎中。非聚簇索引比聚簇索引多了一次读取数据的IO操作,所以查找性能上会差。

utf8mb4

MySQL在5.5.3之后增加了utf8mb4的编码,mb4就是most bytes 4的意思,专门用来兼容四字节的unicode。
utf8mb4是utf8的超集,为了节省空间,一般情况下使用utf8就够了。

int(11)

int(n)中,n表示查询显示时的最小宽度,即最小的字符数。若不够最小长度,则前面补0。

Mysql调优

优化的维度

  • 表结构与索引
  • SQL语句
  • Mysql参数
  • 硬件和系统配置

数据库的水平和垂直扩展能力,提前规则未来读写和数据量的增长,分库分表方案。按UID维度散列,分为4个库,每个库32张表,保证单表数据量控制在千万级别。

字段选择合适的最小空间的数据类型,如年龄使用tinyint

多字段表拆分为多个表,必要时使用中间表关联。

范式与反范式、反范式即保持一定的冗余。

分析慢查询日志,寻找需要优化的语句

利用分析工具,如explain、profile。

查询语句避免使用select *,要指定需要的列。可以避免查询列字段的元信息。

1.使用内置缓存
大多数的MySQL服务器都开启了查询缓存。这是提高性最有效的方法之一,而且这是被MySQL的数据库引擎处理的。当有很多相同的查询被执行了多次,这些查询结果会被缓存。
对于像 NOW() 、RAND()、CURDATE()等SQL函数都不会开启查询缓存,因为这些函数的返回是会不定的易变的。所以需要用一个变量来代替MySQL的函数,从而开启缓存。

2.使用 EXPLAIN 执行SELECT查询
使用 EXPLAIN 关键字可以打印出MySQL是如何处理SQL语句的,可以帮助分析查询语句或者表结构的性能瓶颈。
EXPLAIN 的查询结果还会告诉索引主键是被如何利用的、数据表是如何被搜索和排序的等等。
在SELECT语句(推荐挑选那个最复杂的,有多表联接的),把关键字EXPLAIN加到前面,可以使用phpmyadmin来执行。然后会看到一张表格。

3. 追加 LIMIT 1
查询表有时已经知道结果只会有一条结果,此时加上 LIMIT 1 可以增加性能。MySQL数据库引擎会在找到一条数据后停止搜索,而不是继续往后查少下一条符合记录的数据。
但是在用explain查询分析,显示limit 1加与不加,性能相同。是因为可能是使用了缓存吗?

4. 搜索字段建索引
索引并不一定是给主键或是唯一的字段,如果表中有某个字段经常用来做搜索,那么请为其建立索引。
有些搜索是不能使用正常的索引的。例如需要在一篇大的文章中搜索一个词时,如: “WHERE post_content LIKE ‘%apple%’”,索引是没有意义的。这可能需要使用MySQL全文索引或是自己做一个索引(比如搜索关键词、标签)。
查询语句中使用use index可以指定索引。

5.使用 ENUM 代替 VARCHAR
ENUM 类型是非常快和紧凑的,实际上其保存的是 TINYINT,但其外表上显示为字符串。用这个字段类型来做选项列表变得相当的完美。比如“性别”,“国家”,“民族”,“状态”或“部门”字段,这些字段的取值是有限而且固定的,那么应该使用 ENUM 而不是 VARCHAR。

6.PROCEDURE ANALYSE() 结构建设
PROCEDURE ANALYSE() 会让 MySQL 帮助分析字段和其实际的数据,给出一些有用的建议。只有表中有实际的数据这些建议才会变得有用,因为要做一些大的决定是需要有数据作为基础的。
例如,如果你创建了一个 INT 字段作为你的主键,然而并没有太多的数据,那么,PROCEDURE ANALYSE()会建议你把这个字段的类型改成 MEDIUMINT 。或是你使用了一个 VARCHAR 字段,因为数据不多,你可能会得到一个让你把它改成 ENUM 的建议。但这些建议可能因为数据不够多而决策做得就不够准确。
在phpmyadmin里,你可以在查看表结构时,点击 “Propose table structure” 或“规则表结构”来查看这些建议,建议结果呈现在Optimal_fieldtype字段中。

7.字段尽量设置默认值
除非有特殊原因使用 NULL 值,否则应该总是让字段保持 NOT NULL。NULL需要额外的空间,并且在进行比较的时候,程序会更复杂,难以查询优化。
下面摘自MySQL自己的文档:
“NULL columns require additional space in the row to record whether their values are NULL. For MyISAM tables, each NULL column takes one bit extra, rounded up to the nearest byte.”

MySQL 性能优化…经验分享
https://www.cnblogs.com/pengyunjing/p/6591660.html

mysql中不要用blob等大字段

在开发规范中,我们一般都是要求字段不要设置成blob这种大字段。原因是查询的时候效率问题。另外一个就是在插入量大的时候,生成的binlog太多,容易导致一些问题。线上就遇到了,1k多的插入,binlog狂写,磁盘干满了。

1.多表先约束再连接
由全表连接,变为先约束为小表再连接。

2.索引
随着集合的增长,需要针对查询条件中数据量大的排序字段做索引。
如果没有对索引的键排序,数据库需要将所有数据提取到内存并排序。因此在做无索引排序时,如果数据量过大以致无法在内存中进行排序,数据库将会报错。初步可以对出现查询慢的表建立索引、组合索引。
在创建多列索引时,要根据业务需求,where子句中使用最频繁的一列放在索引组合的最左边。
mysql 组合索引“最左前缀”规则,简单的理解就是只从最左面的开始组合。查询条件中没有使用组合索引最左列列的语句,不会使用到索引。
MySQL只对<,<=,=,>,>=,BETWEEN,IN,以及某些时候的LIKE才会使用索引。在以通配符%和_开头作查询时,MySQL不会使用索引。
虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件。
只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL。
对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的列,如果在前10个或20个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。
MySQL查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。
explain sql1 可以分析sql语句的执行情况,进而对sql语句进行优化。
组合索引-最左优先原则(最左原则)

MySQL有一个复合索引:INDEX(`a`, `b`, `c`),以下查询能用上索引。
A、select * from users where a = 1 and b = 2
B、select * from users where b = 2 and a = 1
C、select * from users where a = 2 and c = 1
第二项会由Mysql查询器优化。

https://blog.csdn.net/u014590757/article/details/79590561

3.数据库拆分:分库、分表、分区

单表的数据量限制,当单表数据量到一定条数之后数据库性能会显著下降。分库减少单台数据库的压力。有些数据表适合通过主键进行散列分库分表。

数据库的垂直切分和水平切分
数据切分可以是物理上的,对数据通过一系列的切分规则将数据分布到不同的DB服务器上,通过路由规则访问特定的数据库,降低单台机器的负载压力。

数据切分也可以是数据库内的,对数据通过一系列的切分规则,将数据分布到一个数据库的不同表中,比如将article表分为article_001,article_002等子表,若干个子表水平拼合有组成了逻辑上一个完整的article表。比如article表中有5000w条数据,在这个表中增加(insert)一条新的数据,insert后数据库会针对这张表重新建立索引,5000w行数据建立索引的系统开销还是不容忽视的。如果将这个表分成100 个子表,每个子表里边就只有50万行数据,向一张只有50w行数据的table中insert数据后建立索引的时间就会呈数量级的下降,提高了DB的并发量。分表的好处还有诸如写操作的锁操作等。

分库降低了单点机器的负载;分表提高了数据操作的效率,尤其是Write操作的效率。

垂直水平切分

分库分表后id主键处理的方法:
A、单库生成自增 id
B、设置数据库 sequence 或者表自增字段步长
C、UUID
D、最佳方法是snowflake 算法

snowflake 算法是 twitter 开源的分布式id生成算法,采用 Scala 语言实现,是把一个 64 位的 long 型的 id,1 个 bit 是不用的,用其中的 41 bit 作为毫秒数,用 10 bit 作为工作机器 id,12 bit 作为序列号。
1 bit 不用,是因为二进制里第一个 bit 为如果是 1,那么都是负数,但是我们生成的 id 都是正数,所以第一个 bit 统一都是 0。 41 bit:表示的是时间戳,单位是毫秒。41 bit 可以表示的数字多达 2^41 – 1,也就是可以标识 2^41 – 1 个毫秒值,换算成年就是表示69年的时间。 10 bit:记录工作机器 id,代表的是这个服务最多可以部署在 2^10台机器上哪,也就是1024台机器。但是 10 bit 里 5 个 bit 代表机房 id,5 个 bit 代表机器 id。意思就是最多代表 2^5个机房(32个机房),每个机房里可以代表 2^5 个机器(32台机器)。 12 bit:这个是用来记录同一个毫秒内产生的不同 id,12 bit 可以代表的最大正整数是 2^12 – 1 = 4096,也就是说可以用这个 12 bit 代表的数字来区分同一个毫秒内的 4096 个不同的 id。

4.读写分离
读写分离,基本的原理是让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE),从数据库处理SELECT查询操作。数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库。

例如用户信息,每个用户都有系统内部的一个userid,与userid对应的还有用户名。那么如果分库分表的时候单纯通过userid进行散列分库,那么根据登录名来获取用户的信息,就无法知道该用户处于哪个数据库中。或许可以维护一个username—-userid的映射关系,先查询到userid再根据userid的分库分表规则到对应库的对应表来获取用户的记录信息。但这个映射关系的条数本身也是个瓶颈,原则上是没有减少单表内数据的条数,算是一个单点。并且也要维护这个映射关系和用户信息的一致性。最大一个原因,其实用户信息实际是一个读大于写的库,所以对用户信息拆分还是有一定局限性的。

对于这类读大于写并且数据量增加不明显的数据库,推荐采用读写分离+缓存的模式,用户注册、修改信息、记录登录时间、登录IP、修改密码,这些是写操作,但是这些操作次数都是很小的,所以整个数据库的写压力是很小的。读写分离首要解决的就是将经常变化的数据的拆分,比如:用户登录时间、记录用户登录IP,这类信息可以单独独立出来,记录在持久化类的缓存中(可靠性要求并不高,登陆时间、IP丢了就丢了,下次来了就又来了)。

主库负责写数据、读数据。读库仅负责读数据。每次有写库操作,同步更新cache,每次读取先读cache再读DB。写库就一个,读库可以有多个,例如Oracle采用dataguard来负责主库和多个读库的数据同步。

参考
https://www.cnblogs.com/panxuejun/p/5887118.html
https://www.jianshu.com/p/65e8a31fbab8
https://www.cnblogs.com/alvin_xp/p/4162249.html

MySQL数据库则可以利用MySQL主从配置,实现读写分离,既起到备份作用又可以减轻数据库的读写的压力。读写分离的基本原理是让“主”数据库处理事务性增、改、删操作,“从”数据库处理查询操作。利用数据库复制把事务性操作导致的变更从主数据库同步到从数据库。写库有一个,读库可以有多个,采用日志同步的方式实现主库和多个读库的数据同步。

Mysql 的 Replication 是一个异步的复制过程,从一个MySQL节点(称为Master)复制到另一个MySQL节点(称Slave)。在 Master 与 Slave 之间的实现整个复制过程主要由三个线程来完成,其中两个线程(SQL 线程和 I/O 线程)在 Slave 端,另外一个线程(I/O 线程)在 Master 端。
要实现 MySQL 的 Replication ,首先要打开 Master 端的 Binary Log,整个复制过程实际上就是 Slave 从 Master 端获取日志,然后在自己身上完全顺序的执行日志中所记录的各种操作。
MySQL的Replication原理有以下结论和推论:
* 每个从仅可以设置一个主。
* 主在执行sql之后,记录二进制log文件(bin-log)。
* 从连接主,并从主获取bin-log,存于本地relay-log,并从上次记住的位置起执行sql,一旦遇到错误则停止同步。
* 主从间的数据库不是实时同步。
* 如果主从的网络断开,从会在网络正常后,批量同步。
* 如果对从进行修改数据,那么很可能从在执行主的bin-log时出现错误而停止同步,这个是很危险的操作。所以一般情况下,非常小心的修改从上的数据。
* 一个衍生的配置是双主,互为主从配置,只要双方的修改不冲突,可以工作良好。
* 如果需要多主的话,可以用环形配置,这样任意一个节点的修改都可以同步到所有节点。

4.数据缓存
大型网站为了应对大量的并发访问,除了在业务端实现分布式负载均衡,还要减少数据库的连接,例如采用优秀的代码框架进行代码优化,采用优秀的数据缓存技术如memcached,如果资金丰厚还可以架设服务器群来分担主数据库的压力。

建表原则

1、定长与变长分离
如id int占4个字节,char(4)占4个字节,即每一个单元值占的字节都是固定的。而varchar,text,blob 变长字段适合单放另一张表,在其中使用主键与核心表关联。
2、常用字段和不常用字段向分离
结合具体的业务分析字段的查询场景,把查询频度低的字段单拆出来。
3、把1对多等需要关联统计的数值添加冗余字段。
例如论坛中每个栏目显示今日发帖数目存储下来,不需要每次查询都再统计。

sql语句优化

计算机存储空间分为:寄存器、高速缓存、内存、交换区(外部存储虚拟化)、硬盘以及其他的外部存储。从寄存器开始到硬盘读写速度是从快到慢依次递减。对于批量记录如果一条一条的连接数据库进行操作,耗费的时间非常恐怖。调优的环节之一,则是减少与数据库交互的次数,将多条查询、插入、更新合并为交互一次,也就是批操作。多次处理的操作交给主程序在内存中进行处理,内存中处理的速度要快上很多。

批量插入语句
将插入语句进行拼接,多条插入语句拼接成一条插入语句,与数据库交互一次执行一次。

//如果字符串太长,则需要配置下MYSQL,在mysql 命令行中运行 :
set global max_allowed_packet=2*1024*1024*10
//批量插入语句
insert into 表名(字段名1,字段名2)values(值a1,值b1), (值a2,值b2)

批量更新语句

UPDATE categories SET 
display_order = CASE id 
        WHEN 1 THEN 3 
        WHEN 2 THEN 4 
        WHEN 3 THEN 5 
END, 
title = CASE id 
        WHEN 1 THEN 'New Title 1'
        WHEN 2 THEN 'New Title 2'
        WHEN 3 THEN 'New Title 3'
END
WHERE id IN (1,2,3);

批量查询和删除

select * from tableName where id in (1,2,3,4) order by id
delete from tableName where id in(1,2,3,4,5,6)

sql语句取3000条记录

#Oracle :
select * from table where rownum between 1 and 3000
select * from table rownum<3001
#MySql:
select * from table limit 1 to 3000

插入记录隐藏列名时注意表结构中字段顺序

例如以下插入,是按字段顺序对应,不是按字段名对应。
insert into b_subuser_deleted_table SELECT * from b_subuser_table WHERE id=1