├── README.md ├── golang └── basic │ ├── go-100-questions.md │ ├── go-basic.md │ └── go-question.md ├── java ├── basic │ ├── concurrent.md │ ├── draw.drawio │ ├── hashmap.md │ ├── img │ │ ├── Java访问权限控制.png │ │ ├── executor-service.png │ │ ├── java-thread-pool-class.jpg │ │ ├── java-thread-pool-method.jpg │ │ ├── java-thread-states.jpg │ │ ├── multiple-thread-cas.webp │ │ ├── synchronized-block.jpg │ │ ├── synchronized-method.jpg │ │ └── thread-states.png │ ├── java-basic.md │ ├── java-collection.md │ ├── java-io-nio.md │ ├── java-thread-executor-framework.png │ ├── java-thread-future-api.png │ ├── java-thread-juc.md │ ├── java-thread-pool-process.png │ └── java-thread.md ├── javaweb │ ├── filter.png │ ├── jsp.md │ └── servlet.md ├── jvm │ ├── JVM虚拟机监控及性能调优.md │ ├── png │ │ ├── install-visual-gc-plugin.png │ │ ├── jmx-monitor.png │ │ ├── update-visual-gc-settings.png │ │ ├── visual-gc-plugins.png │ │ └── visual-gc-view.png │ └── 深入理解Java虚拟机.md └── spring │ ├── image │ ├── documented-annotation.png │ └── hystrix.png │ ├── spring-annotation.md │ ├── spring-boot │ ├── 0-springboot-history.md │ ├── 1-springboot-basic.md │ ├── 2-spring-security.md │ ├── springboot-admin.md │ ├── springboot-note.md │ ├── springboot-scheduled-task.md │ ├── springboot-ssl.md │ ├── springboot-starter.md │ └── thymeleaf.md │ ├── spring-cloud │ ├── spring-cloud-eureka.md │ ├── spring-cloud-gateway.md │ ├── spring-cloud-hystrix.md │ ├── spring-cloud-request-process.md │ └── spring-cloud.md │ └── spring.md ├── plugins ├── activemq.md ├── database │ ├── SQL优化.md │ ├── database.md │ ├── img │ │ ├── b+tree-example.png │ │ ├── b+tree.PNG │ │ ├── binary-tree-no-balance.PNG │ │ ├── binary-tree.PNG │ │ ├── btree-example.png │ │ ├── hash-integer.PNG │ │ ├── hash-string.PNG │ │ ├── mysql-btree.png │ │ ├── mysql-select-process.jpg │ │ ├── mysql-sync.PNG │ │ ├── mysql_profile_demo.png │ │ └── read-black-tree.png │ └── mysql │ │ ├── MySQL中的乐观锁与悲观锁.md │ │ ├── mysql索引.md │ │ └── 数据库主键怎么选择.md ├── docker.md ├── elasticsearch.md ├── jmeter.md ├── keepalived.md ├── log.md ├── maven.md ├── mongodb.md ├── mq │ ├── img │ │ └── mq-compare.png │ └── mq.md ├── mqtt.md ├── mybatis-plus.md ├── mybatis.md ├── mysql.md ├── netty.md ├── nginx.md ├── png │ ├── Tomcat_Architecture.png │ ├── amqp-topic.png │ ├── jmeter-elements.png │ ├── mqtt-fidge-2.svg │ ├── mybatis-architecture.jpg │ ├── mybatis-level1-cache.png │ ├── mybatis-level2-cache.png │ ├── netty-architecture.png │ ├── redis-aof-append-block.png │ ├── redis-cluster-nodes.png │ ├── redis-cluster.png │ ├── redis-cmd-lifecycle.png │ ├── redis-data-type-structure.PNG │ ├── redis-full-reclipate.png │ ├── redis-part-replication.png │ └── zookeeper-distributed-lock.png ├── postgresql.md ├── rabbitmq.md ├── redis.md ├── redis │ ├── redis-cas.md │ ├── redis-rdb-aof分析.md │ ├── redis命令执行分析.md │ ├── redis基础数据类型及使用场景.md │ ├── redis常用客户端使用总结.md │ ├── redis整体架构分析.md │ ├── redis服务器启动.md │ ├── redis网络模型分析.md │ ├── redis过期策略.md │ └── 如何保证缓存和数据库的双写一致性.md ├── rocketmq.md ├── tomcat.md └── 一张图了解Tomcat架构.md ├── system ├── algorithm │ ├── algorithm.md │ ├── img │ │ ├── es-btree.png │ │ ├── es-index.png │ │ ├── es-storage-index.png │ │ └── 八大排序算法.png │ ├── letcode │ │ └── note.md │ ├── 倒排索引.md │ ├── 数据结构.md │ └── 设计模式.md ├── architecture │ ├── CAP.md │ ├── distribute_transactional.md │ ├── img │ │ ├── api.png │ │ ├── cap.jpg │ │ ├── consistency-conflict.png │ │ ├── consistency-done.png │ │ ├── consistency-send.png │ │ ├── consistency-sync.png │ │ ├── consistency.png │ │ ├── distribute_lock.jpg │ │ ├── java-log-architecture.png │ │ └── partitiontolerance.png │ ├── io-multiplexing.md │ ├── log-note.md │ ├── spring-cloud-优雅上下线.md │ ├── system.md │ ├── tools.md │ ├── 分布式ID生成方案.md │ ├── 分布式系统随笔.md │ ├── 分布式锁.md │ ├── 削峰填谷.md │ ├── 如何设计一个对外安全的接口.md │ ├── 异地多活总结.md │ ├── 推荐系统.md │ ├── 服务端如何防止重复提交.md │ ├── 架构设计随思录.md │ ├── 系统架构安全设计.md │ ├── 系统架构性能设计.md │ ├── 系统架构设计其他注意事项.md │ ├── 系统架构高可用设计.md │ ├── 系统设计注意事项.md │ ├── 限流.md │ └── 集群环境下日志合并方案.md └── network │ ├── image │ ├── TCP-IP.gif │ ├── https.jpg │ └── https_request_process.png │ ├── network.md │ ├── notes │ ├── HTTP_HTTPS_SSL.md │ └── second-level-domain.md │ └── 彻底了解cookies.md └── tool ├── 2023-03-24.png ├── api-testing-tool.md ├── coding-life.md ├── cronolog.md ├── deployment.md ├── english.md ├── git.md ├── hutool.md ├── intellij.md ├── interview.md ├── maven.md ├── png ├── CNZZ网站流量统计分析.PNG ├── git-file-status.png ├── git-file-storage.png ├── idea-encode-utf8.png ├── idea-font-size.png └── idea-tab-whitespace.PNG ├── postman.md ├── shell ├── auto-commit.sh └── linux.md ├── todo.md ├── tools.md └── vscode-settings.md /README.md: -------------------------------------------------------------------------------- 1 | **`声明`** 2 | 本项目为个人学习之总结,内容大多来源网上、书籍、视频,若引用不当,麻烦告知,我定删除。喜欢的话可以`Star`下,生活不易,希望对读者有帮助。祝好!!! 3 | 4 | ### 目录 5 | 6 | | 英语 | Java生态 | Golang生态 | 中间件 | 持久化 | 服务器 | 网络/系统 | 内功 | 程序人生 | 7 | |:----|:-----|:------|:------|:------|:------|:------|:------|:------| 8 | |英语|Java Basic
JVM
Web
Spring
Spring Boot
Spring Cloud|Go Basic
Go Web|Keepalived
ActiveMQ
RabbitMQ
RocketMQ
MQTT
Netty
Mybatis
Redis
Log|MySQL
Postgresql
Mongodb|Tomcat
Nginx|网络
Linux|数据结构
算法
设计模式|软文
规范
工具
面试集锦
实战训练| 9 | 10 | ### 英语 11 | * [计算机行业常用英语积累](tool/english.md) 12 | 13 | ### Java 14 | * `JavaCore`:  [Java基础](java/basic/java-basic.md) 15 |   [JDBC基础](https://github.com/zhonghuasheng/JAVA/blob/master/jdbc/src/main/java/com/zhonghuasheng/jdbc/learn01/BasicSteps.java)  [Java集合](java/basic/java-collection.md)  [Java多线程系列](java/basic/java-thread.md)  [JUC系列](java/basic/java-thread-juc.md)  [Java IO基础](java/basic/java-io-nio.md) 16 | * `Java -VM`:  [Java虚拟机系列](java/jvm/深入理解Java虚拟机.md) [JVM虚拟机监控及性能调优系列](java/jvm/JVM虚拟机监控及性能调优.md) 17 | * `Java-Web`:  [Servlet基础](java/javaweb/servlet.md) [JSP基础](java/javaweb/jsp.md) 18 | * `Spring X`:  [Spring4系列](java/spring/spring.md#Spring) [SpringMVC系列](java/spring/spring.md#SpringMVC) [SpringBoot系列](java/spring/spring.md#SpringBoot) [SpringCloud系列](java/spring/spring-cloud/spring-cloud.md) 19 | 20 | ### Golang 21 | * `Golang Basic`:  [Go基础](golang/basic/go-basic.md) 22 | * `Golang Web`:  [Go Web](golang/basic/go-basic.md#goweb) 23 | 24 | ### 中间件 25 | * `负载均衡`:  [Keepalived系列](plugins/keepalived.md) 26 | * `消息通信`:  [消息通信基础](http://note.youdao.com/noteshare?id=30a11e46aaef3f00d2ecfb84692ca294&sub=wcp157828038663078) [MQ概述](plugins/mq/mq.md) [ActiveMQ系列](plugins/activemq.md) [RabbitMQ系列](plugins/rabbitmq.md)  [RocketMQ系列](plugins/rocketmq.md)  [Netty系列](plugins/netty.md)  [IOT通信](plugins/mqtt.md) 27 | * `数据访问`:  [MyBatis](plugins/mybatis.md)  [MyBatis-Plus](plugins/mybatis-plus.md) 28 | * `数据缓存`:  [Redis系列](plugins/redis.md) 29 | * `搜索引擎`:  [Elasticsearch](plugins/elasticsearch.md) 30 | * `日志模块`:  [Log4j2](plugins/log.md) 31 | 32 | ### 数据库 33 | * `关系型数据库`:  [数据库理论基础](plugins/database/database.md) [MySQL](plugins/mysql.md) [Postgresql](plugins/postgresql.md) 34 | * `非关系型数据库`:  [Mongodb学习笔记](plugins/mongodb.md) 35 | 36 | ### 服务器 37 | * [Tomcat服务器](plugins/tomcat.md) [Nginx反向代理服务器搭建](plugins/nginx.md) [Linux系统常用命令](tool/shell/linux.md) 38 | 39 | ### 架构设计 40 | * [分布式锁](system/architecture/分布式锁.md) 41 | * [分布式ID生成方案](system/architecture/分布式ID生成方案.md) 42 | * [如何设计一个对外安全的接口](system/architecture/如何设计一个对外安全的接口.md) 43 | * [CAP理论](system/architecture/CAP.md) 44 | * [日志](system/architecture/log-note.md) 45 | 46 | ### 内功 47 | * `设计模式`: [23种设计模式](system/algorithm/设计模式.md) 48 | * `数据结构`: [数据结构系列](system/algorithm/数据结构.md) 49 | * `算法`: [算法系列](system/algorithm/algorithm.md) 50 | * `操作系统`: [操作系统](tool/shell/linux.md) 51 | 52 | ### 网络 53 | * `常见网络问题`: [常见网络问题系列](system/network/network.md) 54 | 55 | ### 程序人生 56 | > `软文` 57 | * [工作经历 - 记录自己的成长](tool/coding-life.md#记录自己的成长) 58 | * [最好的建议](tool/coding-life.md/#最好的建议) 59 | * [正视自己的价值](tool/coding-life.md/#正视自己的价值) 60 | * [新工程师要干的五件事情](tool/coding-life.md/#新工程师要干的五件事情) 61 | * [为什么CTO,技术总监,架构师不写代码都这么牛逼](http://note.youdao.com/noteshare?id=f4eeda7da9b73adf4294f984a5e7cbe5&sub=945D4467238947AAB5C030B17D5AC01E) 62 | * [技术/管理](https://www.cnblogs.com/yexiaochai/p/14805941.html#top) 63 | * [简单/不简单](https://www.cnblogs.com/xxcanghai/p/ping-shi-de-gong-zuo-ru-he-ti-xian-yi-ge-ren-de-ji.html) 64 | 65 | > `规范` 66 | * [雅虎前端34条军规](http://note.youdao.com/noteshare?id=b59d0da4f7bb2b7ba5f73129d85b1ba1) 67 | * [Google Java Coding Style](https://google.github.io/styleguide/javaguide.html) 68 | * [阿里巴巴代码规范](https://github.com/alibaba/p3c/blob/master/%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4Java%E5%BC%80%E5%8F%91%E6%89%8B%E5%86%8C%EF%BC%88%E8%AF%A6%E5%B0%BD%E7%89%88%EF%BC%89.pdf) 69 | * [给函数取一个好的名字](http://note.youdao.com/noteshare?id=74f3c5fae9fc26473e7046a700cdad12&sub=wcp1581864078132689) 70 | * [Java命名规范参考](http://note.youdao.com/noteshare?id=c0ca7331624eb2f19b06f623a1b832ae&sub=2F7223EB9D9E4072B60A1FB578BF0AFA) 71 | 72 | > `工具` 73 | * [尖刀]() 74 | * [Hutool](tool/hutool.md) 75 | * [Java诊断工具] 76 | * [阿里JAVA诊断工具Arthas](tool/tools.md) 77 | * [API测试工具](tool/api-testing-tool.md) 78 | * [流量统计,网站分析](tool/common-tools.md) 79 | * [日志管理工具](tool/cronolog.md) 80 | * [Git](tool/git.md) 81 | * [Intellij](tool/intellij.md) 82 | * [Maven](tool/maven.md) 83 | * [VSCode](tool/vscode-settings.md) 84 | * [CloudFlare免费的CDS服务]() 85 | * [LDAP搭建和使用]() 86 | * [常见部署方式](tool/deployment.md) 87 | 88 | > `面试集锦` 89 | * [疯狂面试题](tool/interview.md) 90 | 91 | > `实战训练` 92 | * [秒杀商城](https://github.com/zhonghuasheng/JAVA/tree/master/seckill) 93 | 94 |
95 |

技术栈

96 |
97 | 98 | ![](tool/tutorial-2020-10-31.png) 99 | 100 |
101 | -------------------------------------------------------------------------------- /golang/basic/go-100-questions.md: -------------------------------------------------------------------------------- 1 | # Go白问 2 | 1. 使用go关键字开启一个协程都发生了什么?它与java中的并发有什么不一样的地方? 3 | ```go 4 | go count(5) // 使用go关键字创建一个goroutine 5 | ``` -------------------------------------------------------------------------------- /golang/basic/go-basic.md: -------------------------------------------------------------------------------- 1 | ### 学习计划 2 | * B站8小时转go开发 3 | * go-kit实战小例子 4 | 5 | #### go basic 6 | 7 | #### go web 8 | * 示例地址 https://github.com/zhonghuasheng/JAVA_LOVE_GO/tree/master/gop/com/zhonghuasheng/web 9 | 10 | ### 目录 11 | * RPC 12 | * Protobuf 13 | * go thinking 14 | * basic 15 | * 空白标识符 16 | * 注意 17 | 18 | ### RPC 19 | 整体过程就是: 20 | 1. 客户端发送数据(以字节流的方式) 21 | 2. 服务端接收并解析。根据约定知道执行什么,然后把结果返回客户端 22 | RPC就是把 23 | 1. 上述流程封装下,使其操作更加优化,让使用者感觉像是调用本地方法一样 24 | 2. 使用一些大家都认可的协议 使其规范化 25 | 3. 做成一些框架,直接或间接产生利益 26 | 27 | ### Protobuf 28 | Google Protocol Buffer 29 | 轻便高效的序列化数据结构协议 30 | 31 | ### go thinking 32 | 众多语言学术流派,面向过程、面向对象、函数式编程、面向消息编程等。Go语言接受函数式编程、支持匿名函数与闭包,接受以Erlang语言为代表的面向消息编程思想,支持goroutine和通道,并推荐使用消息而不是共享内存来进行并发编程。Go语言最主要的特性 33 | * 自动垃圾回收 34 | * runtime系统调度机制 35 | * 更丰富的内置类型 36 | * 函数多返回值 37 | * 错误处理 38 | * 匿名函数和闭包 39 | * 类型和接口 40 | * 并发编程 41 | * 反射 42 | * 语言交互性 43 | 44 | ### basic 45 | * Go程序由多个标记组成,可以是关键字、标识符、常量、字符串、符号。 46 | * 行分隔符: 每一行代表一个语句结束。建议每一行加上分号;标识结尾,不加的话Go编译器自动完成 47 | * 注释:注释不会被编译 48 | * 标识符:标识符用来命名变量、类型等程序实体 49 | * 字符串连接:Go语言的字符串可以通过+实现 50 | * 关键字:Go语言包含25个关键字。break default func interface select case defer go map struct chan else goto package switch const flatthrough if range type continue for import return var 51 | * Go语言还有36个预定义标识符 52 | * 空白标识符_是一个只写变量,你不能得到它的值,被用于抛弃值。这样做是因为Go语言中你必须使用所有被声明的变量,但有时你并不需要使用从一个函数得到的所有返回值。 53 | * 环境搭建 54 | * windows环境搭建 55 | * 安装go二进制文件 到镜像网站下载 https://goproxy.io/zh/ 56 | * 下载Goland IDEA,设置GOPATH 57 | * 配置GOPROXY代理,不然很慢 58 | * go get xxx 下载xxx包 59 | * go mod tidy 刷新 类似maven update 60 | * go三层经典模型 61 | * Transport 主要负责Http, gRpc, thrift 62 | * Services 业务函数 63 | * Endpoint 定义request, response格式等 64 | * 四种变量声明方式 65 | * channel,go语言是如何实现不同协程之前通信的呢?其他语言是通过共享内存来实现通信,而go语言是通过通信来实现共享。一个重要的特性:不论是从channel中读一条消息,还是往channel中发送一条消息,都会阻塞当前代码运行。 66 | 67 | ##### 指针 68 | 取址运算符“&”用于获取对象地址。 69 | 指针运算符“*”用于间接引用目标对象。 70 | ```code 71 | x := 10 72 | var p *int = &x // 获取地址,保存到指针变量 73 | *p += 20 // 用指针间接引用,并更新对象 74 | ``` 75 | 76 | ### 注意 77 | * go语言中{不能单独放在一行,否则运行时会产生错误 78 | 79 | ### 其他 80 | * facebook grace平滑升级项目 81 | * 腾讯在15年的时候使用go做了docker万台规模,主要用于蓝鲸游戏平台 82 | 83 | ### 常见错误 84 | * package command-line-arguments is not a main package 85 | 要运行的go文件,package不是main。PS,也要有一个main函数 86 | 87 | * sql: Scan error on column index 3, name "created_at": unsupported Scan, storing driver.Value type []uint8 into type *time.Time 88 | 在conn上加parseTime=true,eg `/guestdb?charset=utf8&parseTime=true` -------------------------------------------------------------------------------- /golang/basic/go-question.md: -------------------------------------------------------------------------------- 1 | # Go语言答疑解惑 2 | 3 | ## channel 4 | * 从一个关闭的 channel 仍然能读出数据吗 5 | * channel 有哪些应用 6 | * 如何优雅地关闭 channel 7 | * channel 在什么情况下会引起资源泄漏 8 | * 什么是 CSP 9 | * channel 底层的数据结构是什么 10 | * channel 发送和接收元素的本质是什么 11 | * 关于 channel 的 happened-before 有哪些 12 | * 向 channel 发送数据的过程是怎样的 13 | * 从 channel 接收数据的过程是怎样的 14 | * 操作 channel 的情况总结 15 | * 关闭一个 channel 的过程是怎样的 16 | 17 | ## map 18 | * map 的底层实现原理是什么 19 | * 可以边遍历边删除吗 20 | * map 的删除过程是怎样的 21 | * 可以对 map 的元素取地址吗 22 | * 如何比较两个 map 相等 23 | * 如何实现两种 get 操作 24 | * map 是线程安全的吗 25 | * map 的遍历过程是怎样的 26 | * map 中的 key 为什么是无序的 27 | * float 类型可以作为 map 的 key 吗 28 | * map 的赋值过程是怎样的 29 | * map 的扩容过程是怎样的 30 | 31 | ## interface 32 | * iface 和 eface 的区别是什么 33 | * Go 接口与 C++ 接口有何异同 34 | * 接口转换的原理 35 | * 如何用 interface 实现多态 36 | * Go 语言与鸭子类型的关系 37 | * 值接收者和指针接收者的区别 38 | * 接口的构造过程是怎样的 39 | * 编译器自动检测类型是否实现接口 40 | * 类型转换和断言的区别 41 | * 接口的动态类型和动态值 42 | 43 | ## 标准库 44 | * context 如何被取消 45 | * context 是什么 46 | * context 有什么作用 47 | * context.Value 的查找过程是怎样的 48 | * unsafe 49 | * Go指针和unsafe.Pointer有什么区别 50 | * 如何利用unsafe包修改私有成员 51 | * 如何利用unsafe获取slice&map的长度 52 | * 如何实现字符串和byte切片的零拷贝转换 53 | 54 | ## goroutine 调度器 55 | * g0 栈何用户栈如何切换 56 | * goroutine 如何退出 57 | * goroutine 调度时机有哪些 58 | * goroutine和线程的区别 59 | * GPM 是什么 60 | * M 如何找工作 61 | * mian gorutine 如何创建 62 | * schedule 循环如何启动 63 | * schedule 循环如何运转 64 | * sysmon 后台监控线程做了什么 65 | * 一个调度相关的陷阱 66 | * 什么是 go shceduler 67 | * 什么是M:N模型 68 | * 什么是workstealing 69 | * 描述 scheduler 的初始化过程 70 | 71 | ## 编译和链接 72 | * Go 程序启动过程是怎样的 73 | * Go 编译相关的命令详解 74 | * Go 编译链接过程概述 75 | * GoRoot 和 GoPath 有什么用 76 | * 逃逸分析是怎么进行的 77 | 78 | ## 反射 79 | * Go 语言中反射有哪些应用 80 | * Go 语言如何实现反射 81 | * 什么情况下需要使用反射 82 | * 什么是反射 83 | * 如何比较两个对象完全相同 84 | 85 | ## 数组与切片 86 | * 切片作为函数参数 87 | * 切片的容量是怎样增长的 88 | * 数组和切片有什么异同 89 | 90 | 91 | ## GC 的认识 92 | * 什么是 GC,有什么作用? 93 | * 根对象到底是什么? 94 | * 常见的 GC 实现方式有哪些?Go 语言的 GC 使用的是 95 | * 三色标记法是什么? 96 | * STW 是什么意思? 97 | * 如何观察 Go GC? 98 | * 有了 GC,为什么还会发生内存泄露? 99 | * 并发标记清除法的难点是什么? 100 | * 什么是写屏障、混合写屏障,如何实现? 101 | * Go 语言中 GC 的流程是什么? 102 | * 触发 GC 的时机是什么? 103 | * 如果内存分配速度超过了标记清除的速度怎么办? 104 | * GC 关注的指标有哪些? 105 | * Go 的 GC 如何调优? 106 | * Go 的垃圾回收器有哪些相关的 API?其作用分 107 | * Go 历史各个版本在 GC 方面的改进? 108 | * Go GC 在演化过程中还存在哪些其他设计?为什么没有被采用? 109 | * 目前提供 GC 的语言以及不提供 GC 的语言有哪些?GC 和 No GC 各自的优缺点是什么? 110 | * Go 对比 Java、V8 中 JavaScript 的 GC 性能如何? 111 | * 目前 Go 语言的 GC 还存在哪些问题? 112 | -------------------------------------------------------------------------------- /java/basic/concurrent.md: -------------------------------------------------------------------------------- 1 | [并行与并发的区别](http://note.youdao.com/noteshare?id=07f1542ba53ff20ccf6e036a1a8a52d1) 2 | [线程安全](http://note.youdao.com/noteshare?id=6f65c98d2421430a5faa8e129ee77cb7) -------------------------------------------------------------------------------- /java/basic/draw.drawio: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/java/basic/draw.drawio -------------------------------------------------------------------------------- /java/basic/hashmap.md: -------------------------------------------------------------------------------- 1 | ### 学习笔记 2 | Hash几乎是面试的必考,我没事就找机会面试,几乎每次都被面到,面试的时候主要是考察你对Hash底层结构的理解,同时结合你项目实际中的使用来聊。我在这些年的开发和研发过程中,确实有很多场景的设计或者使用都或多或少用到了Hash,当然平时开发写代码,肯定少不了HashMap。面试官还喜欢问你对JDK7和8中HashMap的区别,也可以看看我的[面试宝典](../../tool/interview.md#盘涅) 3 | 4 | * HashMap 全理论 https://blog.csdn.net/weixin_34392227/article/details/112348756 5 | * HashMap面试题 https://www.cnblogs.com/aobing/p/12014271.html 6 | * HashMap JDK8以前头插法为什么会出现死循环 https://www.bilibili.com/video/BV1n541177Ea?spm_id_from=333.337.search-card.all.click 7 | 8 | 9 | ### 为什么链表长度达到8后变为红黑树 10 | https://www.pianshen.com/article/2770135206/ 11 | 12 | 13 | ### HashMap基础知识 14 | * [一致性Hash](http://note.youdao.com/noteshare?id=2df0dfa390855dde55075260b8ddc27a&sub=A2CDBD1C8B614310ABFF0F03682FAB7A) -------------------------------------------------------------------------------- /java/basic/img/Java访问权限控制.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/java/basic/img/Java访问权限控制.png -------------------------------------------------------------------------------- /java/basic/img/executor-service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/java/basic/img/executor-service.png -------------------------------------------------------------------------------- /java/basic/img/java-thread-pool-class.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/java/basic/img/java-thread-pool-class.jpg -------------------------------------------------------------------------------- /java/basic/img/java-thread-pool-method.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/java/basic/img/java-thread-pool-method.jpg -------------------------------------------------------------------------------- /java/basic/img/java-thread-states.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/java/basic/img/java-thread-states.jpg -------------------------------------------------------------------------------- /java/basic/img/multiple-thread-cas.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/java/basic/img/multiple-thread-cas.webp -------------------------------------------------------------------------------- /java/basic/img/synchronized-block.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/java/basic/img/synchronized-block.jpg -------------------------------------------------------------------------------- /java/basic/img/synchronized-method.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/java/basic/img/synchronized-method.jpg -------------------------------------------------------------------------------- /java/basic/img/thread-states.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/java/basic/img/thread-states.png -------------------------------------------------------------------------------- /java/basic/java-io-nio.md: -------------------------------------------------------------------------------- 1 | # IO简介 2 | ``` 3 | IO是Java中的一种输入和输出的功能,Java中对这种操作叫做对流的操作。 4 | 流代表的是任何有能力产出数据的数据源对象或者是有能力接受数据的接收端对象。 5 | 流的本质是数据传输,流不只是对文件可进行读写,还可以对内存、网络、程序操作。 6 | ``` 7 | 8 | ## 学习计划 9 | * [Java IO、NIO原理](https://www.jianshu.com/p/63d1c4476f45) 10 | * [讲的最好的同步/异步/阻塞/非阻塞/BIO/NIO/AIO的文章](http://note.youdao.com/noteshare?id=e00d8caf0973471780b8ca880e1c5bf9&sub=wcp1578879502523399) 11 | * [零拷贝](http://note.youdao.com/noteshare?id=13101142e0a628da85eca4a52df1596b&sub=wcp1579073093657123) 12 | * [如何学习Java的NIO](http://note.youdao.com/noteshare?id=5ea48ae4fd97f7a7bb4bd9d036ba4d11) 13 | * [一篇文章读懂阻塞,非阻塞,同步,异步](https://www.jianshu.com/p/b8203d46895c) 14 | * 结合代码来理解,这篇文章提到了底层的原理,但是不够深入 15 | * https://blog.csdn.net/qq_41936805/article/details/94675873 帮助理解多路复用 16 | * http://www.imooc.com/article/255865 有代码可以看下 17 | * [操作系统IO处理过程](https://blog.csdn.net/hutongling/article/details/69944456) 18 | * [Java IO层次体系结构](https://blog.csdn.net/qq_21870555/article/details/82999195) 19 | * [IO多路复用](https://www.jianshu.com/p/397449cadc9a) 20 | 21 | ## 学习笔记 22 | NIO是同步的IO,是因为程序需要IO操作时,必须获得了IO权限后亲自进行IO操作才能进行下一步操作。AIO是对NIO的改进(所以AIO又叫NIO.2),它是基于Proactor模型的。每个socket连接在事件分离器注册 IO完成事件 和 IO完成事件处理器。程序需要进行IO时,向分离器发出IO请求并把所用的Buffer区域告知分离器,分离器通知操作系统进行IO操作,操作系统自己不断尝试获取IO权限并进行IO操作(数据保存在Buffer区),操作完成后通知分离器;分离器检测到 IO完成事件,则激活 IO完成事件处理器,处理器会通知程序说“IO已完成”,程序知道后就直接从Buffer区进行数据的读写。 23 | 24 | 也就是说:AIO是发出IO请求后,由操作系统自己去获取IO权限并进行IO操作;NIO则是发出IO请求后,由线程不断尝试获取IO权限,获取到后通知应用程序自己进行IO操作。 25 | 同步/异步:数据如果尚未就绪,是否需要等待数据结果。 26 | 阻塞/非阻塞:进程/线程需要操作的数据如果尚未就绪,是否妨碍了当前进程/线程的后续操作。应用程序的调用是否立即返回! 27 | NIO与BIO最大的区别是 BIO是面向流的,而NIO是面向Buffer的。 28 | 29 | Buffer是一块连续的内存块,是 NIO 数据读或写的中转地。 为什么说NIO是基于缓冲区的IO方式呢?因为,当一个链接建立完成后,IO的数据未必会马上到达,为了当数据到达时能够正确完成IO操作,在BIO(阻塞IO)中,等待IO的线程必须被阻塞,以全天候地执行IO操作。为了解决这种IO方式低效的问题,引入了缓冲区的概念,当数据到达时,可以预先被写入缓冲区,再由缓冲区交给线程,因此线程无需阻塞地等待IO。 30 | 31 |   缓冲区实际上是一个容器对象,更直接的说,其实就是一个数组,在NIO 库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的; 在写入数据时,它也是写入到缓冲区中的;任何时候访问NIO 中的数据,都是将它放到缓冲区中。而在面向流I/O 系统中,所有数据都是直接写入或者直接将数据读取到Stream 对象中。在NIO 中,所有的缓冲区类型都继承于抽象类Buffer,最常用的就是ByteBuffer 32 | # Java IO中常用的类 33 | ``` 34 | 整个Java IO包中最重要的就是5个类和一个接口。 35 | 5个类指: 36 | * File:用于文件或者目录的描述信息,例如生成新的目录,修改文件名,删除文件,判断文件,过滤文件等 37 | * OutputStream:抽象类,基于字节的输出操作,是所有输出流的父类。 38 | * InputStream:抽象类,基于字节的输入操作,是所有输入流的父类。 39 | * Writer:抽象类,基于字符的输出操作。 40 | * Reader:抽象类,基于字符的输入操作。 41 | 一个接口指:Serializable 42 | 另外一个特殊的类:RandomAccessFile:随机文件操作,可以从文件任意位置进行存取(输入输出)操作。 43 | ``` 44 | `IO接口和类的结构图可参考技术栈图` 45 | 46 | ## RandomAccessFile 47 | ``` 48 | 我们在对文件的操作过程中,除了使用字节流和字符流的方式之外,我们还可以使用RandomAcessFile这个工具类来实现。 49 | RandomAccessFile可以实现对文件的读 和 写,但是他并不是继承于以上4中基本虚拟类。 50 | 而且在对文件的操作中,RandomAccessFile有一个巨大的优势,他可以支持文件的随机访问,程序快可以直接跳转到文件的任意地方来读写数据。所以如果需要访问文件的部分内容,而不是把文件从头读到尾,使用RandomAccessFile将是更好的选择。 51 | RandomAccessFile的方法虽然多,但它有一个最大的局限,就是只能读写文件,不能读写其他IO节点。 52 | RandomAccessFile的一个重要使用场景就是网络请求中的多线程下载及断点续传。 53 | ``` 54 | 55 | # 字符与字节 56 | Java中有输入和输出两种IO流,每种输入输出流又分为字节流和字符流两大类。 57 | 58 | * 关于字节:每个字节(byte)有8bit组成 59 | * 关于字符:一个字符代表一个英文字母或一个汉字 60 | 61 | ## 字符与字节的关系 62 | Java采用unicode编码,2个字节表示1个字符 63 | 64 | # 总结 65 | * 先进先出,最先写入输出流的数据最先被输入流读取到 66 | * 顺序读取,不能随机访问数据(RandomAccessFile除外) 67 | * 只读只写,每个流只能是输入流或输出流的一种 68 | * 每次进行IO操作,要手动close,因为IO资源并不属于内存资源,并不会被GC回收 69 | * 对于输出操作,flush()会刷新输出流,强制缓冲区中的输出字节被写出; close()关闭输出流,释放和这个流相关的系统资源,调用close()会自动flush 70 | * 流结束的判断:方法read()的返回值为-1时;readLine()的返回值为null时 71 | * 节流没有缓冲区,是直接输出的,而字符流是输出到缓冲区的。因此在输出时,字节流不调用colse()方法时,信息已经输出了,而字符流只有在调用close()方法关闭缓冲区时,信息才输出。要想字符流在未关闭时输出信息,则需要手动调用flush()方法 72 | * 字节流与字符流区别 73 | * 字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节 74 | * 字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据 75 | * 只要是处理纯文本数据,就优先考虑使用字符流。除此之外都使用字节流 76 | 77 | # Java IO与IO的区别和比较 78 | 79 | # NIO 80 | 传统的 Socket 阻塞模式直接导致每个 Socket 都必须绑定一个线程来操作数据,参与通信的任意一方如果处理数据的速度较慢,则都会直接拖累另一方,导致另一方的线程不得不浪费大量的时间在 I/O 等待上,所以,每个 Socket 要绑定一个单独的线程正是传统Socket 阻塞模式的根本“缺陷”。之所以这里加了“缺陷”两个字,是因为这种模式在一些特定场合下效果是最好的,比如只有少量的 TCP 连接通信,双方都非常快速地传输数据,此时这种模式的性能最高。 81 | 82 | 现在我们可以开始分析“非阻塞”模式了,它就是要解决 I/O 线程与 Socket 解耦的问题,因此,它引入了事件机制来达到解耦的目的。我们可以认为 NIO 底层中存在一个 I/O 调度线程,它不断扫描每个 Socket 的缓冲区,当发现写入缓冲区为空(或者不满)的时候,它会产生一个Socket 可写事件,此时程序就可以把数据写入 Socket 里,如果一次写不完,则等待下次可写事件的通知;而当发现读取缓冲区里有数据的时候,它会产生一个 Socket 可读事件,程序收到这个通知事件时,就可以从 Socket 读取数据了。 83 | 84 | 85 | 86 | 内核空间、用户空间、计算机体系结构、计算机组成原理、…… 确实有点儿深奥。 87 | 88 | 我的新书《代码之谜》会有专门的章节讲解相关知识,现在写个简短的科普文: 89 | 90 | 就速度来说 CPU > 内存 > 硬盘 91 | 92 | I- 就是从硬盘到内存 93 | O- 就是从内存到硬盘 94 | 95 | 第一种方式:我从硬盘读取数据,然后程序一直等,数据读完后,继续操作。这种方式是最简单的,叫阻塞IO。 96 | 97 | 第二种方式:我从硬盘读取数据,然后程序继续向下执行,等数据读取完后,通知当前程序(对硬件来说叫中断,对程序来说叫回调),然后此程序可以立即处理数据,也可以执行完当前操作在读取数据。 98 | 99 | 在一起的 Java IO 中,都是阻塞式 IO,NIO 引入了非阻塞式 IO。 100 | 101 | 还有一种就是同步 IO 和异步 IO。经常说的一个术语就是“异步非阻塞”,好象异步和非阻塞是同一回事,这大概是一个误区吧。 102 | 103 | 至于 Java NIO 的 Selector,在旧的 Java IO 系统中,是基于 Stream 的,即“流”,流式 IO。 104 | 105 | 当程序从硬盘往内存读取数据的时候,操作系统使用了 2 个“小伎俩”来提高性能,那就是预读,如果我读取了第一扇区的第三磁道的内容,那么你很有可能也会使用第二磁道和第四磁道的内容,所以操作系统会把附近磁道的内容提前读取出来,放在内存中,即缓存。 106 | 107 | (PS:以上过程简化了) 108 | 109 | 通过上面可以看到,操作系统是按块 Block从硬盘拿数据,就如同一个大脸盆,一下子就放入了一盆水。但是,当 Java 使用的时候,旧的 IO 确实基于 流 Stream的,也就是虽然操作系统给我了一脸盆水,但是我得用吸管慢慢喝。 110 | 111 | 于是,NIO 横空出世。 112 | 113 | ### 总结 114 | Java中的IO/NIO:多路复用 IO 模型 115 | 1、多路复用 IO 模型是目前使用得比较多的模型。Java NIO 实际上就是多路复用 IO。在多路复用 IO 模型中,会有一个线程不断去轮询多个 socket 的状态,只有当 socket 真正有读写事件时,才真正调用实际的 IO 读写操作。因为在多路复用 IO 模型中,只需要使用一个线程就可以管理多个socket,系统不需要建立新的进程或者线程,也不必维护这些线程和进程,并且只有在真正有 socket 读写事件进行时,才会使用 IO 资源,所以它大大减少了资源占用。在 Java NIO 中,是通过 selector.select()去查询每个通道是否有到达事件,如果没有事件,则一直阻塞在那里,因此这种方式会导致用户线程的阻塞。多路复用 IO 模式,通过一个线程就可以管理多个 socket,只有当 socket 真正有读写事件发生才会占用资源来进行实际的读写操作。因此,多路复用 IO 比较适合连接数比较多的情况。 116 | 2、另外多路复用 IO 为何比非阻塞 IO 模型的效率高是因为在非阻塞 IO 中,不断地询问 socket 状态时通过用户线程去进行的,而在多路复用 IO 中,轮询每个 socket 状态是内核在进行的,这个效率要比用户线程要高的多。 117 | 3、不过要注意的是,多路复用 IO 模型是通过轮询的方式来检测是否有事件到达,并且对到达的事件逐一进行响应。因此对于多路复用 IO 模型来说, 118 | 一旦事件响应体很大,那么就会导致后续的事件迟迟得不到处理,并且会影响新的事件轮询。 119 | I/O复用是多路复用,这里的多路是指N个连接,每一个连接对应一个channel,或者说多路就是多个channel。复用,是指多个连接复用了一个线程或者少量线程(在Tomcat中是Math.min(2,Runtime.getRuntime().availableProcessors()))。 120 | 121 | # Reference 122 | * [Java IO详解](https://www.jianshu.com/p/aea76bc0e6d1) 123 | * [深入理解Java中的IO](https://www.cnblogs.com/ylspace/p/8128112.html) 124 | * [Java IO与IO的区别和比较](https://blog.51cto.com/825272560/2059144) -------------------------------------------------------------------------------- /java/basic/java-thread-executor-framework.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/java/basic/java-thread-executor-framework.png -------------------------------------------------------------------------------- /java/basic/java-thread-future-api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/java/basic/java-thread-future-api.png -------------------------------------------------------------------------------- /java/basic/java-thread-pool-process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/java/basic/java-thread-pool-process.png -------------------------------------------------------------------------------- /java/javaweb/filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/java/javaweb/filter.png -------------------------------------------------------------------------------- /java/javaweb/servlet.md: -------------------------------------------------------------------------------- 1 | # Servlet 2 | 3 | ## 目录 4 | * [Servlet简介](#Servlet简介) 5 | * [Servlet环境配置](#Servlet环境配置) 6 | * [Servlet生命周期](#Servlet生命周期) 7 | * [Servlet表单处理](#Servlet表单处理) 8 | * [Servlet过滤器](#Servlet过滤器) 9 | * [Servlet监听器](#Servlet监听器) 10 | 11 | ## Servlet简介 12 | Servlet是运行在Web服务器或应用服务器上的程序,是介于HTTP Client和数据库或者应用程序之间的中间层。从实现上来讲,Servlet只用来扩展基于HTTP协议的Web服务器。 13 | 14 | ## Servlet环境配置 15 | Servlet不是Java平台标准版的组成部分,需要为编译器指定Servlet类的路径。 16 | ``` 17 | 我的电脑-> 属性-> 高级-> 环境变量-> 更新CLASSPATH(apache-tomcat-xxx/common\lib\servlet-api.jar) 18 | ``` 19 | 20 | ## Servlet生命周期 21 | Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程: 22 | * Servlet 通过调用 init () 方法进行初始化。 23 | * Servlet 调用 service() 方法来处理客户端的请求。Servlet容器处理由多个线程产生的多个请求,每个线程执行一个单一的Servlet实例的doService方法。 24 | * Servlet 通过调用 destroy() 方法终止(结束)。 25 | * 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。 26 | 27 | ## Servlet表单处理 28 | * doGet方法处理get请求,doPost方法处理post请求 29 | * 读取表单数据 30 | * getParameter() 31 | * getParameterValues() 32 | * getParameterNames() 33 | * 转发和重定向 34 | * request.getRequestDispatcher(".../xx.jsp").forwared(request, response); 35 | * response.sendRedirect("xxxx") 36 | 37 | ## Servlet过滤器 38 | * 作用:可以实现用户在访问某个资源之前,对访问的请求和响应进行拦截 39 | ![](filter.png) 40 | 41 | ## Servlet监听器 42 | * 作用:可以在事情发生的前后做一些必要的处理 43 | * Listener的三大作用域request, session ServletContext 44 | * Servlet八大监听器和与之对应的Event 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 |
Listener接口Event类
ServletContextListenerServletContextEvent
ServletContextAttributeListenerServletContextAttributeEvent
HttpSessionListenerHttpSessionEvent
HttpSessionActivationListener
HttpSessionAttributeListenerHttpSessionBindingEvent
HttpSessionBindingListener
ServletRequestListenerServletRequestEvent
ServletRequestAttributeListenerServletRequestAttributeEvent
57 | 58 | `eg` 59 | ```java 60 | public class MySessionListener implements HttpSessionListener { 61 | 62 | public void sessionCreated(HttpSessionEvent se) { 63 | HttpSession hs=se.getSession(); 64 | System.out.println(hs.getId()); 65 | } 66 | 67 | public void sessionDestroyed(HttpSessionEvent se) { 68 | System.out.println("Session Destoryed"); 69 | } 70 | } 71 | ``` -------------------------------------------------------------------------------- /java/jvm/JVM虚拟机监控及性能调优.md: -------------------------------------------------------------------------------- 1 | # 目录 2 | * [jvisualvm介绍](#jvisualvm介绍) 3 | * [jvisualvm使用](#jvisualvm使用) 4 | * [jvisualvm监控远程服务器](#jvisualvm监控远程服务器) 5 | * [jvisualvm集成Visual GC插件](#jvisualvm集成Visual-GC插件) 6 | * [常见问题](#常见问题) 7 | * [引用](#引用) 8 | 9 | ## jvisualvm介绍 10 | 1. jvisualvm是JDK自带的可以远程监控内存,跟踪垃圾回收,执行时内存,CPU/线程分析,生成堆快照等的工具。 11 | 2. jvisualvm是从JDK1.6开始被继承到JDK中的。 12 | 13 | ## jvisualvm使用 14 | 15 | ### jvisualvm监控远程服务器 16 | `开启远程监控` 17 | * 通过在服务器上设置jmx参数来开启 18 | ``` 19 | vi /etc/profile 20 | export JAVA_OPTS='-Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=N -Djava.rmi.server.hostname=x.x.x.x -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false' 21 | ``` 22 | * 通过启动jar命令开启 23 | ``` 24 | java -Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=N -Djava.rmi.server.hostname=x.x.x.x -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -jar xxx.jar 25 | ``` 26 | 27 | `连接` 28 | * 打开jvisualvm,在远程中添加需要监控的服务器,然后再在该服务器下添加jmx监控连接 29 | ![jmx-monitor](png/jmx-monitor.png) 30 | 31 | ### jvisualvm集成Visual-GC插件 32 | `Visual GC插件安装` 33 | * 到https://visualvm.github.io/pluginscenters.html去下载对应的Visual GC Plugins 34 | 35 | ![visual-gc-plugins](png/visual-gc-plugins.png) 36 | 37 | * 更改visual-gc配置中心URL 38 | 39 | ![update-visual-gc-settings](png/update-visual-gc-settings.png) 40 | 41 | * 安装Visual GC Plugin 42 | 43 | ![install-visual-gc-plugin](png/install-visual-gc-plugin.png) 44 | 45 | `Visual GC正确开启步骤` 46 | * 在远程主机上添加安全策略文件 47 | ```shell 48 | [root@localhost ~] touch jstatd.all.policy 49 | [root@localhost ~] vi jstatd.all.policy 50 | grant codebase "file:${java.home}/../lib/tools.jar" { 51 | permission java.security.AllPermission; 52 | }; 53 | ``` 54 | > 注意:如果没有配置JDK环境变量,file后需要添加tool.jar的绝对路径 55 | * 在远程主机上启动监控 56 | ```shell 57 | [root@localhost ~] jstatd -J-Djava.security.policy=/xxx/jstatd.all.policy -J-Djava.rmi.server.logCalls=true -J-Djava.rmi.server.hostname=xx.xx.xx.xx -p 1099 58 | ``` 59 | * 参数说明 60 | * -J-Djava.rmi.server.logCalls=true 打开日志,便于排错 61 | * -J-Djava.rmi.server.hostname=xx.xx.xx.xx hostname是本机IP地址,确保client能访问到,另外查看本机的hosts是否有其他配置,这里有坑,具体参照常见问题中的[XXXX](#) 62 | * 可以查看端口是否被正常监听 63 | ```shell 64 | [root@localhost ~]# lsof -i:1099 65 | COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME 66 | jstatd 110703 root 15u IPv6 7374636 0t0 TCP *:rmiregistry (LISTEN) 67 | jstatd 110703 root 17u IPv6 7373817 0t0 TCP localhost:rmiregistry->x.x.x.x:62209 (ESTABLISHED) 68 | ``` 69 | * 使用visualvm连接 70 | * 添加jstatd连接,注意端口号和远程服务器开启的端口号保持一致 71 | > 注意:远程服务器端口要设置开放 72 | 73 | * 参考视图 74 | ![visual-gc-view](png/visual-gc-view.png) 75 | 76 | 77 | # 常见问题 78 | * 开启OOM-dump 79 | ```shell 80 | nohup java -Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=N -Djava.rmi.server.hostname=x.x.x.x -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -XX:+HeapDumpOnOutOfMemoryError -jar xxx.jar -XX:HeapDumpPath=~/dumps/ > nohup.log 2>&1 & 81 | ``` 82 | 83 | * Visual GC提示"不受此JVM支持“ 84 | ```log 85 | Could not create remote object 86 | access denied ("java.util.PropertyPermission" "java.rmi.server.ignoreSubClasses" "write") 87 | java.security.AccessControlException: access denied ("java.util.PropertyPermission" "java.rmi.server.ignoreSubClasses" "write") 88 | at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472) 89 | at java.security.AccessController.checkPermission(AccessController.java:884) 90 | at java.lang.SecurityManager.checkPermission(SecurityManager.java:549) 91 | at java.lang.System.setProperty(System.java:792) 92 | at sun.tools.jstatd.Jstatd.main(Jstatd.java:139) 93 | ``` 94 | * Could not contact registry,指向的IP地址是一个其他的地址 95 | ```log 96 | [root@localdomain bin]# ./jstatd -J-Djava.security.policy=jstatd.all.policy 97 | Could not contact registry 98 | Connection refused to host: y.y.y.y; nested exception is: 99 | java.net.ConnectException: Connection refused 100 | java.rmi.ConnectException: Connection refused to host: y.y.y.y; nested exception is: 101 | ``` 102 | > 注意:我在这里查看了远程机器的hosts,发现其配有一些其他的IP,将其删除后能够联通 103 | * 快速定位导致cpu飙升的线程堆栈信息 104 | ```log 105 | top 首先通过top命令找到高负载的CPU,获取进程id 106 | top -p <进程id> 精确定位到cpu高的进程,然后按H键,查看该进程所有线程 107 | 或者 top -p 进程id -H 查看进程下的线程 108 | printf "%x" 进程id 将进程号转化为16进制,注意把十六进制的大写字母转换为小写 109 | jstack 进程id > xxx.txt 导出日志,然后在日志中查找nid=转换后进程id 110 | 或者 jstack 进程ID|grep -A 10 55a0 10表示这个线程所在行后面10行,55a0是进程ID转换后的十六进制 111 | ``` 112 | * 查看堆内存使用情况 113 | ``` 114 | jps查看各个应用进程id 115 | jmap -heap java项目进程id 116 | jmap -histo 进程id > log.txt 查看此应用中各实例生成情况 117 | jmap -histo:live [pid] > log.txt 过滤存活的对象 118 | ``` 119 | * 查找代码死锁 120 | ``` 121 | jstack 进程id > xxx.txt 导出日志 122 | 搜索 deadlock 或者查 locked关键字找到发生死锁线程 123 | ``` 124 | 125 | # 引用 126 | * [jvisualvm简要说明](https://blog.csdn.net/weixin_38750084/article/details/83314046) 127 | * [jvisualvm 连接 jstatd 远程监控 jvm 或 Visual GC提示"不受此JVM支持“](https://blog.csdn.net/liupeifeng3514/article/details/78998161) 128 | * [使用Java VisualVM监控远程JVM](https://www.jianshu.com/p/2a6658e94ae2) 129 | * [Visualvm 远程测试 问题](https://www.cnblogs.com/kentyshang/archive/2009/08/20/1550745.html) 130 | * [visualgc - Visual Garbage Collection Monitoring Tool](https://www.oracle.com/technetwork/java/visualgc-136680.html) -------------------------------------------------------------------------------- /java/jvm/png/install-visual-gc-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/java/jvm/png/install-visual-gc-plugin.png -------------------------------------------------------------------------------- /java/jvm/png/jmx-monitor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/java/jvm/png/jmx-monitor.png -------------------------------------------------------------------------------- /java/jvm/png/update-visual-gc-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/java/jvm/png/update-visual-gc-settings.png -------------------------------------------------------------------------------- /java/jvm/png/visual-gc-plugins.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/java/jvm/png/visual-gc-plugins.png -------------------------------------------------------------------------------- /java/jvm/png/visual-gc-view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/java/jvm/png/visual-gc-view.png -------------------------------------------------------------------------------- /java/jvm/深入理解Java虚拟机.md: -------------------------------------------------------------------------------- 1 | ### 学习计划 2 | * 初识JVM这篇就够了 3 | * JVM模块详解 4 | * 虚拟机执行子系统 5 | * 程序计数器 6 | * 虚拟机栈 7 | * 堆 8 | * 方法区 9 | * 本地方法 10 | * JVM垃圾回收机制 11 | * Java对象创建的步骤 12 | * 虚拟机执行子系统 13 | 14 | ### 学习笔记 15 | * [Java虚拟机概述](http://note.youdao.com/noteshare?id=04255aa8ae9ab45ed502296d57c736d3&sub=D4C06128EBBD414C91D85B7F89AB0C91) 16 | * [Java内存模型(JMM)概述](http://note.youdao.com/noteshare?id=853bd6ff9802006899b9e0837fece691&sub=wcp1576467027359972) 17 | * [volatile关键字解析](http://note.youdao.com/noteshare?id=b463861623604a614e0ceb2e27f4b36e&sub=ED4A85833F6F4531A65BBC382E218D32) 18 | * [Java内存区域和对象创建及内存分配](http://note.youdao.com/noteshare?id=c5cc62733e28ed05ea252db5243ca797&sub=3386EF7F877C493DACA2FDD53BC0E0E4) 19 | * [JVM垃圾回收机制](http://note.youdao.com/noteshare?id=210c03900e584c1001b4b16d4060dc89&sub=wcp1581062973917549) 20 | * [JVM堆内存(heap)及垃圾回收总结](http://note.youdao.com/noteshare?id=27f16d42fea30933884b640a941e8587&sub=wcp1580995061039682) 21 | * [Java对象的创建过程解析](http://note.youdao.com/noteshare?id=720b1f1bef16d494b767edeaf52e1eee&sub=wcp158116390844063) 22 | 23 | ## 走近Java 24 | 1. 微软公司曾今是Java技术的铁杆支持者,令Java从跨平台技术变为绑定在Windows上的技术是微软的主要目的,然而后期Sun公司控告微软,致使微软不得不在后期产品中逐步移除Java平台,也间接导致.NET平台的产生,2002年微软发布.NET技术平台,这才有了后期的.NET与Java之争。 25 | 26 | 2. 多核并行,在JDK1.5就引入java.util.concurrent包实现粗粒度的并发框架,在JDK1.7中加入java.util.concurrent.forkjoin包则是对这个框架的一次重要扩充。Fork/Join模式是处理并行编程的一个经典方法。 27 | 28 | ## 理解JVM内存模型 29 | Java内存模型(Java Memory Model,JMM)是java虚拟机规范定义的,用来屏蔽掉java程序在各种不同的硬件和操作系统对内存的访问的差异,这样就可以实现java程序在各种不同的平台上都能达到内存访问的一致性。可以避免像c++等直接使用物理硬件和操作系统的内存模型在不同操作系统和硬件平台下表现不同,比如有些c/c++程序可能在windows平台运行正常,而在linux平台却运行有问题。 30 | 31 | ### 运行时数据区域 32 | 33 | 34 | 35 | # 自动化内存管理机制 36 | ## Java内存区域与内存溢出异常 37 | ## 垃圾收集器与内存分配策略 38 | ## 虚拟机性能监控与故障处理工具 39 | ## 调优案例分析与实战 40 | 41 | # 虚拟机执行子系统 42 | ## 类文件结构 43 | ## 虚拟机类加载机制 44 | ## 虚拟机字节码执行引擎 45 | ## 类加载及执行子系统的案例与实战 46 | 47 | # 程序编译与代码优化 48 | ## 早期(编译器)优化 49 | ## 晚期(运行期)优化 50 | 51 | # 高效并发 52 | ## Java内存模型与线程 53 | ## 线程安全与锁优化 54 | 55 | ### JVM 56 | * JVM初始分配的堆内存由-Xms指定,默认是物理内存的1/64;JVM的最大分配的堆内存由-Xmx指定,默认是物理内存的1/4.默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx最大限制;空余堆内存大于70%时,JVM就会减少堆直到-Xms的最小限制。因此,服务器端一般设置-Xms、-Xmx相等以避免在每次GC后调整堆的大小。 57 | 58 | ### JConsole 59 | * Java 5开始引入JConsole 60 | 61 | ### 深入拆解Java虚拟机 62 | * 可以使用-XX:+HeapDumpOnOutOfMemoryError参数来让虚拟机出现OOM的时候自动生成dump文件 63 | * ClassLoader的具体作用就是将class文件加载到jvm虚拟机中去,程序就可以正确运行了。但是,jvm启动的时候,并不会一次性加载所有的class文件,而是根据需要去动态加载。 64 | * Java 虚拟机是如何判定两个 Java 类是相同的。Java 虚拟机不仅要看类的全名是否相同,还要看加载此类的类加载器是否一样。只有两者都相同的情况,才认为两个类是相同的。即便是同样的字节代码,被不同的类加载器加载之后所得到的类,也是不同的。 65 | * ClassLoader 66 | * BootStrap ClassLoader:称为启动类加载器,是Java类加载层次中最顶层的类加载器,负责加载JDK中的核心类库,如:rt.jar、resources.jar、charsets.jar等 67 | * Extension ClassLoader:称为扩展类加载器,负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目下的所有jar。 68 | * App ClassLoader:称为系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件。 69 | * 除了Java默认提供的三个ClassLoader之外,用户还可以根据需要定义自已的ClassLoader,而这些自定义的ClassLoader都必须继承自java.lang.ClassLoader类,也包括Java提供的另外二个ClassLoader(Extension ClassLoader和App ClassLoader)在内,但是Bootstrap ClassLoader不继承自ClassLoader,因为它不是一个普通的Java类,底层由C++编写,已嵌入到了JVM内核当中,当JVM启动后,Bootstrap ClassLoader也随着启动,负责加载完核心类库后,并构造Extension ClassLoader和App ClassLoader类加载器。 70 | 71 | ### 堆内内存与堆外内存 72 | 堆内拷贝到堆外的原因: 操作系统把内存中的数据写入磁盘或网络时,要求数据所在的内存区域不能变动,但是JVM的GC机制会对内存进行整理,导致数据内存地址发生变化,所以无奈,JDK只能先拷贝到堆外内存(不受GC影响),然后把这个地址发给操作系统。 73 | 74 | # *JDK* 75 | ### JDK中自带的工具 76 | #### `version 1.8` 77 | 78 | #### Create and Build Applications 79 | * appletviewer 80 | * extcheck 81 | * jar 82 | * java 83 | * javac 84 | * javadoc 85 | * javah 86 | * javap 87 | * jdb 88 | * jdeps 89 | 90 | #### Security 91 | * keytool 92 | * jarsigner 93 | * policytool 94 | 95 | #### Internationalization 96 | * native2ascli 97 | 98 | #### Remote Method Invocation(RMI) 99 | * rmic 100 | * rmiregistry 101 | * rmid 102 | * serialver 103 | 104 | #### Java IDL and RMI-IIOP 105 | * tnameserv 106 | * idlj 107 | * orbd 108 | * servertool 109 | 110 | #### Deploy Applications and Applets 111 | * pack200 112 | * unpack200 113 | * javapackager 114 | * javafxpackager 115 | 116 | #### Java Web Start 117 | * javaws 118 | 119 | #### Monitor Java Applications 120 | * jconsole 121 | * jvisualvm 122 | 123 | #### Monitor the JVM 124 | * jps 125 | * jstat 126 | * jstatd 127 | * jmc 128 | 129 | #### Web Services 130 | * schemagen 131 | * wsgen 132 | * wsimport 133 | * xjc 134 | 135 | #### Troubleshooting 136 | * jcmd 137 | * jinfo 138 | * jhat 139 | * jmap 140 | * jsadebugd 141 | * jstack 142 | 143 | #### Scripting 144 | * jrunscript 145 | * jjs 146 | 147 | # FAO 148 | 1. 函数式编程的一个重要优点就是这样的程序天然地适合并行运行,why? -------------------------------------------------------------------------------- /java/spring/image/documented-annotation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/java/spring/image/documented-annotation.png -------------------------------------------------------------------------------- /java/spring/image/hystrix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/java/spring/image/hystrix.png -------------------------------------------------------------------------------- /java/spring/spring-boot/1-springboot-basic.md: -------------------------------------------------------------------------------- 1 | > 本篇主要介绍Spring Boot中的基础知识 2 | 3 | ### `Spring Boot文件目录介绍` 4 | * /src 5 | * main 6 | * java: 目录下放置所有的Java文件 7 | * resource: 存放所有的资源文件,包括静态资源文件、配置文件、页面文件等 8 | * static: 存放各类静态资源 9 | * application.properties:配置文件,SpringBoot默认支持.properties和.yml这两种格式的配置文件 10 | * templates: 用于存放各类模板文件,如thymeleaf 11 | * test 12 | * java: 放置单元测试类的Java代码 13 | * /target:放置编译后的.class文件、配置文件等 14 | 15 | Spring Boot将很多配置文件进行了统一管理,且配置了默认值。Spring Boot会自动在/src/main/resources目录下寻找application.properties或者application.yml配置文件。.properties配置文件的优先级高于.yml。 16 | 17 | ### `Spring Boot中的起步依赖` 18 | 19 | ### `Spring Boot中相关注解` 20 | 21 | * @SpringBootApplication: 是一个组合注解,包含@EnableAutoConfiguration,@ComponentScan和@SpringBootConfiguration三个注解,是项目启动注解。 22 | 23 | ```java 24 | import org.springframework.boot.SpringApplication; 25 | import org.springframework.boot.atoconfigure.SpringBootApplication; 26 | 27 | @SpringBootApplication 28 | public class TestSpringBootApplication { 29 | public static void main(String[] args) { 30 | SpringApplication.run(TestSpringBootApplication.class, args); 31 | } 32 | } 33 | 34 | ``` 35 | 36 | ### @RestController和@Controller的区别 37 | @RestController注解相当于@ResponseBody + @Controller合在一起的作用。 38 | 1.使用@Controller 注解,在对应的方法上,视图解析器可以解析return 的jsp,html页面,并且跳转到相应页面,若返回json等内容到页面,则需要加@ResponseBody注解 39 | 2.@RestController注解,相当于@Controller+@ResponseBody两个注解的结合,返回json数据不需要在方法前面加@ResponseBody注解了,但使用@RestController这个注解,就不能返回jsp,html页面,视图解析器无法解析jsp,html页面, 配置的视图解析器 InternalResourceViewResolver不起作用,返回的内容就是Return 里的内容。 -------------------------------------------------------------------------------- /java/spring/spring-boot/2-spring-security.md: -------------------------------------------------------------------------------- 1 | Spring Security,是一个基于Spring AOP和Servlet过滤器的安全框架。它提供全面的安全性解决方案,同时在Web请求级和方法调用级处理身份确认和授权。 -------------------------------------------------------------------------------- /java/spring/spring-boot/springboot-admin.md: -------------------------------------------------------------------------------- 1 | Spring Boot Admin 用于监控基于 Spring Boot 的应用,它是在 Spring Boot Actuator 的基础上提供简洁的可视化 WEB UI。 2 | Spring Boot Admin 是一个管理和监控Spring Boot 应用程序的开源软件,它针对springboot的actuator接口进行UI美化封装。 3 | Spring Boot Admin 提供了很多功能,如显示 name、id 和 version,显示在线状态,Loggers 的日志级别管理,Threads 线程管理,Environment 管理等。 4 | 在 Spring Cloud 中基于 Eureka 的 Spring Boot Admin 的搭建 5 | 在 Spring Cloud 中基于 Nacos 的 Spring Boot Admin 的搭建 -------------------------------------------------------------------------------- /java/spring/spring-boot/springboot-note.md: -------------------------------------------------------------------------------- 1 | ### springboot各个依赖都是干什么的 2 | * spring-boot-starter-parent: spring-boot-starter-parent是一个特殊的starter,它用来提供相关的Maven默认依赖。使用它之后,常用的包依赖可以省去version标签。通过继承spring-boot-starter-parent,默认具备了如下功能:Java版本(Java8)、源码的文件编码方式(UTF-8)、依赖管理、打包支持、动态识别资源、识别插件配置、识别不同的配置,如:application-dev.properties 和 application-dev.yml 3 | * spring-boot-maven-plugin: 用于执行package命令是生成可执行的jar,如果不添加,执行java -jar时会报错 4 | “springboot-helloworld-2.2.5.RELEASE.jar中没有主清单属性” 5 | 6 | 7 | 8 | 9 | ### swagger 10 | * 配置依赖swagger2 11 | ```xml 12 | 13 | io.springfox 14 | springfox-swagger2 15 | 16 | 17 | io.springfox 18 | springfox-swagger-ui 19 | 20 | ``` 21 | * 配置Swagger2所需的Docket Bean 22 | ```java 23 | @Configuration 24 | @EnableSwagger2 25 | public class Swagger2Config { 26 | 27 | private ApiInfo apiInfo() { 28 | return new ApiInfoBuilder() 29 | .title("SpringBoot使用Swagger2构建api文档") 30 | .description("文档的详细描述") 31 | .version("1.0") 32 | .build(); 33 | } 34 | 35 | @Bean 36 | public Docket createRestApi() { 37 | return new Docket(DocumentationType.SWAGGER_2) 38 | .apiInfo(apiInfo()) 39 | .select() 40 | .apis(RequestHandlerSelectors.basePackage("com.zhonghuasheng.swagger.controller")) 41 | .paths(PathSelectors.any()) 42 | .build(); 43 | } 44 | } 45 | ``` 46 | * 使用swagger注解在controller上 47 | ```java 48 | @ApiOperation(value = "获取用户", notes = "根据url中的id获取用户信息") 49 | @RequestMapping(value = "/{id}", method = RequestMethod.GET) 50 | public User get(@PathVariable Long id) { 51 | return null; 52 | } 53 | ``` 54 | * 配置好swagger后访问http://localhost:8080/swagger-ui.html 55 | * Swagger提供的注解 56 | * @Api:修饰整个类,用于描述Controller类 57 | * @ApiOperation:描述类的方法或者说是一个接口 58 | * @ApiParam: 单个参数描述 59 | * @ApiModel: 用对象来接收参数 60 | * @ApiResponse:HTTP响应的一个描述 61 | * @ApiIgnore: swagger会忽略这个方法 62 | * @ApiError: 发生错误返回的信息 63 | * 其他注解自查 64 | 65 | ### 引用 66 | * 理解spring-boot-starter-parent的作用 https://www.jianshu.com/p/628acadbe3d8 67 | 68 | ### 常见问题 69 | * Mapped Statements collection does not contain value for 70 | 多数时mapper文件的问题,文件名/方法名/在properties中定义的扫描文件等 71 | * SpringBoot读取配置的两种方式 72 | * 通过ConfigurableApplicationContext对象来读取 - 代码读取 73 | * 通过配置@Value注解到bean上读取 -------------------------------------------------------------------------------- /java/spring/spring-boot/springboot-scheduled-task.md: -------------------------------------------------------------------------------- 1 | ### SpringBoot实现定时任务的4中方式 2 | * 使用Timer 3 | * 使用ScheduledExecutorService 4 | * 使用Spring Task 5 | * 简单的定时任务 6 | * 多线程执行 7 | * 执行时间的配置 8 | * cron表达式配置 9 | * 整合Quartz -------------------------------------------------------------------------------- /java/spring/spring-boot/springboot-ssl.md: -------------------------------------------------------------------------------- 1 | # SpringBoot中集成SSL 2 | 3 | > 测试时使用的是1.5.x的版本,2.x的版本会有一些类的写法不一样 4 | 5 | ## 目录 6 | * [生成SSL](#生成SSL) 7 | * [SpringBoot中配置SSL](#SpringBoot中配置SSL) 8 | * [参考文章](#参考文章) 9 | 10 | ### 生成SSL 11 | ```shell 12 | keytool -genkey -alias test -keyalg RSA -keystore /home/user/test.keystore 13 | ``` 14 | 15 | ### SpringBoot中配置SSL 16 | ```properties 17 | server.port=8443 18 | server.ssl.key-store=classpath:ssl/test.keystore #classpath是springboot中的resources所在的路径 19 | server.ssl.key-store-password=testpwd 20 | server.ssl.keyStoreType=JKS 21 | server.ssl.keyAlias=test 22 | ``` 23 | 24 | 启动项目,验证https 25 | 26 | ## 配置http自动跳转https 27 | 参考网上的写法会有个问题,http的post请求会被跳转为https的get请求,报错信息是Get方法不被支持。如下是我使用的解决方案: 28 | 1. 配置接收http请求和开通8080端口 29 | ```java 30 | @SpringBootApplication 31 | public class Application { 32 | 33 | public static void main(String[] args) { 34 | SpringApplication.run(Application.class, args); 35 | } 36 | 37 | @Bean 38 | public EmbeddedServletContainerFactory servletContainer() { 39 | TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory(); 40 | tomcat.addAdditionalTomcatConnectors(httpConnector()); 41 | 42 | return tomcat; 43 | } 44 | 45 | 46 | @Bean 47 | public Connector httpConnector() { 48 | Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol"); 49 | connector.setScheme("http"); 50 | connector.setPort(8080); 51 | connector.setSecure(false); 52 | 53 | return connector; 54 | } 55 | } 56 | ``` 57 | 2. 添加一个HttpsFilter用来将Http请求转换为Https请求 58 | ```java 59 | import org.springframework.beans.factory.annotation.Value; 60 | import org.springframework.stereotype.Component; 61 | 62 | import javax.servlet.*; 63 | import javax.servlet.annotation.WebFilter; 64 | import javax.servlet.http.HttpServletRequest; 65 | import javax.servlet.http.HttpServletResponse; 66 | import java.io.IOException; 67 | import java.net.URL; 68 | 69 | @Component 70 | @WebFilter(urlPatterns = "/*", filterName = "HttpsFilter") 71 | public class HttpsFilter implements Filter { 72 | 73 | private static final String HTTPS = "https"; 74 | 75 | @Override 76 | public void init(FilterConfig filterConfig) throws ServletException { 77 | } 78 | 79 | @Override 80 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 81 | if (request.getScheme().equals(HTTPS)) { 82 | chain.doFilter(request, response); 83 | } else { 84 | URL newUrl = null; 85 | HttpServletRequest httpRequest = (HttpServletRequest)request; 86 | HttpServletResponse httpResponse = (HttpServletResponse)response; 87 | String queryString = httpRequest.getQueryString()==null ? "":"?"+httpRequest.getQueryString(); 88 | httpResponse.setStatus(307); 89 | String requestUrl = httpRequest.getRequestURL().toString(); 90 | URL reqUrl = new URL(requestUrl+queryString); 91 | newUrl = new URL(HTTPS, reqUrl.getHost(), 8443, reqUrl.getFile()); 92 | // 进行重定向 93 | httpResponse.setHeader("Location", newUrl.toString()); 94 | httpResponse.setHeader("Connection", "close"); 95 | // 允许所有跨域请求 96 | httpResponse.addHeader("Access-Control-Allow-Origin", "*"); 97 | } 98 | } 99 | 100 | @Override 101 | public void destroy() { 102 | } 103 | } 104 | ``` 105 | 106 | ## 参考文章 107 | * [Springboot配置使用ssl,使用https](https://www.cnblogs.com/duanxz/p/9155509.html) 108 | * [Http 重定向到Https,post请求被强制转换为get请求的解决方案](https://blog.csdn.net/u011242657/article/details/80114074) -------------------------------------------------------------------------------- /java/spring/spring-boot/springboot-starter.md: -------------------------------------------------------------------------------- 1 | ### 常见问题 2 | 1. SpringBoot Starter解决了什么问题? 3 | 2. 你讲一下SpringBoot Starter的启动原理 4 | 3. 如何自定义一个SpringBoot Starter 5 | 4. 真实项目中SpringBoot Starter的使用案例 6 | 7 | #### SpringBoot Starter解决了什么问题? 8 | 1. SpringBoot的Starter解决了Spring MVC时代被xml配置文件搞的晕头转向的问题。举个例子,日常开发web项目,不适用SpringBoot时需要引入spring-web, spring-webmvc, spring-aop等等,而SpringBoot只需要引入spring-boot-starter-web。 9 | 2. 约定大于配置。在应用配置文件中加入相应的配置,配置都是组件约定好的。 10 | 3. SpringBoot Starter中可以声明很多通用的方法和bean。 11 | 12 | #### SpringBoot Starter的启动原理 13 | 1. SpringBoot默认扫描启动类所在的包下的主类和子类的所有组件,但并没有包括依赖包中的类。那么starter中的bean是如何被发现和加载的呢? 14 | 2. @SpringBootApplication这个复合组件中有个@EnableAutoConfiguration的注解,借助@Import的支持,能够收集和注册依赖包中相关bean的定义。通过一层一层翻源码发现,可以发现SpringFactoriesLoader.loadFactoryNames方法调用了loadSpringFactories,从所有jar包中读取META-INF/spring.factories文件信息。spring.factories中配置的是被@Configuration注解修饰的配置类。(SPI技术)这样启动之后starter中的bean也被注入到了容器中。 15 | 16 | #### 自定义SpringBoot Starter的步骤 17 | 1. 新建一个项目,命名格式采用xxx-spring-boot-starter。spring规定非官方的starter以xxx-spring-boot-starter,官方的以spring-boot-starter-xxx命名。 18 | 2. 添加starter中需要的依赖 19 | 3. 添加必要的配置类,可以写一些通用的模板类,然后在resource/下建META-INF/spring.factories文件,把配置类配到里面 20 | 4. 执行mvn clean install把jar包打到本地maven仓库,然后就可以使用了 21 | 22 | #### SpringBoot Starter使用案例 23 | 24 | 25 | ### 参考引用 26 | * https://www.cnblogs.com/hello-shf/p/10864977.html -------------------------------------------------------------------------------- /java/spring/spring-boot/thymeleaf.md: -------------------------------------------------------------------------------- 1 | * th:href传递多个参数 https://www.cnblogs.com/onmyway20xx/p/8856804.html 2 | * thymeleaf教程 https://www.jianshu.com/p/908b48b10702 -------------------------------------------------------------------------------- /java/spring/spring-cloud/spring-cloud-eureka.md: -------------------------------------------------------------------------------- 1 | ## 学习计划 2 | * Eureka的自我保护机制 3 | * Eureka源码--服务的注册、服务续约、服务发现、服务下线、服务剔除、定时任务以及自定义注册中心的思路 https://www.cnblogs.com/yangxiaohui227/p/12604172.html 4 | 微服务注册后,在注册中心的注册表结构是一个map: ConcurrentHashMap>> registry,假如一个order服务部署了三台机器,那么Map的第一个key为服务名称,第二个map的key是实例编号(instance-id), InstanceInfo该对象封装了服务的主要信息,例如ip 端口 服务名称 服务的编号等 5 | 6 | ## Eureka的自我保护机制 7 | 总结:在网络正常的情况下,如果EurekaServer在一定时间(默认90s)内没有收到某个服务实例的心跳,EurekaServer会注销该实例。OK,这个前提条件是网络正常,那要是网络不正常呢?出现网络不正常的情况有两种,EurekaServer的网络不正常或者某些EurekaClient的网络不正常,先说说EurekaServer网络不正常的情况,如果EurekaServer网络不正常,那么它应该收不到很多Client的心跳;如果说是某些Client的网络不正常,那么它应该可以收到其他的Client的心跳,因此就需要一个阀值来评估要不要进入自我保护机制。Eureka规定在15min内没有收到心跳的服务的实例超过了85%就认为需要进入自我保护。我们先说说进入自我保护之后会发生什么。EurekaServer进入自我保护后(`只进不出【只注册不发现】,沉默是金【不同步】`),可以接收新的服务注册和查询,也不把那些没有收到心跳的服务移除,在网络稳定之前EurekaServer的这份服务信息是不会同步到其他服务的,直到网络稳定后才同步。在EurekaServer进入自我保护期内,如果原本正常的服务下线,会导致服务的调用失败,这个在API的设计上需要注意,要引入熔断和快速失败的机制。我们再说说是Client这边的网络问题,超过85%的服务在15min内没有心跳,我们基本认为这个系统挂掉了,需要立马排查原因重新上线。最后我们再来说说自我保护啥时候能被接触 8 | 9 | 自我保护模式被解除的条件是:在 1 分钟后,Renews (last min) < Renews threshold 10 | 这两个参数的意思: 11 | * Renews threshold:Eureka Server 期望每分钟收到客户端实例续约的总数。 12 | * Renews (last min):Eureka Server 最后 1 分钟收到客户端实例续约的总数。 13 | 14 | 进入自我保护的标志: 15 | 如果说 Eureka Server 的首页看到一下这段提示,则说明Eureka 进入了保护模式。 16 | EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE. 17 | 18 | ### 自我保护背景 19 | 首先对Eureka注册中心需要了解的是Eureka各个节点都是平等的,没有ZK中角色的概念, 即使N-1个节点挂掉也不会影响其他节点的正常运行。 20 | 21 | 默认情况下,如果Eureka Server在一定时间内(默认90秒)没有接收到某个微服务实例的心跳,Eureka Server将会移除该实例。但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,而微服务本身是正常运行的,此时不应该移除这个微服务,所以引入了自我保护机制。 22 | 23 | ### 自我保护机制 24 | 自我保护模式正是一种`针对网络异常波动的安全保护措施`,使用自我保护模式能使Eureka集群更加的健壮、稳定的运行。 25 | 26 | > Eureka Server怎么知道是网络异常呢? 27 | 28 | 自我保护机制的工作机制是如果在15分钟内超过85%的客户端节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障, 29 | 30 | Eureka Server自动进入自我保护机制,此时会出现以下几种情况: 31 | 1. Eureka Server不再从注册列表中移除因为长时间没收到心跳而应该过期的服务。 32 | 2. Eureka Server仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上,保证当前节点依然可用。 33 | 3. 当网络稳定时,当前Eureka Server新的注册信息会被同步到其它节点中。 34 | 35 | 因此Eureka Server可以很好的应对因网络故障导致部分节点失联的情况,而不会像ZK那样如果有一半不可用的情况会导致整个集群不可用而变成瘫痪。 36 | 37 | 自我保护开关 38 | 39 | Eureka自我保护机制,通过配置eureka.server.enable-self-preservation来true打开/false禁用自我保护机制,默认打开状态,建议生产环境打开此配置。 40 | 开发环境配置 41 | 42 | 开发环境中如果要实现服务失效能自动移除,只需要修改以下配置。 43 | -------------------------------------------------------------------------------- /java/spring/spring-cloud/spring-cloud-gateway.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | * [SpringCloud Gateway为什么会出现](#简介) 3 | * [能用来干什么](#功能特性) 4 | 5 | ## 简介 6 | SpringCloud Gateway是基于spring-webflux,采用netty+reactor(Spring WebFlux 是一个异步非阻塞式的 Web 框架,它能够充分利用多核 CPU 的硬件资源去处理大量的并发请求,WebFlux 内部使用的是响应式编程(Reactive Programming),以 Reactor 库为基础, 基于异步和事件驱动,可以让我们在不扩充硬件资源的前提下,提升系统的吞吐量和伸缩性。Spring MVC 构建于 Servlet API 之上,使用的是同步阻塞式 I/O 模型,什么是同步阻塞式 I/O 模型呢?就是说,每一个请求对应一个线程去处理。) 7 | 8 | ## 功能特性 9 | 1. 路由:能够在任意请求属性上匹配路由 10 | 2. 过滤: 11 | 3. 集成Hystrix熔断器 12 | 4. 集成Spring Cloud DiscoveryClient,能够从注册中心获取服务注册列表,实现自动路由 13 | 5. 集成了Ribbon,实现了负载均衡 14 | 6. 能够限制请求速率 15 | 16 | Route(路由):路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由,目标URI会被访问。 17 | Predicate(断言):这是一个java 8的Predicate,可以使用它来匹配来自HTTP请求的任何内容,可以理解为当满足这种条件后才会被转发 18 | Filter(过滤器): 19 | -------------------------------------------------------------------------------- /java/spring/spring-cloud/spring-cloud-hystrix.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | * [要解决什么问题](#问题产生) 3 | * [实现原理和基本特性](#实现原理和基本特性) 4 | * [SpringCloud Hystrix是如何实现隔离、熔断、降级的?]() 5 | * [熔断配置](#熔断配置) 6 | 7 | ## 问题产生 8 | 问题产生: 雪崩效应是一种因服务提供者的不可用导致服务调用者的不可用,并将不可用逐渐放大的过程 9 | 10 | Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统中,服务间的调用不可避免会失败,比如超时、异常等。Hystrix能保证在一个依赖出问题的情况下,不会导致整体服务的失败,避免级联故障。Hystrix 熔断机制是如何保证的?当失败的情况达到预定的阈值(5秒失败20次)或达到一定的失败率,会打开断路器,拒绝所有请求,直到服务恢复正常为止。 11 | 12 | ## 实现原理和基本特性 13 | Hystrix是Netflix开源的一个限流熔断的项目,主要有以下功能: 14 | 1. 隔离(`线程池隔离`和`信号量隔离`): 限制调用分布式服务资源的使用,通过线程池隔离或者信号量隔离来保证当某一个服务请求响应异常的时候,不会影响其他服务。使用线程池隔离或信号量隔离的目的是将各依赖服务的访问交由独立的线程池来处理,会为每个依赖服务创建一个线程池,当自己的资源用完了,直接返回失败而不是占用别人的资源。 15 | ``` 16 | > 线程池方式: 17 | 优点: 18 | 1. 使用线程池隔离可以完全隔离各个请求 19 | 2. 线程可以被回收用来接收新的请求,并且不用新建线程,可以加快请求的速度 20 | 3. 独立的线程池提高了并发性 21 | 缺点: 22 | 线程池隔离增加了系统资源如CPU的开销,每隔命令涉及到系统调度和上下文切换 23 | > 信号量方式: 24 | 使用一个原子计数器来记录当前有多少线程在运行,当请求进来时先判断计数器的数值,若超过设置的最大线程池个数则拒绝该请求;若不超过则通行,计数器+1,请求返回成功后计数器-1。信号量模式下任务由当前线程直接处理,不涉及到线程切换,自然也就没有超时控制。TryableSemaphoreActual类中使用AtomicInteger(Unsafe.cas来保证)来计数 25 | ``` 26 | 27 | ![](../image/hystrix.png) 28 | 2. 熔断:熔断机制是应对雪崩效应的一种微服务链路保护机制,当微服务链路的某个服务出错不可用或者响应时间太长,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。当一定时间内,异常请求比例(请求超时、网络故障、服务异常等)达到阀值时,启动熔断器,熔断器一旦启动,则会停止调用具体服务逻辑,通过fallback快速返回托底数据,保证服务链的完整。 29 | 熔断有自动恢复机制,如:当熔断器启动后,每隔5秒,尝试将新的请求发送给服务提供者,如果服务可正常执行并返回结果,则熔断器半开,允许定量服务请求,如果调用都成功,则认为恢复了,关闭熔断器;如果仍旧调用失败,则继续返回托底数据,熔断器持续开启状态。熔断机制使用的是@HystrixCommand注解。 30 | ``` 31 | 熔断器是位于线程池之前的组件,用户请求某一服务之后,Hystrix会先经过熔断器,此时如果熔断器是打开,则说明已经熔断,直接进行降级处理;如果熔断器是关闭的状态,则会继续将请求发到对应的线程池。 32 | 熔断器状态: 33 | 1. closed: 熔断器关闭状态 - 所有请求返回成功 34 | 2. open: 熔断器打开状态 - 调用次数累计达到阈值或者比例,熔断器打开,服务直接返回错误 35 | 3. half open: 熔断器半开状态 - 默认时间过后,进入半熔断状态,允许定量服务请求,如果调用都成功,则认为恢复了,关闭熔断器;否则打开熔断器 36 | ``` 37 | 3. 降级:服务降级,将服务的级别降低,原本的服务时返回一个业务的正确的结果,现在服务出现了问题,但是又得有个返回值,因此服务端会自己准备一个fallBack的回调,返回一个缺省值,这样总比直接挂掉要强。使用时在方法的注解@HystrixCommand(fallbackMethod=xxxMethod) 38 | ``` 39 | 可能出现服务降级的情况: 40 | 1. 程序运行异常 41 | 2. 服务超时 42 | 3. 服务熔断触发服务降级 43 | 4. 服务隔离中线程池或信号量跑满也会导致服务降级 44 | ``` 45 | 4. 请求缓存:高并发场景下,通过请求缓存来减少服务器的压力。SpringClound Hystrix中有两种方式来实现,一种是重写HystrixCommand下的getCacheKey()方法,另外一种是使用注解。注解有三个 46 | * @CacheResult: 注解在方法上,表示该方法开启缓存,默认情况下方法的所有参数都作为缓存key 47 | * @CacheKey:注解在方法上,指定缓存的key 48 | * @CacheRemove:注解在方法上,该注解用来让请求的缓存失效,失效的缓存根据定义的key决定 49 | 50 | ## 熔断配置 51 | * 全局配置 52 | ``` 53 | circuitBreaker.sleepWindowInMilliseconds:监控时间 54 | circuitBreaker.requestVolumeThreshold:失败次数 55 | circuitBreaker.errorThresholdPercentage:失败率 56 | ``` 57 | * 方法级别的配置 58 | ```java 59 | 60 | @RestController 61 | public class HiController { 62 | 63 | @GetMapping("/hystrix") 64 | @HystrixCommand(fallbackMethod = "fallbackMethod", commandProperties = { 65 | // 设置超时时间,默认1秒 66 | @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000"), 67 | // 监控时间,默认5秒 68 | @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000"), 69 | // 失败次数,默认20次 70 | @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20"), 71 | // 失败了,默认50% 72 | @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50") 73 | }) 74 | public String sayHi() { 75 | /* // 1. 容错,此处逻辑抛出异常,会走熔断方法 76 | int i = 3 / 0;*/ 77 | // 2. 响应超时熔断 78 | try { 79 | Thread.sleep(2000); 80 | } catch (InterruptedException e) { 81 | 82 | } 83 | return "hi"; 84 | } 85 | 86 | /** 87 | * 熔断方法 88 | * @return String 89 | */ 90 | private String fallbackMethod() { 91 | return "熔断了"; 92 | } 93 | } 94 | ``` 95 | -------------------------------------------------------------------------------- /java/spring/spring-cloud/spring-cloud-request-process.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | 3 | ## SpringCloud调用接口过程 4 | Feign -> Hystrix -> Ribbon -> Http Client(apache http components OR Okhttp) 5 | 1. `接口请求调用`:当调用被@FeignClient注解修饰的接口时,在框架内部,将请求转化成Feign的请求实例`feign.Request`,交由Feign框架处理 6 | 2. `Feign`:转化请求,Feign是一个http请求调用的轻量级框架,可以以Java接口注解的方式调用Http请求,封装了Http调用流程 7 | 3. `Hystrix`:熔断处理机制,Feign的调用关系,会被Hystrix代理拦截,对每一个Feign调用请求,Hystrix都会将其包装成HystrixCommand,参与Hystrix的流控和熔断规则。如果请求判断需要熔断,则Hystrix直接熔断,抛出异常或者使用FallbackFactory返回熔断Fallback结果;如果通过,则将调用请求传递给Ribbon组件 8 | 4. `Ribbon`:服务地址选择,当请求传递到Ribbon之后,Ribbon会根据自身维护的服务列表,根据服务的服务质量,如平均响应时间、Load等,结合特定的规则,从列表中挑选合适的服务实例,选择好机器之后,然后将机器实例的信息请求传递给HttpClient客户端,HttpClient客户端来执行真正的Http接口调用 9 | 5. `Http Client`:Http客户端,真正执行Http调用根据上层Ribbon传递过来的请求,已经指定了服务地址,则HttpClient开始执行真正的Http请求 -------------------------------------------------------------------------------- /java/spring/spring-cloud/spring-cloud.md: -------------------------------------------------------------------------------- 1 | ### 学习资源 2 | * 比较全和详细 https://blog.didispace.com/spring-cloud-learning/ 3 | ### 微服务本身的复杂度带来的问题 4 | * 分散在各个服务器上的日志如何处理?日志在format的时候一定要有规则,最好的方式是异常都要有对应的errorCode,方便后期过滤 5 | * 如果业务出现了错误和异常,如何定位和处理? 6 | * 如何跟踪业务的处理顺序和结果? 7 | * 微服务时代 运维监控是难点 8 | 9 | * [Spring Cloud架构的各个组件的原理分析](http://note.youdao.com/noteshare?id=fb41aeb44300dc2f82b230b16f4b51f9&sub=393903C6584B4367A5038703D0D212B2) 10 | ``` 11 | 文中讲了Doubbo, Spring, SpringBoot, SpringCloud的发展,及SpringBoot/Cloud产生的原因,SpringCloud各个组件 12 | ``` 13 | * [SpringCloud请求处理流程](spring-cloud-request-process.md) 14 | * [SpringCloud注册中心 - Eureka](spring-cloud-eureka.md) 15 | * [SpringCloud熔断器 - Hystrix](spring-cloud-hystrix.md) 16 | 17 | ### 笔记 18 | * SpringCloud是需要SpringBoot做基础的,因此在选择好SpringCloud的版本之后,要查看该版本依赖的是哪个SpringBoot版本,不能随便选择SpringBoot的版本,否则容易遇到意想不到的错误 19 | * SpringCloud Feign中,如果A服务通过Feign调用B服务,需要传递多个参数时,需要将参数组装成一个DTO来传递,否则会报参数找不到的错误 20 | 21 | ### 引用 22 | * SpringCloud系列 https://www.cnblogs.com/h--d/tag/SpringCloud/ -------------------------------------------------------------------------------- /java/spring/spring.md: -------------------------------------------------------------------------------- 1 | `目录` 2 | ### Spring 3 | * [为什么要有Spring](http://note.youdao.com/noteshare?id=a61d1330cec20afe21d369f0526756a2&sub=wcp1556526473148138) 4 | * [为什么要有Spring AOP](http://note.youdao.com/noteshare?id=21f2b64abb67a24ad45baca5456648a5&sub=wcp1556587241813493) 5 | * [关于Spring IOC和AOP的理解](http://note.youdao.com/noteshare?id=d0aa79a9af96f02aad6e25c1d3f192b3&sub=wcp1582173498187944) 6 | * [Spring历史版本变迁和如今的生态帝国](http://note.youdao.com/noteshare?id=80509c0296c54ccb86c1848b95c9c530&sub=wcp15565934311825) 7 | * [手写一个Spring IOC的简单实现](https://github.com/zhonghuasheng/JAVA/tree/master/basic/src/main/java/com/zhonghuasheng/ioc) 8 | * [什么是Spring]() 9 | * [Spring 依赖注入](http://note.youdao.com/noteshare?id=91ac0b573c1898e8fa3b47ebfdfffbf1&sub=wcp1582257498880783) 10 | * [Spring Java配置](http://note.youdao.com/noteshare?id=4808a867c7b646f7f4d41a1bbe2f79fa&sub=wcp1582272695540930) 11 | * [Spring Bean Scope](http://note.youdao.com/noteshare?id=f0c541d742d9548342dbca9e04607758&sub=wcp1582292894805554) 12 | * [Spring AOP与AspectJ的对比](http://note.youdao.com/noteshare?id=b75baf23ad8073d69527838449b259c1&sub=wcp1582290319293279) 13 | * [Spring EL和资源调用](http://note.youdao.com/noteshare?id=35b5a39e2859023b508d417f34925398&sub=wcp1582372537958305) 14 | * [Spring Profile](http://note.youdao.com/noteshare?id=3828c670a4a3f8ee15030da5aa33b601&sub=wcp1582426672342855) 15 | * [Spring Event](http://note.youdao.com/noteshare?id=cfcfc768052b2ad41af7d58a380d0428&sub=wcp1582441131568780) 16 | * [Spring Aware](http://note.youdao.com/noteshare?id=b4846212af36a32fa327833c93b3fd9b&sub=wcp1582507656479831) 17 | * [Spring多线程](http://note.youdao.com/noteshare?id=b1dbd6b066db81f7e4d7436aac1e7af7&sub=wcp1582507689758259) 18 | * [Spring Schedule](http://note.youdao.com/noteshare?id=2f6e090483fdadb277460faee41bd213&sub=wcp1582507714943294) 19 | * [Spring Condition](http://note.youdao.com/noteshare?id=cd966fbce76b5b57ee1afee0a2e7f388&sub=wcp1582507730857453) 20 | * [Spring组合注解](http://note.youdao.com/noteshare?id=6f847f37be5b0d7b42132ea9f069c7d5&sub=wcp1582507747315363) 21 | * [Spring @Enable*注解](http://note.youdao.com/noteshare?id=879cd184830f9501821ca6073c4b71a9&sub=wcp1582507762687224) 22 | * [Spring 常用注解总结](spring-annotation.md) 23 | 24 | ### SpringMVC 25 | * [SpringMVC初始化无web.xml项目](http://note.youdao.com/noteshare?id=205b607e70b9b0f0b9e131d0cce812fe&sub=wcp1582775530722662) 26 | * [SpringMVC常用注解](http://note.youdao.com/noteshare?id=2ba40b0807fd025783c50dd0295426b0&sub=wcp1582785745286940) 27 | * [SpringMVC配置返回JSON数据格式](http://note.youdao.com/noteshare?id=56597a6ac75b39ee8676090b039ac9da&sub=wcp158285925711064) 28 | * [SpringMVC基本配置-静态资源映射](http://note.youdao.com/noteshare?id=353a5add7736bb43d2d8385d9da9b316&sub=wcp1582804386017933) 29 | * [SpringMVC基本配置-过滤器](http://note.youdao.com/noteshare?id=705d1389728fc7a84ae75c56a56632aa&sub=wcp1582895863705318) 30 | * [SpringMVC基本配置-拦截器](http://note.youdao.com/noteshare?id=43f57fe16f133916f14fd1285ffe1d8d&sub=wcp1582868210157413) 31 | * [SpringMVC基本配置-监听器](http://note.youdao.com/noteshare?id=705d1389728fc7a84ae75c56a56632aa&sub=wcp1582895863705318) 32 | * [SpringMVC基础配置-@ControllerAdvice注解](http://note.youdao.com/noteshare?id=86e8bbe0fc34129ac23ea0a81e114d94&sub=wcp1582872248611915) 33 | * [SpringMVC基础配置-快捷的ViewController](http://note.youdao.com/noteshare?id=2f1919491b52ee9d16f41ca5a4f608ad&sub=1B8ED2525FE44788BC9219B7B2F0A060) 34 | * [SpringMVC基础配置-路径匹配参数配置](http://note.youdao.com/noteshare?id=452d39e440514114c27624af34460beb&sub=wcp1582893962706623) 35 | * [SpringMVC文件上传](http://note.youdao.com/noteshare?id=1336c8afd5a0feecbd4fce53e3c7bdf0&sub=wcp1582955118268508) 36 | * [SpringMVC JSON数据与对象T的转换](http://note.youdao.com/noteshare?id=d0ae808a1bdc1c0b445f3ecee2ab141d&sub=wcp1582966629731695) 37 | * [SpringMVC测试](http://note.youdao.com/noteshare?id=1691d99d1263f3d5ff241db2da0a54cc&sub=wcp1582972184053369) 38 | 39 | ### SpringBoot 40 | > SpringBoot基础知识系列 41 | * [SpringBoot历史](spring-boot/0-springboot-history.md) 42 | * [SpringBoot基础](spring-boot/1-springboot-basic.md) 43 | * [SpringBoot运行原理](http://note.youdao.com/noteshare?id=2c7f983f4eff820ba695f1bf47a85925&sub=wcp1583375011581975) 44 | * [SpringBoot-HelloWorld]() 45 | * [SpringBoot AOP](http://note.youdao.com/noteshare?id=167ce48253b948332badd22fd35e14ce&sub=9A67CA36E2BA43A9BEEEC13BA3B5FA36) 46 | * SpringBoot页面模板 47 | * [SpringBoot Thymeleaf的使用] 48 | * [SpringBoot Data]() 49 | * [Spring Data JDBC]() 50 | * [Spring Data JDBC Extension]() 51 | * [Spring Data JAP]() 52 | * [Spring Data LDAP]() 53 | * [Spring Data MongoDB]() 54 | * [Spring Data Redis]() 55 | * [Spring Data REST]() 56 | * [Spring Data Elasticsearch]() 57 | * [Spring Data Spark]() 58 | * [Spring for Apache Hadoop]() 59 | * [SpringBoot MyBatis](https://github.com/zhonghuasheng/JAVA/tree/master/springboot) 60 | * [SpringBoot Security]() https://www.jianshu.com/p/6a7dcef02bd5 61 | * [SpringBoot Shiro] 62 | * [SpringBoot Session]() 63 | * [SpringBoot Log4j2](https://github.com/zhonghuasheng/JAVA/tree/master/springboot) 64 | * [SpringBoot Swagger](spring-boot/springboot-note.md#swagger) 65 | * [SpringBoot实现定时任务的4中方式](spring-boot/springboot-scheduled-task.md) 66 | * [SpringBoot统一结果处理](https://github.com/zhonghuasheng/Spring-Boot/wiki/SpringBoot%E7%BB%9F%E4%B8%80%E5%A4%84%E7%90%86%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9C) 67 | * [SpringBoot统一异常处理](https://github.com/zhonghuasheng/Spring-Boot/wiki/SpringBoot%E7%BB%9F%E4%B8%80%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86) 68 | * [SpringBoot统计在线人数](https://github.com/zhonghuasheng/Tutorial/wiki/SpringBoot%E7%BB%9F%E8%AE%A1%E5%9C%A8%E7%BA%BF%E4%BA%BA%E6%95%B0) 69 | * [SpringBoot + Redis + 自定义注解 + 拦截器 实现接口幂等性校验](https://github.com/zhonghuasheng/Spring-Boot/blob/master/springbootidempotence/README.md) 70 | * [SpringBoot集成SSL,实现HTTP到HTTPS的自动跳转](/java/spring-boot/springboot-ssl.md) 71 | * [SpringBoot中使用Redis做页面缓存](https://github.com/zhonghuasheng/JAVA/commit/340d764e21902797630ea6a42136ec1fc909023b) 72 | * [SpringBoot + Redis Lua脚本实现分布式锁 + 解决电商超卖问题](https://github.com/zhonghuasheng/JAVA/blob/master/springboot/springboot-redis-lock/src/main/java/com/zhonghuasheng/redis/config/RedisRepository.java) 73 | * [SpringBoot启动后按顺序自动执行](https://github.com/zhonghuasheng/JAVA/tree/master/springboot/springboot-basic/src/main/java/com/zhonghuasheng/basic/runner) 74 | * [SpringBoot Starter自定义实现](https://github.com/zhonghuasheng/JAVA/tree/master/springboot/demo-spring-boot-starter) 75 | * [SpringBoot集成Log4j2实现日志的分类输出](https://github.com/zhonghuasheng/JAVA/tree/master/springboot/springboot-log4j2) 76 | 77 | ### SpringCloud 78 | > 微服务基础知识 79 | * [服务注册与发现](spring-cloud/micro-service-register-discovery.md) 80 | > SpringCloud微服务系列 81 | * [Spring Cloud注册中心 - Eureka](spring-cloud/spring-cloud-eureka.md) 82 | * [Spring Cloud熔断器 - Hystrix](spring-cloud/spring-cloud-hystrix.md) 83 | 84 | -------------------------------------------------------------------------------- /plugins/activemq.md: -------------------------------------------------------------------------------- 1 | ### Start in Linux 2 | * Download http://activemq.apache.org/download-archives.html 3 | * Start `cd [activemq_install_dir]/bin` `./activemq start` 4 | 5 | ### Set password 6 | * ActiveMQ使用的是jetty服务器,设置密码时需要先将authenticate设置为true。在 {apache-activemq}/conf/jetty.xml文件中 7 | 8 | ```xml 9 | 10 |         11 |         12 |         13 | 14 | ``` 15 | * 修改登陆的用户名和密码保护,在{apache-activemq}/conf/jetty-realm.properties文件中 16 | ```properties 17 | # Defines users that can access the web (console, demo, etc.) 18 | # username: password [,rolename ...] 19 | admin: admin, admin 20 | ``` -------------------------------------------------------------------------------- /plugins/database/SQL优化.md: -------------------------------------------------------------------------------- 1 | * EXPLAIN不会告诉你关于触发器、存储过程的信息或用户自定义函数对查询的影响情况 2 | * EXPLAIN不考虑各种Cache 3 | * EXPLAIN不能显示MySQL在执行查询时所作的优化工作 4 | * 部分统计信息是估算的,并非精确值 5 | * EXPALIN只能解释SELECT操作,其他操作要重写为SELECT后查看执行计划。 -------------------------------------------------------------------------------- /plugins/database/database.md: -------------------------------------------------------------------------------- 1 | ### 学习计划 2 | 3 | * [数据库主键怎么选择](mysql/数据库主键怎么选择.md) 4 | * [数据库中的索引](mysql/mysql索引.md) 5 | * [数据库性能优化](#数据库性能优化) 6 | 7 | #### 影响数据库性能的因素 8 | 9 | * 磁盘数据库,内存数据库,分布式内存数据库 10 | * Apache Ignite 11 | 12 | * 事务的特性 13 | * 原子性(Atomicity):(同生共死)一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说不可能只执行其中的一部分操作。(银行转账的例子)数据库是如何保证原子性的呢? 14 | * 一致性(Consistency):每个事务都必须保留数据库的完整性约束(已声明的一致性规则)。事务将数据库从一种正确的状态装换到另外一种正确的状态。这个是最难理解的,什么是正确的状态? 15 | * 隔离性(Isolation):隔离性要求一个事务对数据库中数据的修改,在未提交完成前对其它事务是不可见的。四种事务隔离级别: 16 | * 未提交读:事务可以读取未提交的数据,称之为脏读(Read Uncommited) 17 | * 已提交读:大多数数据库(SQL Server/Postgresql)默认隔离级别,mysql不是这个。一个事务开始时只能看到已提交事务做的修改,或者说一个事务在开始提交到结束是不可见的(Read Commited,也叫不可重复读) 18 | * 可重复读:在同一个事务内,多次读取的结果是一致的,什么意思呢,就相当于在这个你的这个事务在开启那刻切出来了一个数据库的镜像,不管在这个事务执行中这个数据库发生了什么,或者有数据的修改,你都感知不到。举个例子,你在事务A中多次查询t表中的结果,然后在事务B中插入了一条新数据到t中,再次在事务A中查询,返回的结果和最开始得到的结果是一样的(Repeatable Read,mysql默认的级别) 19 | * 可串行化(Serializable):最高的隔离级别,在读取的每一行上都加锁,会造成大量的锁争用和超时,很少用,除非严格的数据一致性,或者并发很少的情况下使用。 20 | * 隔离级别由低到高,并发性由高到低。InnoDB的默认隔离级别是可重复读,而不是已提交多 21 | * 持久性(Durability):一旦事务提交,则其所做的修改就会永久保存到数据库中,此时即使系统崩溃,已提交的修改数据也不会丢失 22 | * 事务的ACID不是一个平级的关系 23 | * 只有满足一致性,事务的执行结果才是正确的;在无并发的情况下,事务串行执行,隔离性一定能够满足。此时只要能满足原子性,就一定能满足一致性。在并发的情况下,多个事务并发执行,事务不仅要满足原子性,还要满足隔离性,这样才能保证一致性;事务满足持久化是为了能应对数据库崩溃的情况。 24 | > 事务一致性详解 25 | 1. 首先说下事务的产生原因,其实是为了当应用程序访问数据库的时候,事务能够简化我们的编程模型,不需要我们去考虑各种各样的潜在错误和并发问题.可以想一下当我们使用事务时,要么提交,要么回滚,我们不会去考虑网络异常了,服务器宕机了,同时更改一个数据怎么办对吧?因此事务本质上是为了应用层服务的.而不是伴随着数据库系统天生就有的. 26 | 2. ACID里的AID都是数据库的特征,也就是依赖数据库的具体实现.而唯独这个C,实际上它依赖于应用层,也就是依赖于开发者.这里的一致性是指系统从一个正确的状态,迁移到另一个正确的状态.什么叫正确的状态呢?就是当前的状态满足预定的约束就叫做正确的状态.而事务具备ACID里C的特性是说通过事务的AID来保证我们的一致性. 27 | 3. 这里我们举个大家都在说的财务系统的例子. 28 | * A要向B支付100元,而A的账户中只有90元,并且我们给定账户余额这一列的约束是,不能小于0.那么很明显这条事务执行会失败,因为90-100=-10,小于我们给定的约束了.这个例子里,支付之前我们数据库里的数据都是符合约束的,但是如果事务执行成功了,我们的数据库数据就破坏约束了,因此事务不能成功,这里我们说事务提供了一致性的保证. 29 | * 然后我们再看个例子A要向B支付100元,而A的账户中只有90元,我们的账户余额列没有任何约束.但是我们业务上不允许账户余额小于0.因此支付完成后我们会检查A的账户余额,发现余额小于0了,于是我们进行了事务的回滚.这个例子里,如果事务执行成功,虽然没有破坏数据库的约束,但是破坏了我们应用层的约束.而事务的回滚保证了我们的约束,因此也可以说事务提供了一致性保证(ps:事实上,是我们应用层利用事务回滚保证了我们的约束不被破坏). 30 | * 最后我们再看个例子A要向B支付100元,而A的账户中只有90元,我们的账户余额列没有任何约束.然后支付成功了.这里,如果按照很多人的理解,事务不是保证一致性么?直观上账户余额为什么能为负呢.但这里事务执行前和执行后,我们的系统没有任何的约束被破坏.一直都是保持正确的状态.所以,综上.你可以理解一致性就是:应用系统从一个正确的状态到另一个正确的状态.而ACID就是说事务能够通过AID来保证这个C的过程.C是目的,AID都是手段. 31 | 32 | * 什么影响了数据库性能? 33 | 1. 服务器硬件:CPU/网络/磁盘 34 | * CPU 35 | * 如何选择CPU?计算密集型/存储密集型(亚马逊上选服务器的时候选),CPU的核数,频率。MySQL的版本,老版本对多核支持不太好。32位还是64位的CPU,现在默认的是64位。64位CPU上运行32位架构的操作系统。 36 | * 对于并发比较高的场景CPU的数量比频率重要;对于CPU密集型场景和复杂SQL则频率越高越好。两者都是的话,CPU核数多且频率高越贵哦 37 | * 内存:选择服务器所支持最高的频率 38 | * MyLSam: 索引缓存到内存中,数据通过操作系统来缓存 39 | * InnoDB: 同时在缓存中存储索引和数据,提高效率 40 | * 磁盘:容量/传输速度/访问时间/主轴转速(7000/1.5W)/物理尺寸 41 | * 传统磁盘:便宜,效率低,读写慢。RAID0可以把一些小的磁盘构建磁盘阵列,但是数据可能会丢失;RAID1可以对磁盘做镜像,对数据安全性高,磁盘利用率低;RAID5通过分布式奇偶校验块把数据分散到多个磁盘上,如果任何一个盘数据丢失,都可以从奇偶校验块重建,如果都丢失是无法恢复的;RAID10分片镜像 42 | * SSD:相比机械硬盘有更好的随机读写性能;固态存储吞吐量大,更好支持并发;使用SATA接口(6G/S) 43 | * PCI-E SSD需要特殊的接口和独立的驱动,闪存技术 44 | * SAN: Storage Area Network 通过光纤接入服务器。适合做数据库备份 45 | * NAS:Network-Attached Storage 使用网络连接,使用NFS或SMB协议来访问 46 | * 网络接口性能对数据库的影响:延迟、带宽(也叫吞吐量)、网络的质量(抖动、丢包);根据需求使用万兆交换机;尽可能多网络隔离,不暴露数据库在外网上 47 | 2. 操作系统 48 | * windows对schema大小写不敏感,linux对大小写敏感。建议数据库/表都小写,通过配置参数来强制要求小写也可以。 49 | * centos优化 50 | * 内核相关参数 /etc/sysctl.conf 51 | * net.core.somaxconn=65535 每个端口监听的个数 52 | * net.core.netdev_max_backlog=65535 53 | * net.ipv4.tcp_max_syn_backlog=65535 54 | * net.ipv4.tcp_fin_timeout=10 TCP等待时间加速回收速度 net.ipv4.tcp_tw_reuse=1 net.ipv4.tcp_tw_recycle=1 55 | * net.ipv4.tcp_keepalive_time=120秒 56 | * 增加资源限制 57 | * /etc/security/limit.conf 打开文件数的限制,添加到limit.conf文件的末尾就可以了 58 | * soft nofile 65535 59 | * hard nofile 65535 60 | * 磁盘调度策略 61 | * 文件系统对性能的影响 62 | * Linux文件系统有EXT3/EXT4/XFS都有日志功能,传说XFS性能高 63 | * Windows文件系统有FAT/NTFS 64 | 3. 数据库存储引擎 65 | * MyISAM:不支持事务,表级锁 66 | * InoDB: 事务存储引擎,完美支持行级锁,事务ACID特性 67 | 4. 数据库参数配置 68 | 5. 数据库表结构设计和SQL语句对性能影响 69 | * 慢查询 70 | 71 | #### 数据库性能优化 72 | 1. 数据表的设计 73 | 2. SQL语句的设计 74 | 3. 数据库设计 75 | 76 | ### 学习笔记 77 | * [分库分表 如何做到永不迁移数据和避免热点](https://github.com/zhonghuasheng/Tutorial/wiki/%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8-%E5%A6%82%E4%BD%95%E5%81%9A%E5%88%B0%E6%B0%B8%E4%B8%8D%E8%BF%81%E7%A7%BB%E6%95%B0%E6%8D%AE%E5%92%8C%E9%81%BF%E5%85%8D%E7%83%AD%E7%82%B9) 78 | 79 | ### 百问 80 | 1. Select count(1) 和count(col),count(*)区别 81 | 2. 千万级别的数据,如何更改表字段长度? 82 | 今天遇到一个场景,有一个表创建时间比较长了,现在有3亿的数据,其中有个字段A是varchar(255),现在呢有个新需求,要求A中能存500个长度的数据。直接改A表字段,肯定不行,预计这个表修改需要执行1个多小时。我试了下,弄张新表B,然后修改A字段长度,然后同步A的数据到B,估计也得需要1个小时。你不可能在线上直接改啊,采用的方案是另起一张新表一个id字段指向原表的id,然后加个A字段 83 | -------------------------------------------------------------------------------- /plugins/database/img/b+tree-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/database/img/b+tree-example.png -------------------------------------------------------------------------------- /plugins/database/img/b+tree.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/database/img/b+tree.PNG -------------------------------------------------------------------------------- /plugins/database/img/binary-tree-no-balance.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/database/img/binary-tree-no-balance.PNG -------------------------------------------------------------------------------- /plugins/database/img/binary-tree.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/database/img/binary-tree.PNG -------------------------------------------------------------------------------- /plugins/database/img/btree-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/database/img/btree-example.png -------------------------------------------------------------------------------- /plugins/database/img/hash-integer.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/database/img/hash-integer.PNG -------------------------------------------------------------------------------- /plugins/database/img/hash-string.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/database/img/hash-string.PNG -------------------------------------------------------------------------------- /plugins/database/img/mysql-btree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/database/img/mysql-btree.png -------------------------------------------------------------------------------- /plugins/database/img/mysql-select-process.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/database/img/mysql-select-process.jpg -------------------------------------------------------------------------------- /plugins/database/img/mysql-sync.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/database/img/mysql-sync.PNG -------------------------------------------------------------------------------- /plugins/database/img/mysql_profile_demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/database/img/mysql_profile_demo.png -------------------------------------------------------------------------------- /plugins/database/img/read-black-tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/database/img/read-black-tree.png -------------------------------------------------------------------------------- /plugins/database/mysql/mysql索引.md: -------------------------------------------------------------------------------- 1 | ### 索引是什么 2 | 索引底层是`数据结构`,是一种`排好序`的数据结构,帮助MySQL高效获取数据。 3 | MYSQL用到了索引和执行时间没有必然关系。确定查询执行效率的是扫描行数和回表次数。 4 | 5 | > 索引的优缺点 6 | 7 | * 优势:可以快速检索,减少I/O次数,加快检索速度;根据索引分组和排序,可以加快分组和排序; 8 | * 劣势:索引本身也是表,因此会占用存储空间,一般来说,索引表占用的空间的数据表的1.5倍;索引表的维护和创建需要时间成本,这个成本随着数据量增大而增大;构建索引会降低数据表的修改操作(删除,添加,修改)的效率,因为在修改数据表的同时还需要修改索引表; 9 | 10 | ### 索引的底层数据结构 11 | 常见的索引的存储的数据结构有如下几种 12 | * 二叉树 13 | * 红黑树 14 | * B+树 15 | * 哈希 16 | 17 | 目前数据库索引中索引的存储类型使用的最多的是哈希和B+树,我们一一来分析这几种数据结构。可在https://www.cs.usfca.edu/~galles/visualization/Algorithms.html 网站上查看这几种类型的数据结构演示示例。 18 | * 二叉树:二叉树的特点就是左叶子节点的值小于其父节点,右叶子节点的值大于其父节点,其查找方式是二分查找。在一些业务场景中使用二叉树作为索引的存储结构会导致`单边失衡`的情况,并且树的深度无法控制。举个例子,我们经常会设计一个表的主键是自增的整数,那么如果使用二叉树,下一行记录的主键永远比上一行的大,映射到二叉树上,就会造成所有的叶子节点都在右边,数据量大了的话,就会影响到查询的效率。 19 | 20 | ![](../img/binary-tree.PNG)![](../img/binary-tree-no-balance.PNG) 21 | * 红黑树:Read Black Tree,是一种自平衡的二叉树,能够解决二叉树中单边失衡的问题,但是红黑树没有解决掉树深度的问题,如果树的深度很深的话,查询的效率依然不是很高。 22 | 23 | ![](../img/read-black-tree.png) 24 | * B+树:B是指Balance,不是Binary的意思,B+树是B树的一个变种,叫平衡搜索多叉树,总结来说相对于B树查询速度更快更稳定,我们这里就不做讨论。所有的记录节点都是按键值大小顺序存放在同一层的叶节点中,叶节点间用指针相连,构成双向循环链表,非叶节点(根节点、枝节点)只存放键值,不存放实际数据,非叶子节点只是起到了索引的作用,所有的查询最终都会落到叶子节点。B+树索引减少了树的深度,可以控制深度,同时也增加了索引存储的容量。 25 | 26 | ![](../img/b+tree.png) 27 | * Hash:数据库对hash索引的列做hash计算,将哈希码存储在索引中,同时在哈希表中保存指向每一个数据行的指针,计算机中hash查找是基于内存地址的查找方法,将内存地址与数据值之间建立联系,因此在精准查询时速率很快,但是hash索引在范围查找时效率就很差了。例如在一些政府项目中,对公民的身份证号码建立索引的时候,就可以采用这种hash索引,具体设计时可以将身份证倒序,然后使用前缀索引,匹配前9个字符效率就很高了。 28 | 29 | ### 索引的分类 30 | * **普通索引(INDEX)**:最基本的索引,没有任何限制。`ALTER TABLE 'user' ADD INDEX index_name('col')` 31 | * **唯一索引(UNIQUE)**:与"普通索引"类似,不同的就是:索引列的值必须唯一,但允许有空值。`ALTER TABLE 'user' ADD UNIQUE index_name('col')` 32 | * **主键索引(PRIMARY)**:它 是一种特殊的唯一索引,不允许有空值。`ALTER TABLE 'user' ADD PRIMARY KEY pk_index('col')` 33 | * **全文索引(FULLTEXT )**:仅可用于 MyISAM 表, 用于在一篇文章中,检索文本信息的, 针对较大的数据,生成全文索引很耗时好空间。nnoDB 1.2.x版本开始支持全文检索。`ALTER TABLE 'user' ADD FULLTEXT INDEX ft_index('col')` 34 | * **组合索引**:为了更多的提高mysql效率可建立组合索引,遵循”最左前缀“原则。`ALTER TABLE 'user' ADD INDEX index_name('col1', 'col2', 'col3s')` 35 | 36 | ### 聚集索引与非聚集索引 37 | 聚集(clustered)索引,也叫聚簇索引。定义:数据行的物理顺序与列值(一般是主键的那一列)的逻辑顺序相同,一个表中只能拥有一个聚集索引。 38 | 非聚集(unclustered)索引。定义:该索引中索引的逻辑顺序与磁盘上行的物理存储顺序不同,一个表中可以拥有多个非聚集索引。 39 | 40 | FULLTEXT(全文)索引,仅可用于MyISAM和InnoDB,针对较大的数据,生成全文索引非常的消耗时间和空间。对于文本的大对象,或者较大的CHAR类型的数据,如果使用普通索引,那么匹配文本前几个字符还是可行的,但是想要匹配文本中间的几个单词,那么就要使用LIKE %word%来匹配,这样需要很长的时间来处理,响应时间会大大增加,这种情况,就可使用时FULLTEXT索引了,在生成FULLTEXT索引时,会为文本生成一份单词的清单,在索引时及根据这个单词的清单来索引 41 | 全文索引的查询也有自己特殊的语法,而不能使用LIKE %查询字符串%的模糊查询语法: 42 | `SELECT * FROM table_name MATCH(ft_index) AGAINST('查询字符串');` 43 | * 对于较大的数据集,把数据添加到一个没有FULLTEXT索引的表,然后添加FULLTEXT索引的速度比把数据添加到一个已经有FULLTEXT索引的表快。 44 | * 5.6版本前的MySQL自带的全文索引只能用于MyISAM存储引擎,如果是其它数据引擎,那么全文索引不会生效。5.6版本之后InnoDB存储引擎开始支持全文索引 45 | * 在MySQL中,全文索引支队英文有用,目前对中文还不支持。5.7版本之后通过使用ngram插件开始支持中文。 46 | 47 | ### 索引的高度 48 | 聚集索引的高度决定了根据主键取数据的理论IO次数。根据非聚集索引读取数据的理论IO次数还要加上访问聚集索引的IO次数总和。实际上可能要不了这么多IO。因为索引的分支节点所在的Page因为多次读取会在mysql内存里cache住。 49 | 50 | ### 操作系统和MySQL页的大小 51 | * 操作系统页大小: getconf PAGESIZE,看了一下linux X86系列的是4096B=4KB 52 | * MySQL InnoDB页大小: show variables like 'innodb_page_size'; 16384B=16KB,是内存页的整数倍 53 | 54 | ### MySQL索引查询的原理 55 | 举个例子 56 | 57 | ![](../img/mysql-select-process.jpg) 58 | 59 | 上图是一个BTREE的结构图,简单分析下查询原理。如图所示,如以查询45的数据项为例,`第一次IO是把最上面的第一块磁盘块加载到内存缓冲区`,在内存中通过二分查找法确定45在30和60之间,所以把磁盘块锁定到当前磁盘块的P2指针,然后通过P2指针的磁盘地址把第二块磁盘加载到内容,这样发生第二次IO,再一次的二分查找确定45在40到50之间,所以通过第二块磁盘的P2指针对应的磁盘地址进行第三次IO,加载第三块磁盘到内存中,最后在内存中通过二分查找找到45,由于在内存中的速度非常快,所以耗时可以忽略不计,到此为止,本次查询结束,共进行了三次磁盘IO。在真实的存储过程中,三层的BTREE可以表示上百万的数据,这样也就说明如果有上百万的数据,不使用索引,将会进行百万次的IO,但是使用索引只需要三次就可以,性能将有很大的提升。 60 | 61 | 这里有个注意点,就是作为索引的字段越小,每个磁盘块将存储的索引越多,也就是说如果数据量一定的条件下,索引字段越小,可能数的深度越小,查询效率越高,如果树只有一层的时候将成为线性表。 62 | ### 索引的最佳实践 63 | #### 什么时候要使用索引? 64 | 1. 主键自动建立唯一索引; 65 | 2. 经常作为查询条件在WHERE或者ORDER BY 语句中出现的列要建立索引; 66 | 3. 作为排序的列要建立索引; 67 | 4. 查询中与其他表关联的字段,外键关系建立索引 68 | 5. 高并发条件下倾向组合索引; 69 | 6. 用于聚合函数的列可以建立索引,例如使用了max(column_1)或者count(column_1)时的column_1就需要建立索引 70 | 71 | #### 什么时候不要使用索引? 72 | 1. 经常增删改的列不要建立索引; 73 | 2. 有大量重复的列不建立索引; 74 | 3. 表记录太少不要建立索引。只有当数据库里已经有了足够多的测试数据时,它的性能测试结果才有实际参考价值。如果在测试数据库里只有几百条数据记录,它们往往在执行完第一条查询命令之后就被全部加载到内存里,这将使后续的查询命令都执行得非常快--不管有没有使用索引。只有当数据库里的记录超过了1000条、数据总量也超过了MySQL服务器上的内存总量时,数据库的性能测试结果才有意义。 75 | 4. 如果一个表中没有显示的指定索引,MySQL会默认选取第一个不允许为NULL的唯一索引,如果还没有则使用InnoDB内置的ROWID作为索引。 76 | 77 | #### 索引失效的情况: 78 | 1. 在组合索引中不能有列的值为NULL,如果有,那么这一列对组合索引就是无效的。 79 | 2. 在一个SELECT语句中,索引只能使用一次,如果在WHERE中使用了,那么在ORDER BY中就不要用了。 80 | 3. LIKE操作中,'%aaa%'不会使用索引,也就是索引会失效,但是‘aaa%’可以使用索引。 81 | 4. 在索引的列上使用表达式或者函数会使索引失效,例如:select * from users where YEAR(adddate)<2007,将在每个行上进行运算,这将导致索引失效而进行全表扫描,因此我们可以改成:select * from users where adddate<’2007-01-01′。其它通配符同样,也就是说,在查询条件中使用正则表达式时,只有在搜索模板的第一个字符不是通配符的情况下才能使用索引。 82 | 5. 在查询条件中使用不等于,包括<符号、>符号和!=会导致索引失效。特别的是如果对主键索引使用!=则不会使索引失效,如果对主键索引或者整数类型的索引使用<符号或者>符号不会使索引失效。(经erwkjrfhjwkdb同学提醒,不等于,包括<符号、>符号和!,如果占总记录的比例很小的话,也不会失效) 83 | 6. 在查询条件中使用IS NULL或者IS NOT NULL会导致索引失效。 84 | 7. 字符串不加单引号会导致索引失效。更准确的说是类型不一致会导致失效,比如字段email是字符串类型的,使用WHERE email=99999 则会导致失败,应该改为WHERE email='99999'。 85 | 8. 在查询条件中使用OR连接多个条件会导致索引失效,除非OR链接的每个条件都加上索引,这时应该改为两次查询,然后用UNION ALL连接起来。 86 | 9. 如果排序的字段使用了索引,那么select的字段也要是索引字段,否则索引失效。特别的是如果排序的是主键索引则select * 也不会导致索引失效。 87 | 10. 尽量不要包括多列排序,如果一定要,最好为这队列构建组合索引; 88 | 89 | #### 索引的创建 90 | 1. 尽量扩展索引,不要新建索引,因为索引过多会导致写入速度变慢。 91 | 2. 建有索引的列别参与计算,因为BTREE中存的都是表中的字段值,如果需要先计算再比较的话成本还是比较大的。 92 | 3. CREATE INDEX t ON(columnA, columnB) 索引是以左侧列为基准,向右侧列查找,所以a的区分度最好够小 93 | #### 索引的使用 94 | 1. 最左匹配原则 95 | 这个原则非常重要,我们建立索引的时候根据业务场景建立合适的索引。mysql索引匹配会从左向右一直匹配直到遇到范围查询才停止,比如id=1 and phone=15652635684 and time>1562565855,如果建立索引的顺序为(id,phone,time)则time用不到索引,但是如果顺序为(id,time,phone)则都可以用到。索引的最左前缀和和B+Tree中的“最左前缀原理”有关,举例来说就是如果设置了组合索引那么以下3中情况可以使用索引:col1,,其它的列,比如,col2,col3等等都是不能使用索引的。 96 | 2. =和in查询中可以乱序,不需要考虑最左匹配原则,mysql的查询优化器会进行自动优化 97 | 3. 使用短索引。索引字段尽量选择区分度高的字段,因为重复值越多,扫描的记录数就越多,比如性别类型为0和1,这种的重复就很高,不建议这种类型加索引,因为加了也没有多大提高。例如在一些政府项目中,对公民的身份证号码建立索引的时候,就可以采用这种hash索引,具体设计时可以将身份证倒序,然后使用前缀索引,匹配前9个字符效率就很高了。对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的 列,如果在前10 个或20 个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。 98 | 4. 优化方案 99 | * 增加多种不同规格索引提高索引选择性(5-6组) 100 | * 空间换时间,定时任务增加时报、日报等中间结果 101 | * 硬件调优:增大innodb_buffer_pool多利用内存,减少硬盘回表 102 | 103 | ### B树与B+树的区别 104 | 1. B树每个节点都存储数据,所有节点组成这棵树。B+树只有叶子节点存储数据(B+数中有两个头指针:一个指向根节点,另一个指向关键字最小的叶节点),叶子节点包含了这棵树的所有数据,所有的叶子结点使用链表相连,便于区间查找和遍历,所有非叶节点起到索引作用。 105 | 2. B树中叶节点包含的关键字和其他节点包含的关键字是不重复的,B+树的索引项只包含对应子树的最大关键字和指向该子树的指针,不含有该关键字对应记录的存储地址。 106 | 3. B树中每个节点(非根节点)关键字个数的范围为[m/2(向上取整)-1,m-1](根节点为[1,m-1]),并且具有n个关键字的节点包含(n+1)棵子树。B+树中每个节点(非根节点)关键字个数的范围为[m/2(向上取整),m](根节点为[1,m]),具有n个关键字的节点包含(n)棵子树。 107 | 4. B+树中查找,无论查找是否成功,每次都是一条从根节点到叶节点的路径。 108 | 109 | ![](../img/btree-example.png)![](../img/b+tree-example.png) 110 | 111 | ### EXPLAIN 112 | -------------------------------------------------------------------------------- /plugins/database/mysql/数据库主键怎么选择.md: -------------------------------------------------------------------------------- 1 | 主键:用于唯一标识一个表中一行数据。 2 | 外键:用于建立两个表之间的关系,A表中有一列是B表中的主键,那么A表中这列的数据就受到B表主键的约束。 3 | 4 | 那么关于主键应该如何设计呢,这里我说下优缺点: 5 | 1. 用自动增长字段作为主键,这样的主键可以称之为 非业务主键(或逻辑主键、或代理主键),就是说这列与业务无关,仅仅是作为主键而设计。 6 | * 优点:自增长字段往往是integer bigint类型,最多占8个字节。索引与外键 所占用的空间连带减少,增删改查 效率高。业务变化,不影响,不需要更新主键。 7 | * 缺点:无法转移数据库,比如把表中的一批数据 转移 或 附带到 另一个表中,那么由于是自增长字段,那么会导致无法转移,因为另外一个表可能已经存在部分数据,会造成主键冲突。自增长字段的缺陷。 8 | * 业务数据的完整性,无法保证。 9 | 2. 用全球唯一标识符GUID,来做主键。依然是非业务主键。 10 | * 优点:可以转移数据库。业务变化,不影响,不需要更新主键。 11 | * 缺点:字符串较长,占用的空间较多,如果用于外键的话,会导致连带其它表占用的空间连带增多。A表中有一列是B表中的主键 ,那么A表中的这列也是需要有个索引的,即存储空间会连带增多。效率变低。 12 | * 即除了正常业务字段外,还是弄个字符串字段来专一保存这个全球唯一标识符,造成存储浪费。业务数据的完整性,无法保证。 13 | 3. 用业务字段做主键。 14 | * 优点:可以转移数据库,最大化节省了空间,因为并没有 多增加一个非业务字段做主键。业务数据的完整性,可以保证。避免产生垃圾数据,银行就是用业务字段做主键的,虽然效率低,但是安全。 15 | * 缺点:如果业务发生改变,有可能需要修改主键,举例:国家A表用身份证号做主键,然后其他很多表中的身份证号这列都是来自 身份证表A中的主键(即外键),那么如果身份证号升级,比如从1代升级到2代,那么连带的表的外键 的索引 通通都得发生变化,效率极低 因为会连带更新一串用到这个外键的表,可见用业务字段做主键的话,你得保证 主键不经常变化。 16 | 4. 有些业务使用身份证作为主键 17 | * 优点:可能就是能很好满足按照身份证号进行等值查询的需求,因为是主键所以就不需要回表。 18 | * 缺点:就是索引长度过大,导致每次查询磁盘I/O增加,解决方案是可以采用倒序存储身份证ID,这样就可以进行前缀索引「正序无法满足前缀索引,比如,我们国家的身份证号,一共18位,其中前6位是地址码,所以同一个县的人的身份证号前6位一般会是相同的,这时候如果对身份证号做长度为6的前缀索引的话,这个索引的区分度就非常低了。[MySQL前缀索引和索引的选择性](https://www.cnblogs.com/gomysql/p/3628926.html) 19 | 20 | * MySQL索引与回表 https://www.jianshu.com/p/8991cbca3854 -------------------------------------------------------------------------------- /plugins/docker.md: -------------------------------------------------------------------------------- 1 | ### 学习路线 2 | * Docker基础知识 3 | * [CentOS下安装Docker](#CentOS下安装Docker) 4 | * [基础概念](https://www.cnblogs.com/Can-daydayup/p/15559341.html) 5 | * [常用命令](#常用命令) 6 | * Docker基础使用 7 | * Docker发布SpringBoot项目 https://www.jianshu.com/p/397929dbc27d 8 | * Docker+Jenkins+Git+SpringBoot构建自动化部署 9 | 10 | ### Docker是什么 11 | Docker是一个开源的应用容器引擎,Docker其实就是可以打包程序和运行环境,把环境和程序一起发布的容器,当你需要发布程序时,你可以使用Docker将运行环境一起发布,其他人拿到你的程序后可以直接运行,避免出现一次编译,到处调试的尴尬局面~。Docker的出现主要是为了解决“在我的机器上是正常的,为什么到你的机器上就不正常了”的问题,但是随着Docker的进步,以及K8S等编排软件的流行,Docker的使用场景大大扩展,Docker已经成为高可用服务集群持续交付、继续集成以及云原生的关键技术。 12 | 13 | ### Docker解决了什么问题 14 | Docker主要解决了在你的环境上运行没问题,但是在我的环境上运行有问题 15 | 16 | #### CentOS下安装Docker 17 | ``` shell 18 | # linux 3.10 内核,docker官方说至少3.8以上,建议3.10以上 19 | [root@localhost ~]# uname -a 20 | # 把yum包更新到最新(温馨提示:新环境或测试环境可随意操作,生产环境酌情慎重更新) 21 | [root@localhost ~]# yum update 22 | # 设置yum源 23 | [root@localhost ~]# yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo(阿里仓库) 24 | # 可以查看所有仓库中所有docker版本 25 | [root@localhost ~]# yum list docker-ce --showduplicates | sort -r 26 | # 安装Docker,命令:yum install docker-ce-版本号 27 | [root@localhost ~]# yum install docker-ce-18.03.1.ce 28 | [root@localhost ~]# systemctl start docker 29 | [root@localhost ~]# systemctl enable docker 30 | [root@localhost ~]# docker version 31 | ``` 32 | 33 | #### 常用命令 34 | ```shell 35 | 启动 systemctl start docker 36 | 停止 systemctl stop docker 37 | 重启 systemctl restart docker 38 | 查看状态 systemctl status docker 39 | 开机启动 systemctl enable docker 40 | 查docker信息 docker info 41 | 列举在跑的容器 docker ps 42 | 列举出所有容器 docker ps -a 包含历史 43 | 查看镜像 docker image ls 或 docker images 44 | 启动容器 docker start containerId 45 | 停止容器 docker stop containerId 46 | 重启容器 docker restart containerId 或者 docker restart 容器名字 47 | 删除容器 docker rm containerId 48 | 查看日志 docker logs [-f 跟踪日志输出 -t 显示时间戳 --since="2021-11-19"显示某个时间的所有日志 --tail=10列出最新的N条日志] containerId 49 | 修改容器名字 docker rename 容器原来名 要改为的名字 50 | ``` 51 | 52 | #### Docker中启动springboot项目 53 | 54 | FROM java:8 55 | MAINTAINER luke.chen 56 | VOLUME /tmp 57 | ADD demo-0.0.1-SNAPSHOT.jar app.jar 58 | RUN bash -c 'touch /app.jar' 59 | ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app.jar"] -------------------------------------------------------------------------------- /plugins/jmeter.md: -------------------------------------------------------------------------------- 1 | # JMeter笔记 2 | 3 | ## JMeter特性 4 | * 开源 5 | * 友好的GUI,测试结果方便查看 6 | * 支持各种测试方法、多种协议:Web(HTTP/HTTPS/SOAP)、数据库(JDBC/LDAP)、Mail(POP3) 7 | * 支持远程分布式测试 8 | 9 | ## JMeter测试组件及关系 10 | ![](png/jmeter-elements.png) 11 | 12 | * 测试计划(Test Plan) 13 | * 测试计划包含的所有内容都按照从上到下的顺序执行,或者按照测试计划中定义的顺序执行。测试计划以.jmx扩展文件的形式保存。 14 | * 线程组(Thread Group) 15 | * 一个测试计划中至少包含一个测试的线程组 16 | * 线程组是测试的起点 17 | * 线程中可以设置线程数、加速时间(Ramp-up:在n秒内启动这些线程)、执行测试的次数 18 | * 控制器(Controllers) 19 | * 分为两大类:采集器和控制器 20 | * 采集器:Samplers in JMeter allows JMeter to send different types of requests to a server. Samplers are the actual requests, JMeter sends to the web server under test. Each sampler (except Test Action) generates one or more sample results. 21 | * JMeter中采集器服务的请求列表:FTP/HTTP/JDBC/Java/JMS/JUnit/LDAP/Mail/TCP 22 | * 逻辑控制器:逻辑控制器可以控制线程中采集器处理顺序的流程 23 | * 逻辑控制器列表:IF控制器/while控制器/Switch控制器/ForEach控制器... 24 | * 监听器(Listeners) 25 | * A listener is a component that shows the results of the samples. The results can be shown in a tree, tables, graphs or simply written to a log file. 26 | * 计时器(Timers) 27 | * 在网站或应用程序上执行任何操作时,它们自然会有暂停和延迟。 这些可以使用计时器(Timers)进行模拟。JMeter发送请求时不会在每个采样器/请求之间应用延迟。 如果在服务器上执行负载/压力测试没有指定延迟,它将会超载。 这可能不完全是我们想要的。可以添加一个计时器元素,该元素允许您定义在每个请求到达时间等待的终止。 28 | * 配置元素(Configuratin Elements) 29 | * Config elements in JMeter are used to configure or modify the sampler requests made to the server. These elements are added at the same or higher level of the samplers that we want to configure. 30 | * 预处理器元素(Pre-Processor Elements) 31 | * 预处理器元素用于在采集器发出请求之前修改样本请求的设置,或更新未从响应文本中提取的变量。 32 | * 后处理器元素(Post-Processor Elements) 33 | * 后处理器最常用于处理响应数据 34 | 35 | ## JMeter函数 36 | JMeter函数可以称为特殊值,可以填充测试树中任何Sampler或其他元素的字段。 37 | 38 | 例如:${__time(dd MM YYYY HH mm ss)} 39 | 40 | ## JMeter常用测试计划 41 | 42 | ### JMeter数据库测试计划 43 | 可用于数据库的性能测试。 44 | 1. 添加一个测试计划,然后添加一个Thread Group 45 | 2. 在Thread Group中,添加一个JDBC Request的Sampler和JDBC Connection Configuration的配置器 46 | 3. 将响应的JDBC jar放到jmeter lib下 47 | 4. 填写相关的sql,数据库信息等 48 | 49 | ### JMeter Web测试计划 50 | 可用于测试页面的响应时间。 51 | 1. 添加一个测试计划,然后添加一个Thread Group 52 | 2. 在Thread Group中,添加一个HTTP Request的Sampler和View Result Tree的Listener 53 | 3. 在HTTP Request中填写相关信息 54 | 55 | ### JMeter FTP测试 56 | 参考https://www.yiibai.com/jmeter/jmeter-ftp-test-plan.html 57 | 58 | ### JMeter测试Message Queue 59 | JMeter可以测试消息队列的吞吐量,也可以单独测试subscriber/publisher的性能 60 | 61 | ### JMeter分布式测试 -------------------------------------------------------------------------------- /plugins/maven.md: -------------------------------------------------------------------------------- 1 | * 本地父子项目继承: 其实都是一个坐标,不过本地父项目你需要install到本地Maven仓库,不然坐标无法检索。安装到本地仓库即可让子项目继承,父项目有的依赖子项目都会有了。执行mvn clean install,具体示例参考springcloud-eureka。 -------------------------------------------------------------------------------- /plugins/mq/img/mq-compare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/mq/img/mq-compare.png -------------------------------------------------------------------------------- /plugins/mq/mq.md: -------------------------------------------------------------------------------- 1 | ### 学习笔记 2 | - [什么时候使用MQ]() 3 | - [常见问题]() 4 | - [为什么要用消息队列?(消息队列的应用场景?)](#为什么要用消息队列-消息队列的应用场景) 5 | - [各种消息队列产品的比较?](#各种消息队列产品的比较) 6 | - [消息队列的优点和缺点?](#消息队列的优点和缺点) 7 | 8 | * MQ总结 9 | * 消息总线(Message Queue),是一种跨进程的通信机制,用于上下游传递消息。 10 | * 消息队列的本质是一种“新进先出”的数据结构 11 | * 常用场景:解耦、异步、削峰 12 | * 什么时候不使用MQ? 13 | * 上游实时关注执行结果 14 | * 什么时候使用MQ? 15 | * 数据驱动的任务依赖。D依赖C,C依赖B,B依赖A, 16 | * 上游不关心多下游执行结果 17 | * 异步返回执行时间长 18 | * 常见产品 19 | * ActivyMQ 20 | * RabbitMQ 21 | * QMQ是去哪儿网内部广泛使用的消息中间件,自2012年诞生以来在去哪儿网所有业务场景中广泛的应用,包括跟交易息息相关的订单场景; 也包括报价搜索等高吞吐量场景。目前在公司内部日常消息qps在60W左右,生产上承载将近4W+消息topic,消息的端到端延迟可以控制在10ms以内。 22 | * Apache RocketMQ is a distributed messaging and streaming platform with low latency, high performance and reliability, trillion-level capacity and flexible scalability. 23 | * Kafka 24 | * MQTT 25 | 26 | ### 消息队列的技术选型 27 | 消息队列及常见消息队列介绍 - 云+社区... 28 | http://note.youdao.com/noteshare?id=7c550bb62a6597091e4533fbb6b920c1&sub=wcp155548841293021 29 | 30 | ### 消息队列优势 31 | 消息队列作为高并发系统的核心组件之一,能够帮助业务系统解构提升开发效率和系统稳定性。主要具有以下优势: 32 | * 33 | 34 | 35 | 36 | 除了上面列出的应用解棉、流量消峰、消息分发等功能外,消息队列还有保证最终一致性、方便动态扩容等功能。 37 | 38 | 39 | ### 常见问题 40 | 1. 为什么要用消息队列?(消息队列的应用场景?) 41 | 2. 各种消息队列产品的比较? 42 | 3. 消息队列的优点和缺点? 43 | 4. 如何保证消息队列的高可用? 44 | 5. 如何保证消息不丢失? 45 | 6. 如何保证消息不被重复消费? 46 | 7. 如何保证消息的顺序性? 47 | 8. 基于MQ的分布式事务实现 48 | 49 | 为什么要用消息队列-消息队列的应用场景 50 | ---------------------------------- 51 | 52 | 消息队列的本质是一个先进先出的数据结构。它能在解耦、异步、削峰上提供很好的能力。 53 | 1. 解耦(解决不同重要程度、不同能力级别系统之间依赖导致一死全死) 54 | 复杂的应用里会存在多个子系统, 比如在电商应用中有订单系统、库存系统、物流系统 支付系统等,这个时候如果各个子系统之间的耦合性太高,整体系统的可用性就会大幅降低,多个低错误率的子系统糅合在一起,得到的是一个高错误率的整体系统。以电商应用为例,用户创建订单后,如果耦合调用库存系统、物流系统、支付系统,任何一个子系统出了故障或者因为升级等原因暂时不可用,都会造成下单操作异常,影响用户使用体验。当转变成基于消息队列的方式后,系统可用性就高多了,比如物流系统因为发生故障,需要几分钟的时间来修 ,在这几分钟的时间里,物流系统要处理的内容被缓存在消息队列里,用户的下单操作可以正常完成。当物流系统恢复后,补充处理存储在消息队列里的订单信息即可,终端用户感知不到物流系统发生过几分钟的故障。 55 | 2. 异步(当存在一对多调用时,可以发一条消息给消息系统,让消息系统通知相关系统,应用间并发处理消息,相比串行处理,减少处理时间) 56 | 比如用户注册的消息,需要被数据部门处理,也要被业务部门处理,如果串行调用,会导致用户注册的流程耗时,这时候采用消息异步处理,用户完成基本的注册后只需要写入消息,各个子系统订阅消费此消息。 57 | 3. 削峰(主要解决瞬时写压力大于应用服务能力导致消息丢失、系统奔溃等问题) 58 | 在秒杀或团队抢购活动中,由于用户请求量较大,导致流量暴增,秒杀的应用在处理如此大量的访问流量后,下游的通知系统无法承载海量的调用量,甚至会导致下游系统崩溃等问题而发生漏通知的情况。为解决这些问题,可在应用和下游通知系统之间加入消息队列来做缓冲。 59 | 4. 蓄流压测(线上有些链路不好压测,可以通过堆积一定量消息再放开来压测) 60 | 61 | 各种消息队列产品的比较 62 | --------------------- 63 | * ActiveMQ, 早期使用的比较多,没有经过大规模吞吐量场景的验证,社区也不是很活跃,现在确实用的不多,不推荐 64 | * RabbitMQ, 采用Erlang语言开发,导致很少有工程师去深入研究和掌控它,对公司而言,如果想进行二次开发,基本处于不可控的状态,但是RabbitMQ是开源的,且社区很活跃,相对来说有比较稳定的支持。如果对性能要求不是特别高,且追求稳定,推荐使用。另外RabbitMQ严格遵循了AMQP协议,功能十分丰富,且提供rabbitmqAdmin可视化管理后端 65 | * RocketMQ,采用Java开发,诞生于电商业务,天生支持分布式,且经过阿里双十一业务场景考验,稳定性和性能均不错,且可以考虑后期二次开发,推荐使用,也提供后端可是化界面。社区活跃度中等 66 | * Kafka, 采用Scala开发,诞生于Hadoop大数据业务,是大数据领域、日志采集的标配,社区活跃度高,推荐使用。 67 | 68 | https://blog.csdn.net/zollty/article/details/53958656 69 | 70 | 71 | 消息队列的优点和缺点 72 | ------------------- 73 | * 优点:解耦、异步、削峰 74 | * 缺点: 75 | * 系统可用性降低: 系统引入的外部越多,系统的稳定性就越差。一旦MQ宕机,就会对业务产生影响。 -> `如何保证MQ的高可用?`。之前我们发完文章,直接RPC调用用户模块,获取好友列表,然后挨个增加他们的未读文章列表,为了解耦,我们引入MQ,如果MQ挂了,那他们的未读文章就没有我发的这篇文章。 76 | * 系统复杂度提高: MQ的引入大大增加了系统的复杂度,以前系统是同步的远程调用,现在是通过MQ进行异步调用。也就是在内容服务和用户服务之间加了一层MQ,那就必须考虑`消息丢失了怎么办?`、`重复消息怎么处理?`、`如何保证消息顺序性消费?`这些情况怎么办? 77 | * 一致性问题:A系统处理完业务,通过MQ给B、C、D三个系统发消息数据,如果B、C系统处理成功,D系统处理失败,那这个数据就不一致了。比如商城下的订单,要异步同步到门店工单,和OMS订单,那如果门店成功了,OMS失败了,数据就不一致。 78 | 79 | 80 | ![MQ详细对比](img/mq-compare.png) -------------------------------------------------------------------------------- /plugins/mqtt.md: -------------------------------------------------------------------------------- 1 | ### 学习思路 2 | 1. 什么是MQTT?使用场景 3 | 2. 常用的开源产品有哪些? 4 | 3. JAVA集成MQTT 5 | 6 | 7 | * MQTT 介绍 8 | > 简述 9 | MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的"轻量级"通讯协议,该协议构建于TCP/IP协议上,由IBM在1999年发布。MQTT最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。 10 | 11 | MQTT是一个基于客户端-服务器的消息发布/订阅传输协议。MQTT协议是轻量、简单、开放和易于实现的,这些特点使它适用范围非常广泛。在很多情况下,包括受限的环境中,如:机器与机器(M2M)通信和物联网(IoT)。其在,通过卫星链路通信传感器、偶尔拨号的医疗设备、智能家居、及一些小型化设备中已广泛使用。 12 | 13 | > 设计规范 14 | 15 | 由于物联网的环境是非常特别的,所以MQTT遵循以下设计原则: 16 | 1. 精简,不添加可有可无的功能; 17 | 2. 发布/订阅(Pub/Sub)模式,方便消息在传感器之间传递; 18 | 3. 允许用户动态创建主题,零运维成本; 19 | 4. 把传输量降到最低以提高传输效率; 20 | 5. 把低带宽、高延迟、不稳定的网络等因素考虑在内; 21 | 6. 支持连续的会话控制; 22 | 7. 理解客户端计算能力可能很低; 23 | 8. 提供服务质量管理; 24 | 9. 假设数据不可知,不强求传输数据的类型与格式,保持灵活性。 25 | 26 | > 主要特性 27 | 28 | MQTT协议工作在低带宽、不可靠的网络的远程传感器和控制设备通讯而设计的协议,它具有以下主要的几项特性: 29 | 1. 使用发布/订阅消息模式,提供一对多的消息发布,解除应用程序耦合。 30 | 这一点很类似于XMPP,但是MQTT的信息冗余远小于XMPP,,因为XMPP使用XML格式文本来传递数据。 31 | 2. 对负载内容屏蔽的消息传输。 32 | 3. 使用TCP/IP提供网络连接。 33 | 主流的MQTT是基于TCP连接进行数据推送的,但是同样有基于UDP的版本,叫做MQTT-SN。这两种版本由于基于不同的连接方式,优缺点自然也就各有不同了。 34 | 4. 有三种消息发布服务质量: 35 | "至多一次",消息发布完全依赖底层TCP/IP网络。会发生消息丢失或重复。这一级别可用于如下情况,环境传感器数据,丢失一次读记录无所谓,因为不久后还会有第二次发送。这一种方式主要普通APP的推送,倘若你的智能设备在消息推送时未联网,推送过去没收到,再次联网也就收不到了。 36 | "至少一次",确保消息到达,但消息重复可能会发生。 37 | "只有一次",确保消息到达一次。在一些要求比较严格的计费系统中,可以使用此级别。在计费系统中,消息重复或丢失会导致不正确的结果。这种最高质量的消息发布服务还可以用于即时通讯类的APP的推送,确保用户收到且只会收到一次。 38 | 5. 小型传输,开销很小(固定长度的头部是2字节),协议交换最小化,以降低网络流量。 39 | 这就是为什么在介绍里说它非常适合"在物联网领域,传感器与服务器的通信,信息的收集",要知道嵌入式设备的运算能力和带宽都相对薄弱,使用这种协议来传递消息再适合不过了。 40 | 6. 使用Last Will和Testament特性通知有关各方客户端异常中断的机制。 41 | Last Will:即遗言机制,用于通知同一主题下的其他设备发送遗言的设备已经断开了连接。 42 | Testament:遗嘱机制,功能类似于Last Will。 43 | 44 | > MQTT协议实现方式 45 | ![](png/mqtt-fidge-2.svg) 46 | 47 | 实现MQTT协议需要客户端和服务器端通讯完成,在通讯过程中,MQTT协议中有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。 48 | 49 | MQTT传输的消息分为:主题(Topic)和负载(payload)两部分: 50 | Topic,可以理解为消息的类型,订阅者订阅(Subscribe)后,就会收到该主题的消息内容(payload); 51 | payload,可以理解为消息的内容,是指订阅者具体要使用的内容。 52 | 53 | > 网络传输与应用消息 54 | 55 | MQTT会构建底层网络传输:它将建立客户端到服务器的连接,提供两者之间的一个有序的、无损的、基于字节流的双向传输。 56 | 当应用数据通过MQTT网络发送时,MQTT会把与之相关的服务质量(QoS)和主题名(Topic)相关连。 57 | 58 | > MQTT客户端 59 | 60 | 一个使用MQTT协议的应用程序或者设备,它总是建立到服务器的网络连接。客户端可以: 61 | 1. 发布其他客户端可能会订阅的信息; 62 | 2. 订阅其它客户端发布的消息; 63 | 3. 退订或删除应用程序的消息; 64 | 4. 断开与服务器连接。 65 | 66 | > MQTT服务器 67 | 68 | MQTT服务器以称为"消息代理"(Broker),可以是一个应用程序或一台设备。它是位于消息发布者和订阅者之间,它可以: 69 | 1. 接受来自客户的网络连接; 70 | 2. 接受客户发布的应用信息; 71 | 3. 处理来自客户端的订阅和退订请求; 72 | 4. 向订阅的客户转发应用程序消息。 73 | 74 | > MQTT协议中的订阅、主题、会话 75 | 76 | 一、订阅(Subscription) 77 | 78 | 订阅包含主题筛选器(Topic Filter)和最大服务质量(QoS)。订阅会与一个会话(Session)关联。一个会话可以包含多个订阅。每一个会话中的每个订阅都有一个不同的主题筛选器。 79 | 80 | 二、会话(Session) 81 | 82 | 每个客户端与服务器建立连接后就是一个会话,客户端和服务器之间有状态交互。会话存在于一个网络之间,也可能在客户端和服务器之间跨越多个连续的网络连接。 83 | 84 | 三、主题名(Topic Name) 85 | 86 | 连接到一个应用程序消息的标签,该标签与服务器的订阅相匹配。服务器会将消息发送给订阅所匹配标签的每个客户端。 87 | 88 | 四、主题筛选器(Topic Filter) 89 | 90 | 一个对主题名通配符筛选器,在订阅表达式中使用,表示订阅所匹配到的多个主题。 91 | 92 | 五、负载(Payload) 93 | 94 | 消息订阅者所具体接收的内容。 95 | > MQTT协议中的方法 96 | 97 | MQTT协议中定义了一些方法(也被称为动作),来于表示对确定资源所进行操作。这个资源可以代表预先存在的数据或动态生成数据,这取决于服务器的实现。通常来说,资源指服务器上的文件或输出。主要方法有: 98 | 99 | (1)Connect。等待与服务器建立连接。 100 | (2)Disconnect。等待MQTT客户端完成所做的工作,并与服务器断开TCP/IP会话。 101 | (3)Subscribe。等待完成订阅。 102 | (4)UnSubscribe。等待服务器取消客户端的一个或多个topics订阅。 103 | (5)Publish。MQTT客户端发送消息请求,发送完成后返回应用程序线程。 104 | 105 | > MQTT协议数据包结构 106 | 107 | 在MQTT协议中,一个MQTT数据包由:固定头(Fixed header)、可变头(Variable header)、消息体(payload)三部分构成。MQTT数据包结构如下: 108 | 109 | (1)固定头(Fixed header)。存在于所有MQTT数据包中,表示数据包类型及数据包的分组类标识。 110 | (2)可变头(Variable header)。存在于部分MQTT数据包中,数据包类型决定了可变头是否存在及其具体内容。 111 | (3)消息体(Payload)。存在于部分MQTT数据包中,表示客户端收到的具体内容。 112 | 113 | > MQTT固定头 114 | 115 | 固定头存在于所有MQTT数据包中,其结构如下: 116 | 117 | > MQTT数据包类型 118 | 119 | 位置:Byte 1中bits 7-4。 120 | 121 | 相于一个4位的无符号值,类型、取值及描述如下: 122 | 123 | > 标识位 124 | 125 | 位置:Byte 1中bits 3-0。 126 | 127 | 在不使用标识位的消息类型中,标识位被作为保留位。如果收到无效的标志时,接收端必须关闭网络连接: 128 | 129 | (1)DUP:发布消息的副本。用来在保证消息的可靠传输,如果设置为1,则在下面的变长中增加MessageId,并且需要回复确认,以保证消息传输完成,但不能用于检测消息重复发送。 130 | 131 | (2)QoS:发布消息的服务质量,即:保证消息传递的次数 132 | 133 | Ø00:最多一次,即:<=1 134 | 135 | Ø01:至少一次,即:>=1 136 | 137 | Ø10:一次,即:=1 138 | 139 | Ø11:预留 140 | 141 | (3)RETAIN: 发布保留标识,表示服务器要保留这次推送的信息,如果有新的订阅者出现,就把这消息推送给它,如果设有那么推送至当前订阅者后释放。 5.1.3 剩余长度(Remaining Length) 142 | 143 | 地址:Byte 2。 144 | 145 | 固定头的第二字节用来保存变长头部和消息体的总大小的,但不是直接保存的。这一字节是可以扩展,其保存机制,前7位用于保存长度,后一部用做标识。当最后一位为1时,表示长度不足,需要使用二个字节继续保存。例如:计算出后面的大小为0 146 | 5.2 MQTT可变头 147 | 148 | MQTT数据包中包含一个可变头,它驻位于固定的头和负载之间。可变头的内容因数据包类型而不同,较常的应用是作为包的标识: 149 | 150 | 很多类型数据包中都包括一个2字节的数据包标识字段,这些类型的包有:PUBLISH (QoS > 0)、PUBACK、PUBREC、PUBREL、PUBCOMP、SUBSCRIBE、SUBACK、UNSUBSCRIBE、UNSUBACK。 151 | 5.3 Payload消息体 152 | 153 | Payload消息体位MQTT数据包的第三部分,包含CONNECT、SUBSCRIBE、SUBACK、UNSUBSCRIBE四种类型的消息: 154 | 155 | (1)CONNECT,消息体内容主要是:客户端的ClientID、订阅的Topic、Message以及用户名和密码。 156 | (2)SUBSCRIBE,消息体内容是一系列的要订阅的主题以及QoS。 157 | (3)SUBACK,消息体内容是服务器对于SUBSCRIBE所申请的主题及QoS进行确认和回复。 158 | (4)UNSUBSCRIBE,消息体内容是要订阅的主题。 -------------------------------------------------------------------------------- /plugins/mybatis-plus.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | * [MyBatisPlus - Active Record](#MyBatisPlus活动记录ActiveRecord) 3 | * [MyBatisPlus - 实现多数据源 - springboot-mybatisplus-dynaminc-datasource](https://github.com/zhonghuasheng/JAVA/tree/master/springboot) 4 | * 参考文章 https://baomidou.com/guide/dynamic-datasource.html 5 | 6 | ### MyBatisPlus活动记录ActiveRecord 7 | * Active Record(活动记录),是一种领域模型,特点是一个模型类对应关系型数据库中的一个表,而模型类的一个实例对应表中的一行记录。 8 | * 1. 需要让实体类继承Model类且实现主键制定的方法 9 | ```java 10 | public class Employee extends Model { 11 | //..fields 12 | //..getter and setter 13 | 14 | /** 15 | * 指定当前实体类的主键属性 16 | */ 17 | @Override 18 | protected Serializable pkVal() { 19 | return id; 20 | } 21 | } 22 | 23 | @Test 24 | public void testARInsert() { 25 | Employee employee = new Employee(); 26 | employee.setLastName("宋老师"); 27 | employee.setEmail("sls@atguigu.com"); 28 | employee.setGender(1); 29 | employee.setAge(35); 30 | boolean result = employee.insert(); 31 | System.out.println("result:" +result ); 32 | } 33 | ``` 34 | 35 | ## 引用 36 | * [MyBatisPlus系列六:活动记录ActiveRecord](https://blog.csdn.net/lizhiqiang1217/article/details/89739207) -------------------------------------------------------------------------------- /plugins/mybatis.md: -------------------------------------------------------------------------------- 1 | ### 学习计划 2 | * Java ORM 框架 - Hibernate 与 MyBatis 对比 https://blog.csdn.net/Ro_bot/article/details/64124608 3 | * MyBatis为什么在国内相当流行? https://www.zhihu.com/question/50729231 4 | * 重点文章!!!Mybatis教程-实战看这一篇就够了 http://note.youdao.com/noteshare?id=25025129f785447c34196db07db5a9d4&sub=wcp1579140042868307 5 | * MyBatis系列 https://yq.aliyun.com/album/128/?spm=a2c4e.11154792.blogalbumarticle.139.2dfc40dfUImMg8&p=1 6 | * 重点文章 MyBatis缓存使用 http://note.youdao.com/noteshare?id=1780272626a866407a67843498bbbee2&sub=wcp1579159232777506 7 | * SpringBoot与MyBatis整合 https://blog.csdn.net/a905793674/article/details/82051777 8 | * Spring Boot + Mybatis + Redis二级缓存 https://zhuanlan.zhihu.com/p/27726873 9 | * MyBatis示例 https://github.com/homejim/mybatis-examples 10 | * mybatis源码的中文注释以及mybatis的使用和源码解析 https://github.com/homejim/mybatis-cn 11 | * 【Java进阶】实现自己的ORM框架 https://blog.csdn.net/liyazhou0215/article/details/77431561 12 | * MyBatis Plus(简称MP)是一个 Mybatis 的增强工具,在 Mybatis 的基础上只做增强不做改变,为简化开发、提高效率而生 13 | * [MyBatis中${}和#{}有什么区别?MyBatis是如何防止SQL注入的?](#MyBatis防止SQL注入) 14 | 15 | ### 学习笔记 16 | * 【关注点】针对高级查询,Mybatis需要手动编写SQL语句,以及ResultMap。而Hibernate有良好的映射机制,开发者无需关心SQL的生成与结果映射,可以更专注于业务流程。【SQL优化方面】Hibernate的查询会将表中的所有字段查询出来,这一点会有性能消耗。Hibernate也可以自己写SQL来指定需要查询的字段,但这样就破坏了Hibernate开发的简洁性。而Mybatis的SQL是手动编写的,所以可以按需求指定查询的字段。但Hibernate具有自己的日志统计。Mybatis本身不带日志统计,使用Log4j进行日志记录。【扩展性】Hibernate与具体数据库的关联只需在XML文件中配置即可,所有的HQL语句与具体使用的数据库无关,移植性很好。MyBatis项目中所有的SQL语句都是依赖所用的数据库的,所以不同数据库类型的支持不好。【优势对比】MyBatis可以进行更为细致的SQL优化,可以减少查询字段。MyBatis容易掌握,而Hibernate门槛较高。 17 | * mybatis流行的原因很简单,就是做好了自动封装数据对象这件事,又没有搞出其他的破事,实际上在mybatis的应用场景里面,开发者要的就是自动封装,把sql查询结果转化为指定的java对象,这就够了。hibernate也可以做到这些,但是它自己给自己加了不少戏。什么缓存什么Criteria什么Lazy最后导致结果是当项目大了或者业务复杂了,除了优化业务程序和数据库,还得优化它。用mybatis只要优化业务程序和数据库就行了。用hibernate白白增加工作量还增加学习成本,问题是学了还不是必须用的。 18 | * MyBatis 的主要思想是将程序中的大量 SQL 语句抽取出来,配置在配置文件中,以实现 SQL 的灵活配置。MyBatis 并不完全是一种 ORM 框架,它的设计思想和 ORM 相似,只是它允许直接编写 SQL 语句,使得数据库访问更加灵活。因此,准确地说,MyBatis 提供了一种“半自动化”的 ORM 实现,是一种 "SQL Mapping" 框架。 19 | 20 | ![](png/mybatis-architecture.jpg) 21 | * API接口层:提供给外部使用的接口 API,开发人员通过这些本地 API 来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。 22 | * 数据处理层:负责具体的 SQL 查找、SQL 解析、SQL 执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。 23 | * 基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件,为上层的数据处理层提供最基础的支撑。 24 | * 重点文章的目录结构 25 | * 1.从JDBC谈起 26 | * 2.MyBatis介绍 27 | * 3.Mybaits整体架构 28 | * 4.快速入门(quick start) 29 | * 4.1.引入依赖(pom.xml) 30 | * 4.2.全局配置文件(mybatis-config.xml) 31 | * 4.3.配置Map.xml(MyMapper.xml) 32 | * 4.4.修改全局配置文件(mybatis-config.xml) 33 | * 4.5.构建sqlSessionFactory(MybatisTest.java) 34 | * 4.6.打开sqlSession会话,并执行sql(MybatisTest.java) 35 | * 5.分析 36 | * 5.1.引入日志依赖包(pom.xml) 37 | * 5.2.添加log4j.properties 38 | * 5.3.MyBatis使用步骤总结 39 | * 6.完整的CRUD操作 40 | * 6.1.创建UserDao接口 41 | * 6.2.创建UserDaoImpl 42 | * 6.3.编写UserDao对应的UserDaoMapper.xml 43 | * 6.4.添加UserDao的测试用例 44 | * 6.5.编写UserDao的测试用例 45 | * 6.7.解决数据库字段名和实体类属性名不一致的问题 46 | * 7.动态代理Mapper实现类 47 | * 7.1.思考上述CRUD中的问题 48 | * 7.2.使用动态代理改造CRUD 49 | * 7.3.完整的例子 50 | * 7.4.动态代理总结 51 | * 8.mybatis-config.xml详解 52 | * 8.1.properties属性读取外部资源 53 | * 8.2.settings设置 54 | * 8.3.typeAliases 55 | * 8.4.typeHandlers(类型处理器) 56 | * 8.5.plugins(插件)拦截器 57 | * 8.6.environments(环境) 58 | * 8.7.mappers 59 | * 9.Mapper XML文件详解 60 | * 9.1.CRUD标签 61 | * 9.2.#{}和${} 62 | * 9.3.面试题(#、$区别) 63 | * 9.4.resultMap 64 | * 9.5.sql片段 65 | * 10.动态sql 66 | * 10.1.if 67 | * 10.2.choose when otherwise 68 | * 10.3.where 和set 69 | * 10.4.foreach 70 | * 11.缓存 71 | * 11.1.一级缓存 72 | * 12.高级查询 73 | * 12.1.表关系说明 74 | * 12.2.一对一查询 75 | * 12.3.一对多查询 76 | * 12.4.多对多查询 77 | * 12.5.resultMap的继承 78 | * 12.6.高级查询的整理 79 | * 13.延迟加载 80 | * 14.如果sql语句中出现’<’的解决方案 81 | * 14.1、使用xml中的字符实体 82 | * 14.2、使用 >< 83 | * 15.Spring 集成Mybatis 84 | * 15.1引入spring和Mybatis相关依赖 85 | * 15.2配置spring配置文件 86 | * 16.SpringBoot 集成Mybatis 87 | * 17.Mybatis Generator的使用 88 | * 18.MyBatis整合分页插件 pageHelper 89 | * 为什么开启二级缓存需要对PO对象序列化?开启了二级缓存后,还需要将要缓存的pojo实现Serializable接口,为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一定只存在内存中,有可能存在硬盘中,如果我们要再取这个缓存的话,就需要反序列化了。所以mybatis中的pojo都去实现Serializable接口。 90 | * mybatis 也提供了对缓存的支持, 分为一级缓存和二级缓存。 但是在默认的情况下, 只开启一级缓存(一级缓存是对同一个 SqlSession 而言的)。 91 | * 刷新缓存是清空这个 SqlSession 的所有缓存, 不单单是某个键。 92 | 93 | ![](png/mybatis-level1-cache.png) 94 | 95 | ![](png/mybatis-level2-cache.png) 96 | * 一级缓存总结 97 | 1. 在同一个 SqlSession 中, Mybatis 会把执行的方法和参数通过算法生成缓存的键值, 将键值和结果存放在一个 Map 中, 如果后续的键值一样, 则直接从 Map 中获取数据; 98 | 2. 不同的 SqlSession 之间的缓存是相互隔离的; 99 | 3. 用一个 SqlSession, 可以通过配置使得在查询前清空缓存; 100 | 4. 任何的 UPDATE, INSERT, DELETE 语句都会清空缓存。 101 | * 使用 BlockingCache 会在查询缓存时锁住对应的 Key,如果缓存命中了则会释放对应的锁,否则会在查询数据库以后再释放锁,这样可以阻止并发情况下多个线程同时查询数据 102 | * 注意事项 103 | * 由于在更新时会刷新缓存, 因此需要注意使用场合:查询频率很高, 更新频率很低时使用, 即经常使用 select, 相对较少使用delete, insert, update。 104 | * 缓存是以 namespace 为单位的,不同 namespace 下的操作互不影响。但刷新缓存是刷新整个 namespace 的缓存, 也就是你 update 了一个, 则整个缓存都刷新了。 105 | * 最好在 「只有单表操作」 的表的 namespace 使用缓存, 而且对该表的操作都在这个 namespace 中。 否则可能会出现数据不一致的情况。 106 | 107 | * list in 108 | * XXXMapper.java中 getXXX(@Param("ids") List ids) 109 | * XXXMapper.xml中: 110 | ``` 111 | SELECT a, b, c FROM table WHERE id IN 112 | 113 | #{id} 114 | 115 | ``` 116 | * 处理and 117 | 当遇到sql中这样写WHERE ( au_state = '1' OR au_state = '2' ) ,mybatis中queryWrapper.and(Wrapper -> Wrapper.eq(PcmArticle::getAuState, "1").or().eq(PcmArticle::getAuState, "2")); 118 | * 注解 119 | * @TableName:数据库表相关 120 | * @TableId:表主键标识 121 | * @TableField:表字段标识 122 | * @TableField(value= "", exist = false):表示该属性不为数据库表字段,但又是必须使用的。 123 | * @TableField(value= "", exist = true):表示该属性为数据库表字段。 124 | * @TableLogic:表字段逻辑处理注解(逻辑删除) 125 | 126 | ### MyBatis防止SQL注入 127 | SQL注入的根本原因就是SQL的动态编译。能产生SQL注入的肯定是字符串,否则会报类型错误。在MyBatis中${}会产生SQL注入,#{}不会产生SQL注入。 128 | * ${}匹配的是真实传递的值,传递过后,会与sql语句进行字符串拼接,不能预防SQL注入。比如我传递的值是 1' OR 1=1 129 | * #{}匹配的是一个占位符,相当于JDBC中的?,会对一些敏感的字符进行过滤。比如输入带了单引号,会在单引号前加\ 130 | 1. 那么#{}底层是如何防止SQL注入的?只看字符串 131 | #{}底层使用的是PreparedStatement#setString方法能够保证传参作为一个字符串而不会被拆分(所以不会产生字符串拼接),setString对每个字符都做了检查,比如单引号前会加个\来转义 132 | 2. ${}的使用场景动态传入表名或列名 -------------------------------------------------------------------------------- /plugins/netty.md: -------------------------------------------------------------------------------- 1 | # 目录 2 | * [Netty核心组件介绍](http://note.youdao.com/noteshare?id=220ac83ee37543ea9d761699bf5915d8&sub=wcp157838393679928) 3 | * [Netty入门小例子](https://github.com/zhonghuasheng/JAVA/tree/master/netty) 4 | * [基于Netty构建简易版HTTP服务](https://github.com/zhonghuasheng/JAVA/tree/master/netty) 5 | * [基于Netty实现一个WebSocket服务,实现消息的主动推送(聊天)](https://github.com/zhonghuasheng/JAVA/tree/master/netty) 6 | * [基于Netty实现自定义TCP数据格式的数据接收发送](https://github.com/zhonghuasheng/JAVA/tree/master/netty) 7 | * [基于Netty实现UDP服务](https://github.com/zhonghuasheng/JAVA/tree/master/netty) 8 | 9 | ## 学习计划 10 | `入门阶段` 11 | * Netty 简单server和client示例 https://www.jianshu.com/p/3c0830e13467 12 | * 基于netty搭建websocket,实现消息的主动推送 https://www.jianshu.com/p/56216d1052d7 13 | * Netty实现简单HTTP代理服务器 https://www.cnblogs.com/w1570631036/p/9665385.html 14 | * Netty总结+实现一个简易版Tomcat https://www.cnblogs.com/wuzhenzhao/p/10418650.html 15 | * Netty Channel Option详解 https://www.ezlippi.com/blog/2019/05/netty-channel-option.html 16 | * Netty源码分析 https://segmentfault.com/a/1190000007282628 17 | * Netty之微信-IM介绍 18 | * 代码地址 https://github.com/peiguihuang/wechat-netty 19 | * 文档说明介绍 20 | * https://www.jianshu.com/p/7522bda72a25 21 | * https://blog.csdn.net/huangpeigui/article/details/86596245 22 | * webSocket进阶篇——STOMP Over Websocket https://www.jianshu.com/p/32fae52c61f6 23 | * Netty 粘包/半包原理与拆包实战 https://blog.csdn.net/crazymakercircle/article/details/83957259 24 | * 如何用JAVA实现一款高可用的TCP数据传输服务器(一)——【基于netty4.x】 https://blog.csdn.net/qq_24874939/article/details/86475285 https://github.com/Siwash/netty_TCP 25 | * Linux下Netty实现高性能UDP服务(SO_REUSEPORT) https://www.jianshu.com/p/61df929aa98b 26 | `深入学习` 27 | * BIO/NIO/AIO/异步/同步 28 | * Reactor模式/Proactor模式 29 | * 基于Netty实现简单的RPC 30 | * Netty NioEventGroup的单线程/多线程/主从线程模型 31 | 32 | ## Netty总结 33 | Netty 是一款提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。也就是说,Netty 是一个基于 NIO 的客户、服务器端编程框架,使用 Netty 可以确保你快速和简单地开发出一个网络应用。 34 | Netty 基本上是作为架构的技术底层而存在的,主要完成高性能的网络通信。 35 | Channel 是对Java 底层Socket 连接的抽象 36 | ByteBuf 是Netty 整个结构里面最为底层的模块,主要负责把数据从底层IO 里面读到ByteBuf,然后传递给应用程序,应用程序处理完成之后再把数据封装成ByteBuf 写回到IO。 37 | 38 | 39 | ![](png/netty-architecture.png) 40 | 41 | ## Netty与Tomcat区别 42 | * tomcat就是针对http层的,要求实现servlet规范,所以我建议http还是选择tomcat(或者其他成熟的http-server),并不是说netty不好,而是你的选择问题。 43 | * netty是一个网络组件,tcp,udp,http都可以弄,但是官方文档都是些hello wolrd级别的。如果你非常了解http结构,完全可以基于netty搞出一个比tomcat牛的http server。如果做tcp开发,netty不二之选! 44 | Netty是基于Java NIO开发的,而Tomcat是Apache下的针对HTTP的服务器项目,前者更像一个中间件框架,后者更像一个工具 45 | 46 | # 引用 47 | * [netty与tomcat区别](https://blog.csdn.net/fqwgc8/article/details/50291781) 48 | * [tomcat 源码为啥不采用netty 处理并发?](https://www.zhihu.com/question/53498767) 49 | * [tomcat对keep-alive的实现逻辑](http://hongjiang.info/how-tomcat-implements-keep-alive/) -------------------------------------------------------------------------------- /plugins/nginx.md: -------------------------------------------------------------------------------- 1 | ### 学习计划 2 | * Nginx常用来干什么 3 | * Nginx实现动静分离 https://www.jianshu.com/p/037a088eca4f 4 | * [Nginx在CentOS中的安装](plugins/nginx.md##安装) 5 | * [Nginx反向代理服务器搭建](plugins/nginx.md) 6 | * [Nginx实现动静分离](plugins/nginx.md) 7 | 8 | ### 学习笔记 9 | * Nginx实现动静分离笔记 10 | 配置 11 | ``` 12 | #拦截静态资源 13 | location ~ .*\.(html|htm|gif|jpg|jpeg|bmp|png|ico|js|css)$ { 14 | root /Users/dalaoyang/Downloads/static; 15 | } 16 | ``` 17 | ``` 18 | 2020/01/16 16:56:06 [error] 32656#32656: *10 open() "/root/xxx/static/musicstore/static/js/jquery-3.4.1.min.js" failed (13: Permission denied), client: xx.xx.228.168, server: localhost, request: "GET /musicstore/static/js/jquery-3.4.1.min.js HTTP/1.1", host: "musicstore.anythy.cn", referrer: "http://musicstore.anythy.cn/musicstore/" 19 | ``` 20 | * 拦截的是监听端口下所有的符合规则的静态资源【能否拦截指定URL下的静态资源?】,从nginx日志中可以看到请求会按照url的路径在指定的静态资源文件夹下找到该文件,因此需要在static目录下按照url的规则建立。 21 | * 日志中出现了Permission denied的error,原因是nginx的进程用户是nginx,而我们创建的static文件夹路径的用户是root,因此需要修改用户。有两周方案,修改将ngix赋予static路径下所有文件及文件夹的可读权限,方案二修改nginx的进程用户`vim /etc/nginx/nginx.conf:`。应该采用方案一最小权限原则 22 | ``` 23 | # user www-data; 24 | user root; 25 | worker_processes auto; 26 | pid /run/nginx.pid; 27 | ``` 28 | 实践发现,Niginx用户是不能Login的,导致了如果不赋予其足够的权限,它是访问不了root创建的文件夹,可放入/tmp目录下,谁都能访问,同时设置改目录不被系统自动删除,具体怎么做参考linux笔记。 29 | 30 | ## 安装 31 | ### 官方推荐安装 32 | * http://nginx.org/en/linux_packages.html#stable 33 | * create the file named /etc/yum.repos.d/nginx.repo with the following contents: 34 | * [nginx] 35 | name=nginx repo 36 | baseurl=http://nginx.org/packages/centos/7/$basearch/ 37 | gpgcheck=0 38 | enabled=1 39 | * yum install nginx 40 | * nginx -V 41 | * 查看安装目录 rpm -ql nginx 42 | * 配置文件在 /etc/nginx/conf.d/default.conf 43 | * 启动 nginx 44 | * nginx -s signal : send signal to a master process: stop, quit, reopen, reload 45 | 46 | ### 源码编译安装 47 | 1. 安装编译工具及库文件 `yum -y install make zlib zlib-devel gcc-c++ libtool openssl openssl-devel` 48 | 2. 安装PCRE(可以使Nginx支持Rewrite功能) 49 | ```shell 50 | cd /usr/local/src/ 51 | wget http://downloads.sourceforge.net/project/pcre/pcre/8.35/pcre-8.35.tar.gz 52 | tar zxvf pcre-8.35.tar.gz 53 | cd pcre-8.35 54 | // 编译安装 55 | ./configure 56 | make && make install 57 | // 查看版本 58 | pcre-config --version 59 | ``` 60 | 3. 安装Nginx 61 | ```shell 62 | cd /usr/local/src/ 63 | wget http://nginx.org/download/nginx-1.6.2.tar.gz 64 | tar zxvf nginx-1.6.2.tar.gz 65 | cd nginx-1.6.2 66 | ./configure --prefix=/usr/local/webserver/nginx --with-http_stub_status_module --with-http_ssl_module --with-pcre=/usr/local/src/pcre-8.35 67 | make && make install 68 | /usr/local/webserver/nginx/sbin/nginx -v 69 | ``` 70 | 4. 配置Nginx 71 | * 创建Nginx运行的用户 www(目的是最小权限原则) 72 | ```shell 73 | /usr/sbin/groupadd www 74 | /usr/sbin/useradd -g www www 75 | ``` 76 | * 配置nginx.conf文件 77 | 78 | ```conf 79 | user www www; 80 | worker_processes 2; #设置值和CPU核心数一致 81 | error_log /usr/local/webserver/nginx/logs/nginx_error.log crit; #日志位置和日志级别 82 | pid /usr/local/webserver/nginx/nginx.pid; 83 | #Specifies the value for maximum file descriptors that can be opened by this process. 84 | worker_rlimit_nofile 65535; 85 | events 86 | { 87 | use epoll; 88 | worker_connections 65535; 89 | } 90 | http 91 | { 92 | include mime.types; 93 | default_type application/octet-stream; 94 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 95 | '$status $body_bytes_sent "$http_referer" ' 96 | '"$http_user_agent" $http_x_forwarded_for'; 97 | 98 | #charset gb2312; 99 | 100 | server_names_hash_bucket_size 128; 101 | client_header_buffer_size 32k; 102 | large_client_header_buffers 4 32k; 103 | client_max_body_size 8m; 104 | 105 | sendfile on; 106 | tcp_nopush on; 107 | keepalive_timeout 60; 108 | tcp_nodelay on; 109 | fastcgi_connect_timeout 300; 110 | fastcgi_send_timeout 300; 111 | fastcgi_read_timeout 300; 112 | fastcgi_buffer_size 64k; 113 | fastcgi_buffers 4 64k; 114 | fastcgi_busy_buffers_size 128k; 115 | fastcgi_temp_file_write_size 128k; 116 | gzip on; 117 | gzip_min_length 1k; 118 | gzip_buffers 4 16k; 119 | gzip_http_version 1.0; 120 | gzip_comp_level 2; 121 | gzip_types text/plain application/x-javascript text/css application/xml; 122 | gzip_vary on; 123 | 124 | #limit_zone crawler $binary_remote_addr 10m; 125 | #下面是server虚拟主机的配置 126 | server 127 | { 128 | listen 80;#监听端口 129 | server_name localhost;#域名 130 | index index.html index.htm index.php; 131 | root /usr/local/webserver/nginx/html;#站点目录 132 | location ~ .*\.(php|php5)?$ 133 | { 134 | #fastcgi_pass unix:/tmp/php-cgi.sock; 135 | fastcgi_pass 127.0.0.1:9000; 136 | fastcgi_index index.php; 137 | include fastcgi.conf; 138 | } 139 | location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|ico)$ 140 | { 141 | expires 30d; 142 | # access_log off; 143 | } 144 | location ~ .*\.(js|css)?$ 145 | { 146 | expires 15d; 147 | # access_log off; 148 | } 149 | access_log off; 150 | } 151 | 152 | } 153 | ``` 154 | * 检查nginx.conf的正确性 `/usr/local/webserver/nginx/sbin/nginx -t` 155 | * 启动Nginx `/usr/local/webserver/nginx/sbin/nginx` 156 | * IP地址访问站点,建议替换html内容,这样可以屏蔽网站的技术信息 157 | * 其他命令 158 | ```shell 159 | /usr/local/webserver/nginx/sbin/nginx -s reload # 重新载入配置文件 160 | /usr/local/webserver/nginx/sbin/nginx -s reopen # 重启 Nginx 161 | /usr/local/webserver/nginx/sbin/nginx -s stop # 停止 Nginx 162 | ``` 163 | ### Nginx通过域名转发请求 164 | ``` 165 | server { 166 | listen 80; 167 | server_name musicstore.anythy.cn; 168 | 169 | access_log /var/log/nginx/musicstore.host.access.log main; 170 | 171 | location /musicstore/ { 172 | proxy_set_header Host $host; 173 | proxy_set_header X-real-ip $remote_addr; 174 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 175 | proxy_pass http://xx.107.153.xx:8018/; 176 | } 177 | 178 | location ~ .*\.(jpg|jpeg|png|ico|js|css|gif)$ { 179 | root /tmp/static; 180 | } 181 | location s.anythy.cn.*\.(jpg|jpeg|png|ico|js|css|gif)$ { 182 | root /tmp/static; 183 | } 184 | } 185 | 186 | server { 187 | listen 80; 188 | server_name seckill.anythy.cn; 189 | 190 | access_log /var/log/nginx/musicstore.host.access.log main; 191 | 192 | location / { 193 | proxy_set_header Host $host; 194 | proxy_set_header X-real-ip $remote_addr; 195 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 196 | proxy_pass http://xx.107.153.xx:8019/; 197 | } 198 | } 199 | ``` -------------------------------------------------------------------------------- /plugins/png/Tomcat_Architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/png/Tomcat_Architecture.png -------------------------------------------------------------------------------- /plugins/png/amqp-topic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/png/amqp-topic.png -------------------------------------------------------------------------------- /plugins/png/jmeter-elements.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/png/jmeter-elements.png -------------------------------------------------------------------------------- /plugins/png/mybatis-architecture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/png/mybatis-architecture.jpg -------------------------------------------------------------------------------- /plugins/png/mybatis-level1-cache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/png/mybatis-level1-cache.png -------------------------------------------------------------------------------- /plugins/png/mybatis-level2-cache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/png/mybatis-level2-cache.png -------------------------------------------------------------------------------- /plugins/png/netty-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/png/netty-architecture.png -------------------------------------------------------------------------------- /plugins/png/redis-aof-append-block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/png/redis-aof-append-block.png -------------------------------------------------------------------------------- /plugins/png/redis-cluster-nodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/png/redis-cluster-nodes.png -------------------------------------------------------------------------------- /plugins/png/redis-cluster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/png/redis-cluster.png -------------------------------------------------------------------------------- /plugins/png/redis-cmd-lifecycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/png/redis-cmd-lifecycle.png -------------------------------------------------------------------------------- /plugins/png/redis-data-type-structure.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/png/redis-data-type-structure.PNG -------------------------------------------------------------------------------- /plugins/png/redis-full-reclipate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/png/redis-full-reclipate.png -------------------------------------------------------------------------------- /plugins/png/redis-part-replication.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/png/redis-part-replication.png -------------------------------------------------------------------------------- /plugins/png/zookeeper-distributed-lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/png/zookeeper-distributed-lock.png -------------------------------------------------------------------------------- /plugins/rabbitmq.md: -------------------------------------------------------------------------------- 1 | ### 目录 2 | * [RabbitMQ基础概念](http://note.youdao.com/noteshare?id=3ee2c852ecf09522bd0dd974921e415d) 3 | * [RabbitMQ消息发送-Exchange-fanout示例](https://github.com/zhonghuasheng/JAVA/tree/master/rabbitmq/src/main/java/com/zhonghuasheng/rabbitmq/fanout) 4 | * [RabbitMQ消息发送-Exchange-direct示例](https://github.com/zhonghuasheng/JAVA/tree/master/rabbitmq/src/main/java/com/zhonghuasheng/rabbitmq/direct) 5 | * [RabbitMQ消息发送-Exchange-topic示例](https://github.com/zhonghuasheng/JAVA/tree/master/rabbitmq/src/main/java/com/zhonghuasheng/rabbitmq/topic) 6 | * [RabbtiMQ延迟队列-消息延迟推送](https://www.cnblogs.com/haixiang/p/10966985.html) 7 | 8 | ### 学习计划 9 | * RabbitMQ的基本介绍 https://www.jianshu.com/p/79ca08116d57 10 | * Java 帝国之消息队列 http://note.youdao.com/noteshare?id=a143bb5e514f659bded19ae4322afea4&sub=wcp1579078065196472 11 | * 消息的推模式和拉模式 12 | * 消息的确认与拒绝 13 | * 过期时间 14 | * 死信队列 15 | * 延迟队列 16 | * 优先级队列 17 | * RPC实现 18 | * 持久化 19 | * 生产者确认的事务机制 20 | * 发送发确认机制 21 | * 消息传输的保障 22 | * RabbitMQ集群 23 | 24 | ### 学习笔记 25 | * 消息队列(Message Queue,简称MQ),从字面意思上看,本质是个队列,FIFO先入先出,只不过队列中存放的内容是message而已。其主要用途:不同进程Process/线程Thread之间通信。 26 | * 消息中间件(Message Queue Middleware,简称MQ)是指利用高效可靠的消息传递机制进行与平台无关的数据交流,并基于数据通信来进行分布式系统的集成。消息(Message)是指在应用间传送的数据。消息可以非常简单,比如只包含文本字符串,也可以更复杂,可能包含嵌入对象。消息队列(Message Queue)是一种应用间的通信方式,消息发送后可以立即返回,由消息系统来确保消息的可靠传递。消息发布者只管把消息发布到 MQ 中而不用管谁来取,消息使用者只管从 MQ 中取消息而不管是谁发布的。这样发布者和使用者都不用知道对方的存在。 27 | * 消息中间件的作用:解耦、冗余(存储)、扩张性、销峰、可恢复性、顺序保证、缓冲、异步通信 28 | 29 | ![](png/amqp-topic.png) 30 | * 基本概念 31 | * 生产者把消息发布到 Exchange 上,消息最终到达队列并被消费者接收,而 Binding 决定交换器的消息应该发送到那个队列。 32 | * Message:消息,消息是不具名的,它由消息头和消息体组成。消息体是不透明的,而消息头则由一系列的可选属性组成,这些属性包括routing-key(路由键)、priority(相对于其他消息的优先权)、delivery-mode(指出该消息可能需要持久性存储)等。 33 | * Publisher:消息的生产者,也是一个向交换器发布消息的客户端应用程序。 34 | * Exchange:交换器,用来接收生产者发送的消息并将这些消息路由给服务器中的队列。 35 | * Exchange分发消息时根据类型的不同分发策略有区别,目前共四种类型:direct、fanout、topic、headers 。 36 | * direct: 消息中的路由键(routing key)与Binding 中的 binding key完全一致,交换器就将消息发到对应的队列中。 37 | * fanout: fanout 交换器不处理路由键,只是简单的将队列绑定到交换器上,每个发送到交换器的消息都会被转发到与该交换器绑定的所有队列上。很像子网广播。 38 | * topic: topic 交换器通过模式匹配分配消息的路由键属性,将路由键和某个模式进行匹配,此时队列需要绑定到一个模式上。它将路由键和绑定键的字符串切分成单词,这些单词之间用点隔开。它同样也会识别两个通配符:符号“#”和符号“”。#匹配0个或多个单词,匹配不多不少一个单词。 39 | * Binding:绑定,用于消息队列和交换器之间的关联。一个绑定就是基于路由键将交换器和消息队列连接起来的路由规则,所以可以将交换器理解成一个由绑定构成的路由表。 40 | * Queue:消息队列,用来保存消息直到发送给消费者。它是消息的容器,也是消息的终点。一个消息可投入一个或多个队列。消息一直在队列里面,等待消费者连接到这个队列将其取走。 41 | * Connection:网络连接,比如一个TCP连接。 42 | * Channel:信道,多路复用连接中的一条独立的双向数据流通道。信道是建立在真实的TCP连接内地虚拟连接,AMQP 命令都是通过信道发出去的,不管是发布消息、订阅队列还是接收消息,这些动作都是通过信道完成。因为对于操作系统来说建立和销毁 TCP 都是非常昂贵的开销,所以引入了信道的概念,以复用一条 TCP 连接。 43 | * Consumer:消息的消费者,表示一个从消息队列中取得消息的客户端应用程序。 44 | * Virtual Host:虚拟主机,表示一批交换器、消息队列和相关对象。虚拟主机是共享相同的身份认证和加密环境的独立服务器域。每个 vhost 本质上就是一个 mini 版的 RabbitMQ 服务器,拥有自己的队列、交换器、绑定和权限机制。vhost 是 AMQP 概念的基础,必须在连接时指定,RabbitMQ 默认的 vhost 是 / 。 45 | * Broker:表示消息队列服务器实体。 46 | * 调用方实时依赖执行结果的业务场景,请使用调用,而不是MQ。 47 | 48 | 49 | 50 | # Part3客户端开发向导 51 | ## 连接RabbitMQ 52 | * Channel或者Connection中有个isOpen的方法用来检测是否已经处于开启状态,这个方法的返回值依赖于shutdownCause,有可能 53 | 54 | # Part4 RabbitMQ进阶 55 | ## mandatory/immediate参数,备份交换器 56 | * mandatory和immediate是channel.basicPublish方法中的两个参数,它们都有当消息传递过程中不可达目的地时将消息返回给生产者的功能。 57 | * RabbitMQ提供的备份交换器(Alternate Exchange)可以将未能被交换器路由的消息(没有绑定队列或者没有匹配的绑定)存储起来,而不用返回给客户端。 58 | 59 | ### mandatory 60 | * 当mandatory参数设为true时,交换器无法根据自身的类型和路由键找到一个符合条件的队列,那么RabbitMQ会调用Basic.Return命令将消息返回给生产者;为false时,如果出现上述情况,则消息直接被丢弃。那么生产者如何获取到没有被正确路由到合适队列的消息呢?这时候可以通过调用 61 | channel addReturnListener 来添加 ReturnListener 监昕器实现。 62 | 63 | ### immediate 64 | * 当参数告诉服务器如果该消息关联的队列上有消费者,则立刻投递; 如果所有匹配的队列上都没有消费者,则直接将消息返回给生产者,不用将消息存入队列而等待消费者了。RabbitMQ在3.0版本开始去掉了对immediate的支持,官方解释是此参数会影响镜像队列的性能,增加了代码的复杂度。 65 | 66 | ### 备份交换器 67 | * 备份交换器,英文名称为 Altemate Exchange ,简称AE,或者更直白地称之为"备胎交换器"。生产者在发送消息的时候如果不设置 mandatory 参数,那么消息在未被路由的情况下将会丢失;如果设置了 mandatory 参数,那么需要添加 ReturnListener 的编程逻辑,生产者的代码将变得复杂。如果既不想复杂化生产者的编程逻辑,又不想消息丢失,那么可以使用备份交换器,这样可以将未被路由的消息存储在 RabbitMQ 中,再在需要的时候去处理这些消息。 68 | 69 | # RabbitMQ消息的持久化 70 | https://www.cnblogs.com/bigberg/p/8195622.html 71 | ## 什么情况下会造成消息丢失? 72 | * 突然断电 73 | 74 | ## 哪些地方需要持久化 75 | ```java 76 | // 队列的持久化 durable=true 77 | channel.queueDeclare(QUEUE_NAME, true, false, false, null); 78 | String msg = "Hello World! 你好世界!"; 79 | // 消息的持久化 MessageProperties.PERSISTENT_TEXT_PLAIN 80 | channel.basicPublish("", QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN, msg.getBytes()); 81 | ``` 82 | 83 | ## 消息过载 84 | * Producer生产的message的速度和Consumer消费的message的速度不匹配 85 | 86 | ## 死信队列(DLX) 87 | ### 什么是死信队列 88 | DLX(dead-letter-exchange) 当消息在一个队列中变成死信之后,它会被重新publish到另外一个exchange中,这个exchange就是DLX. 89 | ### 死信队列产生的场景 90 | * 消息被拒绝(basic.reject / basic.nack),并且requeue = false 91 | * 消息因TTL过期 92 | * 队列达到最大长度 93 | 94 | ## 常用命令 95 | 96 | * List Queue 97 | ``` shell 98 | rabbitmqctl list_queues name messages messages_ready \ messages_unacknowledged 99 | ``` 100 | 101 | * Find Queue 102 | ``` 103 | rabbitmqctl list_queues| grep hello | awk '{print $1}' 104 | ``` 105 | 106 | * Delete Queue 107 | ``` 108 | rabbitmqctl delete_queue queueName 109 | ``` -------------------------------------------------------------------------------- /plugins/redis/redis-cas.md: -------------------------------------------------------------------------------- 1 | ## 面试题 2 | redis 的并发竞争问题是什么?如何解决这个问题?了解 redis 事务的 CAS 方案吗? 3 | 4 | ## 面试官心理分析 5 | 这个也是线上非常常见的一个问题,就是**多客户端同时并发写**一个 key,可能本来应该先到的数据后到了,导致数据版本错了;或者是多客户端同时获取一个 key,修改值之后再写回去,只要顺序错了,数据就错了。 6 | 7 | 而且 redis 自己就有天然解决这个问题的 CAS 类的乐观锁方案。 8 | 9 | ## 面试题剖析 10 | 某个时刻,多个系统实例都去更新某个 key。可以基于 zookeeper 实现分布式锁。每个系统通过 zookeeper 获取分布式锁,确保同一时间,只能有一个系统实例在操作某个 key,别人都不允许读和写。 11 | 12 | ![zookeeper-distributed-lock](../png/zookeeper-distributed-lock.png) 13 | 14 | 你要写入缓存的数据,都是从 mysql 里查出来的,都得写入 mysql 中,写入 mysql 中的时候必须保存一个时间戳,从 mysql 查出来的时候,时间戳也查出来。 15 | 16 | 每次要**写之前,先判断**一下当前这个 value 的时间戳是否比缓存里的 value 的时间戳要新。如果是的话,那么可以写,否则,就不能用旧的数据覆盖新的数据。 -------------------------------------------------------------------------------- /plugins/redis/redis-rdb-aof分析.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/redis/redis-rdb-aof分析.md -------------------------------------------------------------------------------- /plugins/redis/redis命令执行分析.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/redis/redis命令执行分析.md -------------------------------------------------------------------------------- /plugins/redis/redis基础数据类型及使用场景.md: -------------------------------------------------------------------------------- 1 | ## Redis基础数据类型 2 | Redis包含`String`、`Hash`、`List`、`Set`、`ZSet`、`Stream`、`Bitmap`、`HLL`、`GEO`、`Bitfield`这些数据类型 3 | 4 | String 5 | ------ 6 | * 简单动态字符串(simple dynamic string, SDS)Redis没有直接使用C语言的传统字符串表示,而是自己构建了一种名为简单动态字符串(Simple Dynamic String, SDS)的抽象类型,并将SDS用作Redis的默认字符串表示。 7 | * String底层对应的数据结构是SDS,有好几个结构体,大致在往db插入值前,会判断value的长度,然后决定使用哪个结构体来存值 8 | ```shell 9 | struct __attribute__ ((__packed__)) sdshdr8 { 10 | uint8_t len; /* used */ hdr5已经不足以描述数据长度了,定义一个8bit的 len来描述 2^5 - 2^8 - 1的字符创长度 11 | uint8_t alloc; /* excluding the header and null terminator */ 12 | /**已分配的总长度, 用于对已存在的字符串追加的场景,3.2之前叫free 13 | * 比如 set a luke01, len=6, 那最开始分给我的时候是字符创长度的2倍,12,现在我要追加 xx,变为luke01xx,就不用重新分配空间,而是在 14 | * 现有的字符数组追加元素即可,通过空间预分配,极大程度的解决了内存分配产生的问题(碎片等) 15 | * 作者为啥这么做,据说是因为大家使用redis极大部分存的值都是字符串,但是我觉得append命令我用的不多 16 | * **/ 17 | unsigned char flags; /* 3 lsb of type, 5 unused bits */ 18 | char buf[]; //SDS遵循C字符串以空字符结尾的惯例 19 | }; 20 | struct __attribute__ ((__packed__)) sdshdr64 { 21 | uint64_t len; /* used */ 22 | uint64_t alloc; /* excluding the header and null terminator */ 23 | unsigned char flags; /* 3 lsb of type, 5 unused bits */ 24 | char buf[]; 25 | }; 26 | ``` 27 | * SDS相比C语言字符创具有以下优点: 28 | 1. 获取字符串长度的复杂度为O(1)。C语言并不记录自身的长度信息,所以为了获取一个C字符串的长度,要遍历整个字符数组,但是SDS会记录字符长度,可以通过len直接在内存中拿取到整块的数据。 29 | 2. 杜绝缓存溢出。除了获取字符串长度的复杂度高之外,C字符串不记录自身长度带来的另外一个问题是容易造成缓冲区溢出(buffer overflow)。SDS在赋值前会判断剩余的长度,如果长度不够了,就会重新分配空间。 30 | 3. 减少修改字符串长度时所需的内存重分配的次数。C语言中每次值的修改都会触发内存重新分配,SDS通过空间预分配和记录剩余字节数量free来减少字符串append(追加)造成的内存重分配,同时通过惰性删除来减少字符串缩短的操作造成的内存重分配。 31 | * 通过未使用空间,SDS实现了空间预分配和惰性空间释放两种优化策略 32 | * 空间预分配: 空间预分配用于优化SDS的字符串增长操作:当SDS的API对一个SDS进行修改,并且需要对SDS进行空间扩展的时候,程序不仅会为SDS分配修改所必须的空间,还会为SDS分配额外的未使用空间。通过空间预分配策略,Redis可以减少连续执行字符串增长操作所需的内存重分配次数。 33 | * 惰性空间释放:惰性空间释放用于优化SDS的字符串缩短操作:当SDS的API需要缩短SDS保存的字符串时,程序并不立即使用内存重分配来回收缩短后多出来的字节,而是可以通过alloc-len来计算未使用的长度,并等待将来使用。3.2之前有个free属性记录剩余长度,3.2之后改为alloc记录总长度。 34 | 4. 二进制安全。SDS以二进制的方式处理buf数组中的数据,写的时候是什么样,读的时候也是什么样。即使写入\0也能正常读出来 35 | 5. 兼容部分C字符串函数。遵循C字符串以空字符结尾的惯例 36 | * `String`使用场景 37 | * Redis String可以包含任何数据,最大能存储512M 38 | * 可以用在计数器/分布式锁/session 39 | -------------------------------------------------------------------------------- /plugins/redis/redis常用客户端使用总结.md: -------------------------------------------------------------------------------- 1 | * 引用 https://blog.csdn.net/w1014074794/article/details/88827946 2 | 3 | 4 | 首先,在spring boot2之后,对redis连接的支持,默认就采用了lettuce。这就一定程度说明了lettuce 和Jedis的优劣。 5 | 6 | ### 概念: 7 | * Jedis:是老牌的Redis的Java实现客户端,提供了比较全面的Redis命令的支持 8 | * Redisson:实现了分布式和可扩展的Java数据结构 9 | * Lettuce:高级Redis客户端,用于线程安全同步,异步和响应使用,支持集群,Sentinel,管道和编码器 10 | 11 | ### 优点: 12 | * Jedis:比较全面的提供了Redis的操作特性 13 | * Redisson:促使使用者对Redis的关注分离,提供很多分布式相关操作服务,例如,分布式锁,分布式集合,可通过Redis支持延迟队列 14 | * Lettuce:基于Netty框架的事件驱动的通信层,其方法调用是异步的。Lettuce的API是线程安全的,所以可以操作单个Lettuce连接来完成各种操作 15 | 16 | > 可伸缩: 17 | * Jedis:使用阻塞的I/O,且其方法调用都是同步的,程序流需要等到sockets处理完I/O才能执行,不支持异步。Jedis客户端实例不是线程安全的,所以需要通过连接池来使用Jedis 18 | * Redisson:基于Netty框架的事件驱动的通信层,其方法调用是异步的。Redisson的API是线程安全的,所以可以操作单个Redisson连接来完成各种操作 19 | * Lettuce:基于Netty框架的事件驱动的通信层,其方法调用是异步的。Lettuce的API是线程安全的,所以可以操作单个Lettuce连接来完成各种操作 20 | 21 | * lettuce能够支持redis4,需要java8及以上。 22 | * lettuce是基于netty实现的与redis进行同步和异步的通信。 23 | 24 | ### lettuce和jedis比较: 25 | * jedis使直接连接redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个jedis实例增加物理连接 26 | * lettuce的连接是基于Netty的,连接实例(StatefulRedisConnection)可以在多个线程间并发访问,StatefulRedisConnection是线程安全的,所以一个连接实例可以满足多线程环境下的并发访问,当然这也是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例。 27 | * Redisson实现了分布式和可扩展的Java数据结构,和Jedis相比,功能较为简单,不支持字符串操作,不支持排序、事务、管道、分区等Redis特性。Redisson的宗旨是促进使用者对Redis的关注分离,从而让使用者能够将精力更集中地放在处理业务逻辑上。 28 | 29 | 总结: 30 | 优先使用Lettuce,如果需要分布式锁,分布式集合等分布式的高级特性,添加Redisson结合使用,因为Redisson本身对字符串的操作支持很差。 31 | -------------------------------------------------------------------------------- /plugins/redis/redis整体架构分析.md: -------------------------------------------------------------------------------- 1 | ## Redis整体架构分析 2 | 3 | 如下是我学习redis及阅读源码,总结的redis整体架构图 4 | 5 | ![](http://r3rutcmq2.hd-bkt.clouddn.com//github01-redis-architecture.PNG) 6 | 7 | 我认为Redis架构包含四个模块 `网络模型`、`线程模型`、`持久化模型`、`数据结构`。其中`网络模型`使用的是IO多路复用;`线程模型`是对读写采用单线程,其他地方有使用多线程,Redis6.0提出的多线程是对网络的读写采用多线程的方式,核心的cmd的操作还是单线程;`持久化模型`指的是RDB和AOF;`数据结构`需要强调一下,Redis的数据结构是经过精心设计的。 8 | 9 | ## Redis源码目录文件分析 10 | 11 | Redis的作者在readme中进行了较为详细的介绍,全文2W多字,系统的描述了Redis的设计理念和关键的源码文件。 12 | * `deps` 依赖的第三方库 13 | * `src` 源码文件 14 | * `db.c` 读取插入值逻辑 15 | * `server.c` redis服务器启动,初始化配置 16 | * `server.h` 结构体 redisServer,redisDb,client,redisObject 记录了redis服务器,数据库,客户端的信息 17 | * `dict.h` 字典结构体dict,还有其中的dictht, dictEntry 18 | * `t_*.h` t_开头的文件是redis底层的数据结构 19 | * `networking.c` 是处理网络I/O的 20 | * `object.c` 封装了对redisObject的操作 21 | 22 | ## Redis数据类型及底层数据结构 23 | 24 | ![](http://r3rutcmq2.hd-bkt.clouddn.com//github02-redis-data-type.PNG) 25 | 26 | ![](http://r3rutcmq2.hd-bkt.clouddn.com/01-redis-data-structure.PNG) -------------------------------------------------------------------------------- /plugins/redis/redis服务器启动.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/redis/redis服务器启动.md -------------------------------------------------------------------------------- /plugins/redis/redis网络模型分析.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/plugins/redis/redis网络模型分析.md -------------------------------------------------------------------------------- /plugins/redis/redis过期策略.md: -------------------------------------------------------------------------------- 1 | ## 面试题 2 | redis 的过期策略都有哪些?内存淘汰机制都有哪些?手写一下 LRU 代码实现? 3 | 4 | ## 面试官心理分析 5 | 如果你连这个问题都不知道,上来就懵了,回答不出来,那线上你写代码的时候,想当然的认为写进 redis 的数据就一定会存在,后面导致系统各种 bug,谁来负责? 6 | 7 | 常见的有两个问题: 8 | - 往 redis 写入的数据怎么没了? 9 | 10 | 可能有同学会遇到,在生产环境的 redis 经常会丢掉一些数据,写进去了,过一会儿可能就没了。我的天,同学,你问这个问题就说明 redis 你就没用对啊。redis 是缓存,你给当存储了是吧? 11 | 12 | 啥叫缓存?用内存当缓存。内存是无限的吗,内存是很宝贵而且是有限的,磁盘是廉价而且是大量的。可能一台机器就几十个 G 的内存,但是可以有几个 T 的硬盘空间。redis 主要是基于内存来进行高性能、高并发的读写操作的。 13 | 14 | 那既然内存是有限的,比如 redis 就只能用 10G,你要是往里面写了 20G 的数据,会咋办?当然会干掉 10G 的数据,然后就保留 10G 的数据了。那干掉哪些数据?保留哪些数据?当然是干掉不常用的数据,保留常用的数据了。 15 | 16 | - 数据明明过期了,怎么还占用着内存? 17 | 18 | 这是由 redis 的过期策略来决定。 19 | 20 | ## 面试题剖析 21 | ### redis 过期策略 22 | redis 过期策略是:**定期删除+惰性删除**。 23 | 24 | 所谓**定期删除**,指的是 redis 默认是每隔 100ms 就随机抽取一些设置了过期时间的 key,检查其是否过期,如果过期就删除。 25 | 26 | 假设 redis 里放了 10w 个 key,都设置了过期时间,你每隔几百毫秒,就检查 10w 个 key,那 redis 基本上就死了,cpu 负载会很高的,消耗在你的检查过期 key 上了。注意,这里可不是每隔 100ms 就遍历所有的设置过期时间的 key,那样就是一场性能上的**灾难**。实际上 redis 是每隔 100ms **随机抽取**一些 key 来检查和删除的。 27 | 28 | 但是问题是,定期删除可能会导致很多过期 key 到了时间并没有被删除掉,那咋整呢?所以就是惰性删除了。这就是说,在你获取某个 key 的时候,redis 会检查一下 ,这个 key 如果设置了过期时间那么是否过期了?如果过期了此时就会删除,不会给你返回任何东西。 29 | 30 | > 获取 key 的时候,如果此时 key 已经过期,就删除,不会返回任何东西。 31 | 32 | 但是实际上这还是有问题的,如果定期删除漏掉了很多过期 key,然后你也没及时去查,也就没走惰性删除,此时会怎么样?如果大量过期 key 堆积在内存里,导致 redis 内存块耗尽了,咋整? 33 | 34 | 答案是:**走内存淘汰机制**。 35 | 36 | ### 内存淘汰机制 37 | redis 内存淘汰机制有以下几个: 38 | - noeviction: 当内存不足以容纳新写入数据时,新写入操作会报错,这个一般没人用吧,实在是太恶心了。 39 | - **allkeys-lru**:当内存不足以容纳新写入数据时,在**键空间**中,移除最近最少使用的 key(这个是**最常用**的)。 40 | - allkeys-random:当内存不足以容纳新写入数据时,在**键空间**中,随机移除某个 key,这个一般没人用吧,为啥要随机,肯定是把最近最少使用的 key 给干掉啊。 41 | - volatile-lru:当内存不足以容纳新写入数据时,在**设置了过期时间的键空间**中,移除最近最少使用的 key(这个一般不太合适)。 42 | - volatile-random:当内存不足以容纳新写入数据时,在**设置了过期时间的键空间**中,**随机移除**某个 key。 43 | - volatile-ttl:当内存不足以容纳新写入数据时,在**设置了过期时间的键空间**中,有**更早过期时间**的 key 优先移除。 44 | 45 | ### 手写一个 LRU 算法 46 | 你可以现场手写最原始的 LRU 算法,那个代码量太大了,似乎不太现实。 47 | 48 | 不求自己纯手工从底层开始打造出自己的 LRU,但是起码要知道如何利用已有的 JDK 数据结构实现一个 Java 版的 LRU。 49 | 50 | ```java 51 | class LRUCache extends LinkedHashMap { 52 | private final int CACHE_SIZE; 53 | 54 | /** 55 | * 传递进来最多能缓存多少数据 56 | * 57 | * @param cacheSize 缓存大小 58 | */ 59 | public LRUCache(int cacheSize) { 60 | // true 表示让 linkedHashMap 按照访问顺序来进行排序,最近访问的放在头部,最老访问的放在尾部。 61 | super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true); 62 | CACHE_SIZE = cacheSize; 63 | } 64 | 65 | @Override 66 | protected boolean removeEldestEntry(Map.Entry eldest) { 67 | // 当 map中的数据量大于指定的缓存个数的时候,就自动删除最老的数据。 68 | return size() > CACHE_SIZE; 69 | } 70 | } 71 | ``` -------------------------------------------------------------------------------- /plugins/redis/如何保证缓存和数据库的双写一致性.md: -------------------------------------------------------------------------------- 1 | ## 面试题 2 | 如何保证缓存与数据库的双写一致性? 3 | 4 | ## 面试官心理分析 5 | 你只要用缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就一定会有数据一致性的问题,那么你如何解决一致性问题? 6 | 7 | ## 面试题剖析 8 | 一般来说,如果允许缓存可以稍微的跟数据库偶尔有不一致的情况,也就是说如果你的系统**不是严格要求** “缓存+数据库” 必须保持一致性的话,最好不要做这个方案,即:**读请求和写请求串行化**,串到一个**内存队列**里去。 9 | 10 | 串行化可以保证一定不会出现不一致的情况,但是它也会导致系统的吞吐量大幅度降低,用比正常情况下多几倍的机器去支撑线上的一个请求。 11 | 12 | ### Cache Aside Pattern 13 | 最经典的缓存+数据库读写的模式,就是 Cache Aside Pattern。 14 | - 读的时候,先读缓存,缓存没有的话,就读数据库,然后取出数据后放入缓存,同时返回响应。 15 | - 更新的时候,**先更新数据库,然后再删除缓存**。 16 | 17 | **为什么是删除缓存,而不是更新缓存?** 18 | 19 | 原因很简单,很多时候,在复杂点的缓存场景,缓存不单单是数据库中直接取出来的值。 20 | 21 | 比如可能更新了某个表的一个字段,然后其对应的缓存,是需要查询另外两个表的数据并进行运算,才能计算出缓存最新的值的。 22 | 23 | 另外更新缓存的代价有时候是很高的。是不是说,每次修改数据库的时候,都一定要将其对应的缓存更新一份?也许有的场景是这样,但是对于**比较复杂的缓存数据计算的场景**,就不是这样了。如果你频繁修改一个缓存涉及的多个表,缓存也频繁更新。但是问题在于,**这个缓存到底会不会被频繁访问到?** 24 | 25 | 举个栗子,一个缓存涉及的表的字段,在 1 分钟内就修改了 20 次,或者是 100 次,那么缓存更新 20 次、100 次;但是这个缓存在 1 分钟内只被读取了 1 次,有**大量的冷数据**。实际上,如果你只是删除缓存的话,那么在 1 分钟内,这个缓存不过就重新计算一次而已,开销大幅度降低。**用到缓存才去算缓存。** 26 | 27 | 其实删除缓存,而不是更新缓存,就是一个 lazy 计算的思想,不要每次都重新做复杂的计算,不管它会不会用到,而是让它到需要被使用的时候再重新计算。像 mybatis,hibernate,都有懒加载思想。查询一个部门,部门带了一个员工的 list,没有必要说每次查询部门,都里面的 1000 个员工的数据也同时查出来啊。80% 的情况,查这个部门,就只是要访问这个部门的信息就可以了。先查部门,同时要访问里面的员工,那么这个时候只有在你要访问里面的员工的时候,才会去数据库里面查询 1000 个员工。 28 | 29 | ### 最初级的缓存不一致问题及解决方案 30 | 问题:先更新数据库,再删除缓存。如果删除缓存失败了,那么会导致数据库中是新数据,缓存中是旧数据,数据就出现了不一致。 31 | 32 | ![redis-junior-inconsistent](/images/redis-junior-inconsistent.png) 33 | 34 | 解决思路:先删除缓存,再更新数据库。如果数据库更新失败了,那么数据库中是旧数据,缓存中是空的,那么数据不会不一致。因为读的时候缓存没有,所以去读了数据库中的旧数据,然后更新到缓存中。 35 | 36 | ### 比较复杂的数据不一致问题分析 37 | 数据发生了变更,先删除了缓存,然后要去修改数据库,此时还没修改。一个请求过来,去读缓存,发现缓存空了,去查询数据库,**查到了修改前的旧数据**,放到了缓存中。随后数据变更的程序完成了数据库的修改。完了,数据库和缓存中的数据不一样了... 38 | 39 | **为什么上亿流量高并发场景下,缓存会出现这个问题?** 40 | 41 | 只有在对一个数据在并发的进行读写的时候,才可能会出现这种问题。其实如果说你的并发量很低的话,特别是读并发很低,每天访问量就 1 万次,那么很少的情况下,会出现刚才描述的那种不一致的场景。但是问题是,如果每天的是上亿的流量,每秒并发读是几万,每秒只要有数据更新的请求,就**可能会出现上述的数据库+缓存不一致的情况**。 42 | 43 | **解决方案如下:** 44 | 45 | 更新数据的时候,根据**数据的唯一标识**,将操作路由之后,发送到一个 jvm 内部队列中。读取数据的时候,如果发现数据不在缓存中,那么将重新读取数据+更新缓存的操作,根据唯一标识路由之后,也发送同一个 jvm 内部队列中。 46 | 47 | 一个队列对应一个工作线程,每个工作线程**串行**拿到对应的操作,然后一条一条的执行。这样的话,一个数据变更的操作,先删除缓存,然后再去更新数据库,但是还没完成更新。此时如果一个读请求过来,没有读到缓存,那么可以先将缓存更新的请求发送到队列中,此时会在队列中积压,然后同步等待缓存更新完成。 48 | 49 | 这里有一个**优化点**,一个队列中,其实**多个更新缓存请求串在一起是没意义的**,因此可以做过滤,如果发现队列中已经有一个更新缓存的请求了,那么就不用再放个更新请求操作进去了,直接等待前面的更新操作请求完成即可。 50 | 51 | 待那个队列对应的工作线程完成了上一个操作的数据库的修改之后,才会去执行下一个操作,也就是缓存更新的操作,此时会从数据库中读取最新的值,然后写入缓存中。 52 | 53 | 如果请求还在等待时间范围内,不断轮询发现可以取到值了,那么就直接返回;如果请求等待的时间超过一定时长,那么这一次直接从数据库中读取当前的旧值。 54 | 55 | 高并发的场景下,该解决方案要注意的问题: 56 | 57 | - 读请求长时阻塞 58 | 59 | 由于读请求进行了非常轻度的异步化,所以一定要注意读超时的问题,每个读请求必须在超时时间范围内返回。 60 | 61 | 该解决方案,最大的风险点在于说,**可能数据更新很频繁**,导致队列中积压了大量更新操作在里面,然后**读请求会发生大量的超时**,最后导致大量的请求直接走数据库。务必通过一些模拟真实的测试,看看更新数据的频率是怎样的。 62 | 63 | 另外一点,因为一个队列中,可能会积压针对多个数据项的更新操作,因此需要根据自己的业务情况进行测试,可能需要**部署多个服务**,每个服务分摊一些数据的更新操作。如果一个内存队列里居然会挤压 100 个商品的库存修改操作,每隔库存修改操作要耗费 10ms 去完成,那么最后一个商品的读请求,可能等待 10 * 100 = 1000ms = 1s 后,才能得到数据,这个时候就导致**读请求的长时阻塞**。 64 | 65 | 一定要做根据实际业务系统的运行情况,去进行一些压力测试,和模拟线上环境,去看看最繁忙的时候,内存队列可能会挤压多少更新操作,可能会导致最后一个更新操作对应的读请求,会 hang 多少时间,如果读请求在 200ms 返回,如果你计算过后,哪怕是最繁忙的时候,积压 10 个更新操作,最多等待 200ms,那还可以的。 66 | 67 | **如果一个内存队列中可能积压的更新操作特别多**,那么你就要**加机器**,让每个机器上部署的服务实例处理更少的数据,那么每个内存队列中积压的更新操作就会越少。 68 | 69 | 其实根据之前的项目经验,一般来说,数据的写频率是很低的,因此实际上正常来说,在队列中积压的更新操作应该是很少的。像这种针对读高并发、读缓存架构的项目,一般来说写请求是非常少的,每秒的 QPS 能到几百就不错了。 70 | 71 | 我们来**实际粗略测算一下**。 72 | 73 | 如果一秒有 500 的写操作,如果分成 5 个时间片,每 200ms 就 100 个写操作,放到 20 个内存队列中,每个内存队列,可能就积压 5 个写操作。每个写操作性能测试后,一般是在 20ms 左右就完成,那么针对每个内存队列的数据的读请求,也就最多 hang 一会儿,200ms 以内肯定能返回了。 74 | 75 | 经过刚才简单的测算,我们知道,单机支撑的写 QPS 在几百是没问题的,如果写 QPS 扩大了 10 倍,那么就扩容机器,扩容 10 倍的机器,每个机器 20 个队列。 76 | 77 | - 读请求并发量过高 78 | 79 | 这里还必须做好压力测试,确保恰巧碰上上述情况的时候,还有一个风险,就是突然间大量读请求会在几十毫秒的延时 hang 在服务上,看服务能不能扛的住,需要多少机器才能扛住最大的极限情况的峰值。 80 | 81 | 但是因为并不是所有的数据都在同一时间更新,缓存也不会同一时间失效,所以每次可能也就是少数数据的缓存失效了,然后那些数据对应的读请求过来,并发量应该也不会特别大。 82 | 83 | - 多服务实例部署的请求路由 84 | 85 | 可能这个服务部署了多个实例,那么必须**保证**说,执行数据更新操作,以及执行缓存更新操作的请求,都通过 Nginx 服务器**路由到相同的服务实例上**。 86 | 87 | 比如说,对同一个商品的读写请求,全部路由到同一台机器上。可以自己去做服务间的按照某个请求参数的 hash 路由,也可以用 Nginx 的 hash 路由功能等等。 88 | 89 | - 热点商品的路由问题,导致请求的倾斜 90 | 91 | 万一某个商品的读写请求特别高,全部打到相同的机器的相同的队列里面去了,可能会造成某台机器的压力过大。就是说,因为只有在商品数据更新的时候才会清空缓存,然后才会导致读写并发,所以其实要根据业务系统去看,如果更新频率不是太高的话,这个问题的影响并不是特别大,但是的确可能某些机器的负载会高一些。 -------------------------------------------------------------------------------- /plugins/rocketmq.md: -------------------------------------------------------------------------------- 1 | ## 学习笔记 2 | - [RocketMQ相比其他MQ的优势特性](#RocketMQ相比其他MQ的优势特性) 3 | - [RocketMQ安装,启动,基础实例](#http://rocketmq.apache.org/docs/quick-start/) 4 | - [RocketMQ与SpringBoot集成基础示例](https://github.com/zhonghuasheng/JAVA/tree/master/springboot/springboot-rocketmq/src/test/java/com/springboot/rocketmq) 5 | - [RocketMQ顺序消息](http://note.youdao.com/noteshare?id=7e23b1b1e3842a06862f6d06184e4466&sub=FB7D72F268AE453BA750B846BC2DAAB0) 6 | - [RocketMQ如何保证消息的可靠性](https://blog.csdn.net/qq_38545713/article/details/104758104) 7 | ## 实战技巧 8 | * 常用命令 9 | ```cmd 10 | start mqnamesrv.cmd 11 | start mqbroker.cmd -n 127.0.0.1:9876 autoCreateTopicEnable=true -c ../conf/broker.conf 12 | ``` 13 | * 使用官方下载的rocketmq,直接启动,是可以使用ip地址访问,一旦配置了conf/broker.conf,并启动了,就需要配置里面的brokerIP1,不然使用ip访问不了,总之,建议使用配置文件启动 14 | 15 | ## 百问 16 | 17 | ### RocketMQ的主要特点 18 | 19 | ### RocketMQ相比其他MQ的优势特性 20 | 目前主流的MQ主要是Rocketmq、kafka、Rabbitmq,Rocketmq相比于Rabbitmq、kafka具有主要优势特性有: 21 | * 支持事务型消息(消息发送和DB操作保持两方的最终一致性,rabbitmq和kafka不支持) 22 | * 支持结合rocketmq的多个系统之间数据最终一致性(多方事务,二方事务是前提) 23 | * 支持18个级别的延迟消息(rabbitmq和kafka不支持) 24 | * 支持指定次数和时间间隔的失败消息重发(kafka不支持,rabbitmq需要手动确认) 25 | * 支持consumer端tag过滤,减少不必要的网络传输(rabbitmq和kafka不支持) 26 | * 支持重复消费(rabbitmq不支持,kafka支持) 27 | 28 | ### RocketMQ各部分角色介绍 29 | RocketMQ由四部分组成,先来直观地了解一下这些角色以及各自的功能。分布式消息队列是用来高效地传输消息的,它的功能和现实生活中的邮局收发信件很类似,我们类比一下相应的模块 现实生活中的邮政系统要正常运行,离不开下面这四个角色,一是发信者,二是收信者,三是负责暂存、传输的邮局,四是负责协调各个地方邮局的管理机构 对应到 RocketMQ 中,这四个角色就是 Producer、Consumer、Broker、NameServer。 30 | 启动 RocketMQ 的顺序是先启动NameServer,再启动Broker,这时候消息队列已经可以提供服务了,想发送消息就使用Producer来发送,想接收消息就使用Consumer来接收。 31 | 了解了四种角色以后再介绍Topic、Message Queue 这两个名词。一个分布式消息队列中间件部署好以后,可以给很多个业务提供服务,同一个业务也有不同类型的消息要投递,这些不同类型的消息以不同的Topic名称来区分。所以发送和接收消息前,先创建Topic,针对某个Topic发送和接收消。有了Topic以后,还需要解决性能问题,如果一个Topic发送和接收的数据量非常大,需要能支持增加并行处理的机器来提高处理速度,这时候一个Topic可以根据需求设置一个或多个Message Queue, Message Queue类似分区或Partition。Topic有了多个Message Queue 后,消息可以并行地向各个Message Queue发送,消费者也可以并行地从多个Message Queue 读取消息并消费。 32 | 33 | `NameServer` 34 | 对于一个消息队列集群来说,系统由很多台机器组成,每个机器的角色、 IP 地址都不相同,而且这些信息是变动的。在这种情况下, 如果一个新的Producer Consumer 加入 ,怎么配置连接信息呢? NameServer 的存在主要是为了解决这类问题,由 NameServer 维护这些配置信息、状态信息,其他角色都通过 NameServer 来协同执行。 35 | NameServer 是整个消息队列中的状态服务器,集群的各个组件通过它来了解全局的信息 同时午,各个角色的机器都要定期 NameServer 上报自己的状态,超时不上报的话, NameServer 认为某个机器出故障不可用了,其他的组件会把这个机器从可用列表里移除。NamServer 可以部署多个,相互之间独立,其他角色同时向多个 NameServer机器上报状态信息,从而达到热备份的目的 NameServer 本身是无状态的,也就是说 NameServer 中的 Broker Topic 等状态信息不会持久存储,都是由各个角色定时上报并存储到内存中的(NameServer 支持配置参数的持 化,一般用不到) 36 | 37 | ### 异常 38 | 1. RocketMQ在windows下broker启动失败解决方法 39 | ``` 40 | 今天RocketMQ所在的电脑意外关机了,重启后怎么都启动不了broker,研究了好久才发现解决办法 41 | 其实很简单 42 | 把c:/user/你的用户名/里面的store里面的所有文件全部删除,再启动,成功 43 | ``` 44 | -------------------------------------------------------------------------------- /plugins/tomcat.md: -------------------------------------------------------------------------------- 1 | ### 学习计划 2 | 3 | ### 学习笔记 4 | * [Tomcat服务器架构](plugins/一张图了解Tomcat架构.md) 5 | * [Tomcat如何处理一个请求](plugins/一张图了解Tomcat架构.md) 6 | * [Tomcat安全配置建议](https://github.com/zhonghuasheng/Tutorial/wiki/Tomcat%E5%AE%89%E5%85%A8%E9%85%8D%E7%BD%AE) 7 | * [Tomcat Access日志分析](shell/linux命令在tomcat日志中的应用.md) 8 | * [Tomcat Nio理解](https://www.jianshu.com/p/76ff17bc6dea) 9 | 10 | ### 优化 11 | 1. enableLookup默认为true,修改为false,这个是禁止DNS反向查询IP,tomcat中有个access_log用于记录哪个IP访问了哪个url,项目初期时我们是可以开启这个配置,干什么呢?第一是统计访问最多的请求落在了哪些地方,帮助我们发现问题。第二是统计出来的IP地址可以大致统计出请求来自的区域,这对于云部署时选择服务器的region提供依据。 -------------------------------------------------------------------------------- /plugins/一张图了解Tomcat架构.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | ### 一张图了解Tomcat架构 4 | 5 |
6 | 7 | ![Tomcat Architecture](png/Tomcat_Architecture.png) 8 | 9 | * Server 10 | ``` 11 | Server是Tomcat的最顶层结构,包含多个service,server控制着整个Tomcat的生命周期。 12 | ``` 13 | 14 | * Service 15 | ``` 16 | 一个Service由多个Connector和一个Container组成,形成一个独立完整的处理单元,负责对外提供服务。一般情况下,我们只需要配置一个service就可以,tomcat默认配置了Cataline这个service(conf/server.xml ) 17 | ``` 18 | * Connector: 19 | ``` 20 | Connector负责把接收到的请求解析出来然后封装成request和response对象,然后交给Container处理。 21 | ``` 22 | * Container: 23 | ``` 24 | 一个Service只有一个Container 25 | ``` 26 | * Engine 27 | ``` 28 | 一个Container只有一个Engine,代表了一个完整的Servlet引擎,它接收来自Connector的请求,并决定传给哪个Host来处理,Host处理完请求后,将结果返回给Engine,Engine再将结果返回给Connector。 29 | ``` 30 | * Host 31 | ``` 32 | 一个Engine可以包含多个Host,每个Host代表一个虚拟主机,这个虚拟主机的作用就是运行多个应用,它负责安装和展开这些应用,并且标识这个应用以便能够区分它们,每个虚拟机对应了一个域名,不同Host容器接收处理对应的域名的请求 33 | ``` 34 | ``` 35 | 36 | ``` 37 | * Context 38 | ``` 39 | Host可以包含多个Context,Context是Servlet规范的实现,它提供了Servlet的基本环境,一个Context代表一个运行在Host上的Web应用 40 | ``` 41 | * Wrapper 42 | ``` 43 | Context可以包含多个Wrapper, Wrapper 代表一个 Servlet,它负责管理一个 Servlet,包括的 Servlet 的装载、初始化、执行以及资源回收。Wrapper 是最底层的容器,它没有子容器了,所以调用它的 addChild 将会报错。 44 | ``` 45 | * Loging: 46 | ``` 47 | 当一个容器里面装了logger组件后, 这个容器里所发生的事情, 就被该组件记录下来, 我们通常会在logs/ 这个目录下看见catalina_log.time.txt 以及localhost.time.txt和localhost_examples_log.time.txt。 这就是因为我们分别为:engin, host以及context(examples)这三个容器安装了logger组件, 这也是默认安装, 又叫做标配 48 | ``` 49 | * Loader: 50 | ``` 51 | loader这个组件通常只会给我们的context容器使用,loader是用来启动context以及管理这个context的classloader用的 52 | ``` 53 | * pipline: 54 | ``` 55 | pipeline是这样一个东西,使用的责任链模式.  当一个容器决定了要把从上级传递过来的需求交给子容器的时候, 他就把这个需求放进容器的管道(pipeline)里面去。 而需求傻呼呼得在管道里面流动的时候, 就会被管道里面的各个阀门拦截下来。 比如管道里面放了两个阀门。 第一个阀门叫做“access_allow_vavle”, 也就是说需求流过来的时候,它会看这个需求是哪个IP过来的, 如果这个IP已经在黑名单里面了,sure, 杀! 第二个阀门叫做“defaul_access_valve”它会做例行的检查, 如果通过的话,OK, 把需求传递给当前容器的子容器。 就是通过这种方式, 需求就在各个容器里面传递,流动, 最后抵达目的地的了。 56 | ``` 57 | * valve: 58 | ``` 59 | 就是上面所说的阀门。 60 | ``` 61 | 62 | 63 | ### 知识点总结 64 | * Standard*XXXX*是组件接口的默认实现类。 65 | * 如果希望定制Web应用的错误页面,出了按照Servlet规范在web.xml中添加外,还可以通过配置Host中的errorReportValueClass属性来实现。前者的作用范围是当前web应用,后者是整个虚拟机。除非错误页面和具体web应用无关,否则不推荐使用此配置方式,当然此配置方式的另一个好处是处于安全的考虑,隐藏了服务器的细节。 66 | 67 | ### Tomcat Server处理一个HTTP请求过程 68 | 1. 用户点击页面,用户请求(localhost/test/index.jsp)被发送到本机端口的8080,被在那里监听的HTTP/1.1 Connector捕获 69 | 2. Connector把请求(Socket请求)封装成request和response,交给Container 70 | 3. Container中Engine获得请求localhost/test/index.jsp,匹配所有的虚拟主机Host 71 | 4. 名为localhost的Engine获得请求/test/index.jsp,匹配她所拥有的所有Context。Host匹配到路径为/test的Context 72 | 5. /test的Contxt获得/index.jsp,在其所有的wrapper中找到对应的servlet 73 | 6. servlet调用JspServlet中的doGet()或doPost()等执行业务逻辑 74 | 7. Context把执行完之后的HttpServletResponse对象返回给Host 75 | 8. Host返回给Engine,Engine返回给Connector,connector返回给Browser 76 | 77 | * 如果要去掉默认该界面,可以重命名tomcat目录下的ROOT,并新建空文件夹命名为ROOT: 78 | 79 | 不错的文章: http://note.youdao.com/noteshare?id=a9d957049757af03d2823a22daf71169 -------------------------------------------------------------------------------- /system/algorithm/algorithm.md: -------------------------------------------------------------------------------- 1 | ### 学习笔记 2 | * [数据结构](数据结构.md) 3 | * [设计模式](设计模式.md) 4 | * [倒排索引](倒排索引.md) -------------------------------------------------------------------------------- /system/algorithm/img/es-btree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/system/algorithm/img/es-btree.png -------------------------------------------------------------------------------- /system/algorithm/img/es-index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/system/algorithm/img/es-index.png -------------------------------------------------------------------------------- /system/algorithm/img/es-storage-index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/system/algorithm/img/es-storage-index.png -------------------------------------------------------------------------------- /system/algorithm/img/八大排序算法.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/system/algorithm/img/八大排序算法.png -------------------------------------------------------------------------------- /system/algorithm/letcode/note.md: -------------------------------------------------------------------------------- 1 | ### 从排序数组中删除重复项 2 | 3 | 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 4 | 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 5 | 6 | ``` 7 | 示例 1: 8 | 给定数组 nums = [1,1,2], 9 | 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 10 | 你不需要考虑数组中超出新长度后面的元素。 11 | ``` 12 | ``` 13 | 示例 2: 14 | 给定 nums = [0,0,1,1,1,2,2,3,3,4], 15 | 函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 16 | ``` 17 | 18 | 你不需要考虑数组中超出新长度后面的元素。 19 | 说明: 20 | 21 | * 为什么返回数值是整数,但输出的答案是数组呢? 22 | 23 | 请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 24 | 25 | 你可以想象内部操作如下: 26 | 27 | // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝 28 | int len = removeDuplicates(nums); 29 | 30 | // 在函数里修改输入数组对于调用者是可见的。 31 | // 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。 32 | for (int i = 0; i < len; i++) { 33 | print(nums[i]); 34 | } 35 | 36 | 0 37 | 1 38 | 2 39 | 3 40 | 4 41 | 5 42 | 6 43 | 7 44 | 8 45 | 9 46 | 5 47 | 6 48 | 6 49 | 7 50 | 7 51 | 8 52 | 8 53 | 9 -------------------------------------------------------------------------------- /system/algorithm/倒排索引.md: -------------------------------------------------------------------------------- 1 | 倒排索引(Inverted Index)也叫反向索引,有反向索引必有正向索引。通俗地来讲,正向索引是通过key找value,反向索引则是通过value找key。 2 | 假设有个user索引,它有四个字段:分别是name,gender,age,address。画出来的话,大概是下面这个样子,跟关系型数据库一样: 3 | * Term(单词):一段文本经过分析器分析以后就会输出一串单词,这一个一个的就叫做Term(直译为:单词) 4 | * Term Dictionary(单词字典):顾名思义,它里面维护的是Term,可以理解为Term的集合 5 | * Term Index(单词索引):为了更快的找到某个单词,我们为单词建立索引 6 | * Posting List(倒排列表):倒排列表记录了出现过某个单词的所有文档的文档列表及单词在该文档中出现的位置信息,每条记录称为一个倒排项(Posting)。根据倒排列表,即可获知哪些文档包含某个单词。(PS:实际的倒排列表中并不只是存了文档ID这么简单,还有一些其它的信息,比如:词频(Term出现的次数)、偏移量(offset)等,可以想象成是Python中的元组,或者Java中的对象) 7 | (PS:如果类比现代汉语词典的话,那么Term就相当于词语,Term Dictionary相当于汉语词典本身,Term Index相当于词典的目录索引) 8 | 我们知道,每个文档都有一个ID,如果插入的时候没有指定的话,Elasticsearch会自动生成一个,因此ID字段就不多说了 9 | 上面的例子,Elasticsearch建立的索引大致如下: 10 | 11 | ![](img/es-index.png) 12 | 13 | Elasticsearch分别为每个字段都建立了一个倒排索引。比如,在上面“张三”、“北京市”、22 这些都是Term,而[1,3]就是Posting List。Posting list就是一个数组,存储了所有符合某个Term的文档ID。 14 | 只要知道文档ID,就能快速找到文档。可是,要怎样通过我们给定的关键词快速找到这个Term呢? 15 | 当然是建索引了,为Terms建立索引,最好的就是B-Tree索引(PS:MySQL就是B树索引最好的例子)。 16 | 首先,让我们来回忆一下MyISAM存储引擎中的索引是什么样的: 17 | 18 | ![](img/es-btree.png) 19 | 20 | 我们查找Term的过程跟在MyISAM中记录ID的过程大致是一样的 21 | 22 | MyISAM中,索引和数据是分开,通过索引可以找到记录的地址,进而可以找到这条记录 23 | 24 | 在倒排索引中,通过Term索引可以找到Term在Term Dictionary中的位置,进而找到Posting List,有了倒排列表就可以根据ID找到文档了 25 | 26 | (PS:可以这样理解,类比MyISAM的话,Term Index相当于索引文件,Term Dictionary相当于数据文件) 27 | 28 | (PS:其实,前面我们分了三步,我们可以把Term Index和Term Dictionary看成一步,就是找Term。因此,可以这样理解倒排索引:通过单词找到对应的倒排列表,根据倒排列表中的倒排项进而可以找到文档记录) 29 | 30 | 为了更进一步理解,下面从网上摘了两张图来具现化这一过程: 31 | ![](img/es-storage-index.png) -------------------------------------------------------------------------------- /system/algorithm/数据结构.md: -------------------------------------------------------------------------------- 1 | ### 学习计划 2 | * 数据结构的定义,为什么要有数据结构? https://blog.csdn.net/turingbooks/article/details/93998363 3 | * 常见的数据结构 https://www.cnblogs.com/qccadmin/p/10085749.html 4 | * 数组 常见排序算法讨论 https://www.zhihu.com/question/51337272/answer/572455307 5 | * 直接插入排序 https://www.jianshu.com/p/7cf0656e76dd 6 | * [数组 八种常见的排序算法](https://github.com/zhonghuasheng/JAVA/blob/master/README.md#thinking) 7 | 8 | ### 学习笔记 9 | * 数据结构是指数据的组织形式。高效的数据组织形式能够加快计算机阅读和处理,从而提高效率。 10 | * 数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合,通常情况下,精心选择的数据结构可以带来更高的运行或者存储的效率。数据结构往往同高效的检索算法和索引技术有关。 11 | * 常见的数据结构 12 | * 集合结构 13 | * 数据类型相同的一类数据。典型的有:数组。 14 | * 线性结构 15 | * 元素之间存在一对一关系。典型的有:栈、队列和线性表。 16 | * 树形结构 17 | * 元素之间存在“一对多”关系,节点间具有层次关系,每一层的一个节点能且只能和上一层的一个节点相关,但同时可以和下一层的多个节点相关。典型的有:树,堆。 18 | * 图形结构 19 | * 在图形结构中,允许多个节点之间相关,存在“多对多”关系。 20 | ### 数组 21 | * 定义: 22 | * 数组:存放着一组相同类型的数据,需要预先指定数组的长度,有一维数组、二维数组、多维数组等。如果数组是自己定义并且初始化的的必须在new 类型[长度]这里指明长度,数组没有默认长度。Java中数组是定长的,一旦经过初始化声明就不可能改变长度,这在实际使用中非常不方便。常见的八大排序算法: 23 | ![](img/八大排序算法.png) 24 | 排序算法可以分为内部排序和外部排序。内部排序是数据记录在内存中进行排序。而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。常见的内部排序算法有:插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。 25 | * 链表:链表是C语言中一种应用广泛的结构,它采用动态分配内存的形式实现,用一组任意的存储单元存放数据元素链表的,一般为每个元素增设指针域,用来指向后继元素 26 | * 数组和链表的区别: 27 | * 从逻辑结构来看:数组必须事先定义固定的长度【有默认值】,不能适应数据动态地增减的情况;链表动态地进行存储分配,可以适应数据动态地增减的情况,且可以方便地插入、删除数据项(数组中插入、删除数据项时,需要移动其它数据项) 28 | * 从内存存储来看:(静态)数组从栈中分配空间(用NEW创建的在堆中), 对于程序员方便快速,但是自由度小;链表从堆中分配空间, 自由度大但是申请管理比较麻烦 29 | * 从访问方式来看:数组在内存中是连续存储的,因此,可以利用下标索引进行随机访问;链表是链式存储结构,在访问元素的时候只能通过线性的方式由前到后顺序访问,所以访问效率比数组要低 30 | * 栈、队列和线性表:可采用顺序存储和链式存储的方法进行存储 31 | * 顺序存储:借助数据元素在存储空间中的相对位置来表示元素之间的逻辑关系 32 | * 链式存储:借助表示数据元素存储地址的指针表示元素之间的逻辑关系 33 | * 栈:只允许在序列末端进行操作,栈的操作只能在栈顶进行,一般栈又被称为后进先出或先进后出的线性结构 34 | * 顺序栈:采用顺序存储结构的栈称为顺序栈,即需要用一片地址连续的空间来存储栈的元素 35 | * 链栈:采用链式存储结构的栈称为链栈 36 | * 队列:只允许在序列两端进行操作,一般队列也被称为先进先出的线性结构 37 | * 循环队列:采用顺序存储结构的队列,需要按队列可能的最大长度分配存储空间 38 |   * 链队列:采用链式存储结构的队列称为链队列,一般需要设置头尾指针只是链表的头尾结点: 39 | * 散列表(哈希表):散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。 40 | 41 | 线性表:允许在序列任意位置进行操作,线性表的操作位置不受限制,线性表的操作十分灵活,常用操作包括在任意位置插入和删除,以及查询和修改任意位置的元素 42 | 43 |   顺序表:采用顺序存储结构表示的线性表称为顺序表,用一组地址连续的存储单元一次存放线性表的数据元素,即以存储位置相邻表示位序相继的两个元素之间的前驱和后继关系,为了避免移动元素,一般在顺序表的接口定义中只考虑在表尾插入和删除元素,如此实现的顺序表也可称为栈表: 44 |   45 | 46 | 47 |  线性表:一般包括单链表、双向链表、循环链表和双向循环链表 48 |  单链表: 49 |    50 | 51 |  双向链表: 52 | 53 |    54 |  线性表两种存储结构的比较: 55 |  顺序表: 56 |  优点:在顺序表中,逻辑中相邻的两个元素在物理位置上也相邻,查找比较方便,存取任一元素的时间复杂度都为O(1) 57 |  缺点:不适合在任意位置插入、删除元素,因为需要移动元素,平均时间复杂度为O(n) 58 |  链表: 59 |  优点:在链接的任意位置插入或删除元素只需修改相应指针,不需要移动元素;按需动态分配,不需要按最大需求预先分配一块连续空空 60 |  缺点:查找不方便,查找某一元素需要从头指针出发沿指针域查找,因此平均时间复杂度为O(n) 61 | 62 | 2、树形结构:结点间具有层次关系,每一层的一个结点能且只能和上一层的一个结点相关,但同时可以和下一层的多个结点相关,称为“一对多”关系,常见类型有:树、堆 63 | (1)二叉树:二叉树是一种递归数据结构,是含有n(n>=0)个结点的有限集合,二叉树具有以下特点: 64 | 二叉树可以是空树;二叉树的每个结点都恰好有两棵子树,其中一个或两个可能为空;二叉树中每个结点的左、右子树的位置不能颠倒,若改变两者的位置,就成为另一棵二叉树 65 | 66 | (2)完全二叉树:从根起,自上而下,自左而右,给满二叉树的每个结点从1到n连续编号,如果每个结点都与深度为k的满二叉树中编号从1至n的结点一一对应,则称为完全二叉树 67 | a、采用顺序存储结构:用一维数组存储完全二叉树,结点的编号对于与结点的下标(如根为1,则根的左孩子为2*i=2*1=2,右孩子为2*i+1=2*1+1=2) 68 |   69 | 70 | b、采用链式存储结构: 71 | 二叉链表: 72 |   73 | 74 | 三叉链表:它的结点比二叉链表多一个指针域parent,用于执行结点的双亲,便于查找双亲结点 75 |   76 | 77 | 两种存储结构比较:对于完全二叉树,采用顺序存储结构既能节省空间,又可利用数组元素的下标值确定结点在二叉树中的位置及结点之间的关系,但采用顺序存储结构存储一般二叉树容易造成空间浪费,链式结构可以克服这个缺点 78 | 79 | (3)二叉查找树:二叉查找树又称二叉排序树,或者是一课空二叉树,或者是具有如下特征的二叉树: 80 | a、若它的左子树不空,则左子树上所有结点的值均小于根结点的值 81 | b、若它的右子树不空,则右子树上所有结点的值均大于根结点的值 82 | c、它的左、右子树也分别是二叉查找树 83 | 84 | (4)平衡二叉树:平衡二叉查找树简称平衡二叉树,平衡二叉树或者是棵空树,或者是具有下列性质的二叉查找树:它的左子树和右子树都是平衡二叉树,且左子树和右子树的高度之差的绝对值不超过1 85 |   86 | 87 | 平衡二叉树的失衡及调整主要可归纳为下列四种情况:LL型、RR型、LR型、RL型 88 | 89 | (5)树:树是含有n(n>=0)个结点的有限集合,在任意一棵非空树种: 90 | a、有且仅有一个特定的称为根的结点 91 | b、当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1,T2,...,Tm,其中每一个集合本身又是一棵树,并且T1,T2,...,Tm称为根的子树 92 | 93 | (6)堆:堆是具有以下特性的完全二叉树,其所有非叶子结点均不大于(或不小于)其左右孩子结点。若堆中所有非叶子结点均不大于其左右孩子结点,则称为小顶堆(小根堆),若堆中所有非叶子结点均不小于其左右孩子结点,则称为大顶堆(大根堆) 94 |   95 | 96 | 97 | (7)并查集:并查集是指由一组不相交子集所构成的集合,记作:S={S1,S2,S3,...,Sn} 98 | (8)B树 99 | 100 | 3、图形结构:在图形结构中,允许多个结点之间相关,称为“多对多”关系,可分为有向图和无向图 -------------------------------------------------------------------------------- /system/algorithm/设计模式.md: -------------------------------------------------------------------------------- 1 | `创建型` 2 | * [单例模式 Singleton Pattern](https://github.com/zhonghuasheng/DesignPattern/wiki/%E5%88%9B%E5%BB%BA%E5%9E%8B---%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F-Singleton-Pattern) 3 | 4 | `结构型` 5 | * [代理模式 Proixy Pattern](https://github.com/zhonghuasheng/DesignPattern/wiki/%E7%BB%93%E6%9E%84%E5%9E%8B-%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F-Proxy-Design-Pattern) 6 | 7 | `行为型` 8 | * [解释器模式](https://github.com/zhonghuasheng/DesignPattern/wiki/%E8%A1%8C%E4%B8%BA%E5%9E%8B-%E8%A7%A3%E6%9E%90%E5%99%A8%E6%A8%A1%E5%BC%8F-Interpreter-Pattern) 9 | -------------------------------------------------------------------------------- /system/architecture/CAP.md: -------------------------------------------------------------------------------- 1 | * 英文定义:In a distributed system (a collection of interconnected nodes that share data.), you can only have two out of the following three guarantees across a write/read pair: Consistency, Availability, and Partition Tolerance - one of them must be sacrificed. 2 | 3 | 关键点解释: 4 | * 互联和共享数据的情形 5 | * cap关注的是对数据的读写操作,而不是分布式系统的所有功能 6 | 7 | 分布式系统(distributed system)正变得越来越重要,大型网站几乎都是分布式的。 8 | 分布式系统的最大难点,就是各个节点的状态如何同步。CAP 定理是这方面的基本定理,也是理解分布式系统的起点。 9 | 10 | 本文介绍该定理。它其实很好懂,而且是显而易见的。下面的内容主要参考了 Michael Whittaker 的文章。 11 | 12 | 1. 分布式系统的三个指标 13 | 1998年,加州大学的计算机科学家 Eric Brewer 提出,分布式系统有三个指标。 14 | * Consistency 15 | * Availability 16 | * Partition tolerance 17 | 18 | ![](img/cap.jpg) 19 | 20 | 它们的第一个字母分别是 C、A、P。 21 | 22 | Eric Brewer 说,这三个指标不可能同时做到。这个结论就叫做 CAP 定理。 23 | 24 | 2. Partition tolerance 25 | 先看 Partition tolerance,中文叫做"分区容错"。 26 | 27 | ![](img/partitiontolerance.png) 28 | 29 | 大多数分布式系统都分布在多个子网络。每个子网络就叫做一个区(partition)。分区容错的意思是,区间通信可能失败。比如,一台服务器放在中国,另一台服务器放在美国,这就是两个区,它们之间可能无法通信。 30 | 31 | 上图中,G1 和 G2 是两台跨区的服务器。G1 向 G2 发送一条消息,G2 可能无法收到。系统设计的时候,必须考虑到这种情况。 32 | 33 | 一般来说,分区容错无法避免,因此可以认为 CAP 的 P 总是成立。CAP 定理告诉我们,剩下的 C 和 A 无法同时做到。 34 | 35 | 3. Consistency 36 | 37 | Consistency 中文叫做"一致性"。意思是,写操作之后的读操作,必须返回该值。举例来说,某条记录是 v0,用户向 G1 发起一个写操作,将其改为 v1。 38 | 39 | ![](img/consistency.png) 40 | 41 | 接下来,用户的读操作就会得到 v1。这就叫一致性。 42 | 43 | ![](img/consistency-send.png) 44 | 45 | 问题是,用户有可能向 G2 发起读操作,由于 G2 的值没有发生变化,因此返回的是 v0。G1 和 G2 读操作的结果不一致,这就不满足一致性了。 46 | 47 | ![](img/consistency-conflict.png) 48 | 49 | 为了让 G2 也能变为 v1,就要在 G1 写操作的时候,让 G1 向 G2 发送一条消息,要求 G2 也改成 v1。 50 | 51 | ![](img/consistency-sync.png) 52 | 53 | 这样的话,用户向 G2 发起读操作,也能得到 v1。 54 | 55 | ![](img/consistency-done.png) 56 | 57 | 4. Availability 58 | 59 | Availability 中文叫做"可用性",意思是只要收到用户的请求,服务器就必须给出回应。 60 | 61 | 用户可以选择向 G1 或 G2 发起读操作。不管是哪台服务器,只要收到请求,就必须告诉用户,到底是 v0 还是 v1,否则就不满足可用性。 62 | 63 | 5. Consistency 和 Availability 的矛盾 64 | 65 | `一致性和可用性,为什么不可能同时成立?答案很简单,因为可能通信失败(即出现分区容错)。` 66 | 67 | 如果保证 G2 的一致性,那么 G1 必须在写操作时,锁定 G2 的读操作和写操作。只有数据同步后,才能重新开放读写。锁定期间,G2 不能读写,没有可用性不。 68 | 69 | 如果保证 G2 的可用性,那么势必不能锁定 G2,所以一致性不成立。 70 | 71 | 综上所述,G2 无法同时做到一致性和可用性。系统设计时只能选择一个目标。如果追求一致性,那么无法保证所有节点的可用性;如果追求所有节点的可用性,那就没法做到一致性。 72 | 73 | ### 百问 74 | > 读者问,在什么场合,可用性高于一致性? 75 | 76 | 举例来说,发布一张网页到 CDN,多个服务器有这张网页的副本。后来发现一个错误,需要更新网页,这时只能每个服务器都更新一遍。 77 | 78 | 一般来说,网页的更新不是特别强调一致性。短时期内,一些用户拿到老版本,另一些用户拿到新版本,问题不会特别大。当然,所有人最终都会看到新版本。所以,这个场合就是可用性高于一致性。 79 | -------------------------------------------------------------------------------- /system/architecture/distribute_transactional.md: -------------------------------------------------------------------------------- 1 | # 分布式事务 2 | 3 | ### Seata 4 | https://www.oschina.net/p/seata?hmsr=aladdin1e1 5 | http://www.dreamwu.com/post-1741.html 6 | https://blog.csdn.net/hosaos/article/details/89136666 -------------------------------------------------------------------------------- /system/architecture/img/api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/system/architecture/img/api.png -------------------------------------------------------------------------------- /system/architecture/img/cap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/system/architecture/img/cap.jpg -------------------------------------------------------------------------------- /system/architecture/img/consistency-conflict.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/system/architecture/img/consistency-conflict.png -------------------------------------------------------------------------------- /system/architecture/img/consistency-done.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/system/architecture/img/consistency-done.png -------------------------------------------------------------------------------- /system/architecture/img/consistency-send.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/system/architecture/img/consistency-send.png -------------------------------------------------------------------------------- /system/architecture/img/consistency-sync.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/system/architecture/img/consistency-sync.png -------------------------------------------------------------------------------- /system/architecture/img/consistency.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/system/architecture/img/consistency.png -------------------------------------------------------------------------------- /system/architecture/img/distribute_lock.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/system/architecture/img/distribute_lock.jpg -------------------------------------------------------------------------------- /system/architecture/img/java-log-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/system/architecture/img/java-log-architecture.png -------------------------------------------------------------------------------- /system/architecture/img/partitiontolerance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/system/architecture/img/partitiontolerance.png -------------------------------------------------------------------------------- /system/architecture/io-multiplexing.md: -------------------------------------------------------------------------------- 1 | ## 网络IO 2 | * 什么是IO多路复用 3 | * 为什么有IO多路复用机制 4 | 5 | ### 什么是IO多路复用 6 | IO多路复用是一种同步IO模型,实现一个线程可以监听多个文件句柄;一旦某个文件句柄就绪,就能够通知应用程序进行相应的独写操作;没有文件句柄就绪会阻塞应用程序,交出cpu。多路是指多个网络连接,复用指的是同一个线程。也可能是进程,但是实际执行的时候是线程执行任务 7 | 8 | ### 为什么有IO多路复用机制 9 | 没有IO多路复用机制的时候,使用的是BIO, NIO两种方式,但有一些问题。 10 | * BIO同步阻塞IO。服务端采用单线程,当accept一个请求后,在recv或send调用阻塞时,将无法accept其他请求(必须等上一个请求处理完recv或send),无法处理并发 11 | ```c 12 | // 伪代码,早期版本 13 | while(1) { 14 | // accept阻塞。accept接受连接,如果没有连接,就一直等待 15 | client_fd = accept(listen_fd) 16 | fds.append(client_fd) 17 | for (fd in fds) { 18 | // recv阻塞(会影响上面的accept)。rece接收数据,如果没有数据到达,也会等待 19 | if (recv(fd)) { 20 | // logic 21 | } 22 | } 23 | } 24 | ``` 25 | 服务端采用多线程,当accept一个请求后,开启线程进行recv,可以完成并发处理,但随着请求数增加需要增加系统线程,大量的线程占用很大的内存空间,并且线程切换会带来很大的开销。 26 | ```c 27 | while(1) { 28 | client_fd = accept(listen_fd); 29 | fds.append(fd); 30 | // 一旦接收到请求,就开启线程read数据。早期可以通过多线程来解决,但是随着web2.0的到来,这种思路出现了瓶颈,线程不能无限创建。 31 | new Thread func() { 32 | if (recv(fd)) { 33 | // logic 34 | } 35 | } 36 | } 37 | ``` 38 | 只要没有客户端连接上服务器,accept方法就一直不能返回,这就是阻塞;对应的读写操作道理也一样,想要读取数据,必须等到有数据到达才能返回,这就是阻塞。 39 | * NIO 同步非阻塞 40 | BIO的瓶颈在于accept客户端的时候会阻塞,以及进行读写操作的时候会阻塞,导致效率低。为了突破这个瓶颈,操作系统发展出了NIO,这里的NIO指的是非阻塞IO。也就是说在accept客户端连接的时候,不需要阻塞,如果当没有客户端连接的时候就返回-1,在读写操作的时候,也不会阻塞,有数据就读,没数据就直接返回。同时NIO用数组集合保存每个连接的客户端,单线程通过while循环来对每个连接进行操作。 41 | ```c 42 | // NIO是操作系统对原来的accept/recv等函数做了优化,让其不再阻塞 43 | setNonblocking(listen_fd) 44 | while(1) { 45 | // 不阻塞了 46 | client_fd = accept(listen_fd) 47 | if (client_fd != null) { 48 | // 有人连接 49 | fds.append(client_fd) 50 | } else { 51 | // 无人连接。直接返回 52 | } 53 | 54 | for (fd in fds) { 55 | // recv非阻塞 56 | setNonblocking(client_fd) 57 | if (len = recv(fd) && len > 0) { 58 | // 有读写数据 59 | } else { 60 | // 直接返回 61 | } 62 | } 63 | } 64 | ``` 65 | 尽管上面的单线程NIO服务器模型比BIO的优良很多,但是仍然有一个大问题。在客户端与服务器建立连接后,后续会进行一系列的读写操作。虽然这些读写操作是非阻塞的,但是每调一次读写操作在操作系统层面都要进行一次用户态和内核态的切换,这也是一个巨大的开销(读写等系统调用都是在内核态完成的)。在上面的代码中每次循环遍历都进行读写操作,我们以读操作为例:大部分读操作都是在数据没有准备好的情况下进行读的,相当于一次空操作。我们要想办法避免这种无效的读取操作,避免内核态和用户态的频繁切换。 66 | ``` 67 | 补充:客户端与服务器端两端都是通过socket进行连接的,socket在linux操作系统中有对应的文件描述符,我们的读写操作都是以该文件描述符为单位进行操作。 68 | ``` 69 | 为了避免上述的无效读写,我们得想办法得知当前的文件描述符是否可读可写。如果逐个文件描述符去询问,那么效率就和直接进行读写操作差不多了,我们希望有一种方法能够一次性得知哪些文件描述符可读,哪些文件描述符可写,这就是操作系统后来发展出来的多路复用器。 70 | 71 | 也就是说,多路复用器的核心功能就是告诉我们哪些文件描述符可读,哪些文件描述符可写。而多路复用器也分为几种,他们也经历了一个演化的过程。最初的多路复用器是select模型,它的模式是这样的:程序端每次把文件描述符集合交给select的系统调用,select遍历每个文件描述符后返回那些可以操作的文件描述符,然后程序对可以操作的文件描述符进行读写。 72 | 73 | 它的弊端是,一次传输的文件描述符集合有限,只能给出1024个文件描述符,poll在此基础上进行了改进,没有了文件描述符数量的限制。 74 | 75 | 但是select和poll在性能上还可以优化,它们共同的弊端在于: 76 | 77 | 1. 它们需要在内核中对所有传入的文件描述符进行遍历,这也是一项比较耗时的操作 78 | 79 | 2. (这点是否存在优化空间有待考证)每次要把文件描述符从用户态的内存搬运到内核态的内存,遍历完成后再搬回去,这个来回复制也是一项耗时的操纵。 80 | 81 | 后来操作系统加入了epoll这个多路复用器,彻底解决了这个问题: 82 | epoll多路复用器的模型是这样的: 83 | 84 | 为了在发起系统调用的时候不遍历所有的文件描述符,epoll的优化在于:当数据到达网卡的时候,会触发中断,正常情况下cpu会把相应的数据复制到内存中,和相关的文件描述符进行绑定。epoll在这个基础之上做了延伸,epoll首先是在内核中维护了一个红黑树,以及一些链表结构,当数据到达网卡拷贝到内存时会把相应的文件描述符从红黑树中拷贝到链表中,这样链表存储的就是已经有数据到达的文件描述符,这样当程序调用epoll_wait的时候就能直接把能读的文件描述符返回给应用程序。(零拷贝) 85 | 86 | 除了epoll_wait之外,epoll还有两个系统调用,分别是epoll_create和epoll_ctl,分别用于初始化epoll和把文件描述符添加到红黑树中。 87 | 88 | 以上就是多路复用器与常见io模型的关系了,网上常常有文章把多路复用器说成是nio的一部分,我觉得也是合理的,因为在具体编程的时候两个概念往往会融为一体。 89 | 90 | 后续 91 | 92 | 其实Java已经为我们把多路复用器用Selector类给封装起来了,我们完全可以基于Selector进行NIO服务器开发。但是我们自己写nio服务器可能不够严谨,Java届有一款优秀nio框架,名叫Netty,这部分内容我们留到下一次再讲啦。 93 | 94 | * IO多路复用 95 | 服务器端采用单线程通过select/poll/epoll等系统调用获取fd列表,遍历有事件的fd进行accept/recv/send 96 | 97 | > IO多路复用的三种实现方式 98 | 99 | * select 100 | * 单个进程所打开的FD是有限制的,通过FD_SETSIZE设置,默认1024 101 | * 每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大 102 | * 对socket扫描时是线性扫描,采用轮询的方法,效率较低(高并发时) 103 | * poll 104 | * poll与select相比,只是没有fd的限制,其它基本一样 105 | * 每次调用poll,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大 106 | * 对socket扫描时是线性扫描,采用轮询的方法,效率较低(高并发时) 107 | * epoll 108 | * epoll只能工作在linux下 109 | * epoll LT 与 ET模式的区别: epoll有EPOLLLT和EPOLLET两种触发模式,LT是默认的模式,ET是“高速”模式。 110 | * LT模式下,只要这个fd还有数据可读,每次 epoll_wait都会返回它的事件,提醒用户程序去操作 111 | * ET模式下,它只会提示一次,直到下次再有数据流入之前都不会再提示了,无论fd中是否还有数据可读。所以在ET模式下,read一个fd的时候一定要把它的buffer读完,或者遇到EAGAIN错误 112 | 113 | 下面举一个例子,模拟一个tcp服务器处理30个客户socket。假设你是一个老师,让30个学生解答一道题目,然后检查学生做的是否正确。 114 | 你有下面几个选择: 115 | 1. 第一种选择:按顺序逐个检查,先检查A,然后是B,之后是C、D。。。这中间如果有一个学生卡主,全班都会被耽误。这种模式就好比,你用循环挨个处理socket,根本不具有并发能力。 116 | 2. 第二种选择:你创建30个分身,每个分身检查一个学生的答案是否正确。 这种类似于为每一个用户创建一个进程或者线程处理连接。 117 | 3. 第三种选择,你站在讲台上等,谁解答完谁举手。这时C、D举手,表示他们解答问题完毕,你下去依次检查C、D的答案,然后继续回到讲台上等。此时E、A又举手,然后去处理E和A。。。 这种就是IO复用模型,Linux下的select、poll和epoll就是干这个的。将用户socket对应的fd注册进epoll,然后epoll帮你监听哪些socket上有消息到达,这样就避免了大量的无用操作。此时的socket应该采用非阻塞模式。这样,整个过程只在调用select、poll、epoll这些调用的时候才会阻塞,收发客户消息是不会阻塞的,整个进程或者线程就被充分利用起来,这就是事件驱动,所谓的reactor模式。 118 | 119 | ### 参考文章 120 | * https://blog.csdn.net/javageektech/article/details/108301658 -------------------------------------------------------------------------------- /system/architecture/log-note.md: -------------------------------------------------------------------------------- 1 | # Log 2 | 3 | ## 目录 4 | 1. 为什么要使用Log 5 | 2. Log的等级 6 | 3. 什么时候打Log 7 | 4. 打什么样的Log 8 | 5. 打Log对系统性能的影响 9 | 6. 一些日志框架 10 | 7. 使用Log时注意事项 11 | 12 | ### 为什么要使用Log 13 | 14 | *用途主要体现在以下方面:* 15 | 16 | * Install: 安装配置时记录具体的安装步骤 17 | * Online debug: 可以通过Log来查看一些Environment Issue 18 | * Collect Information: 通过日志我们可以找到系统中存在的一些漏洞,这些漏洞时平时开发中难以模拟和发现的 19 | * Assessment: 通过日志我们可以分析用户的行为,进而评估用户对系统保持热衷的程度,通过慢日志分析/评估用户在模块停留的时间以及系统的反应时间 20 | * Security: 对于一些很严格的操作我们需要记录详细的说明,比如对一些非授权的操作,银行的业务 21 | 22 | ### Log的等级 23 | 24 | #### Java类 25 | 26 | ![Java日志结构](img/java-log-architecture.png) 27 | 28 | |Log4j slf4j |J2SE | Useage| 29 | |:------------|:------|:------| 30 | |trace|FINEST|输出更详细的调试信息| 31 | |debug|FINER|比调试信息详细点| 32 | |debug|FINE|调试信息| 33 | |info|CONFIG|系统配置,系统运行环境信息| 34 | |info|INFO|系统运行时信息,比如Scheduled时间| 35 | |warn|WARNING|警告,此警告不影响系统的执行,不影响下次业务的执行| 36 | |error|SERVER|错误,问题影响到系统的执行,并且系统不能自行恢复到正常状态| 37 | |fatal||宕机| 38 | 39 | #### Tomcat类 40 | * Tomcat分5类log 41 | * localhost, localhost_access, manager, admin, catalina 42 | * 每一类log分7种等级 43 | * SERVER > WARNING > INFO > CONFIG > FINE > FINER > FINEST 44 | 45 | ### 什么时候打Log 46 | 47 | * 系统安装配置时,对于系统安装的参数,如jdk版本,JVM内存大小,等主要相关信息的输出,这样可以看到安装到了哪一个步骤,模块部署是否正常 48 | * 异常捕获时输出日志,出错时的参数,特别对于prod上不能debug的环境,有时只能通过日志去猜测可能出错的原因 49 | * scheduled job,如定时发送邮件等,这些需要在job开始前后都要记录日志,甚至中间的过程都要详细记录 50 | * 一些敏感操作,如delete,这个时候需要记录who when delete what, pre value, current value 51 | * 关键步骤需要打log,比如服务模块的启动 52 | 53 | ### 打什么样的Log 54 | 55 | * error 和 warn: 出错信息或者警告的描述,相关参数的值,异常的StackTrace 56 | * info: 输出相关信息 57 | * debug: 相关描述,参数信息,异常的StackTrace 58 | 59 | ### 打Log对系统性能的影响 60 | 61 | * 获取logger实例的开销 62 | * 写文件IO开销(禁掉Tomcat中的部分日志,如localhost,manager, admin等) 63 | 64 | 65 | ### 一些日志框架 66 | * Apache Commons Logging 67 | * 提供接口而非实现,通常配合着log4j来使用 68 | * Log4j / Log4j2 69 | * LogBack(Log4j的改良版) 70 | * Tinylog 精简版日志框架,运行特别快,适合小项目 71 | 72 | 73 | ### 使用Log时注意事项 74 | 1. 正确的理解日志的输出级别 75 | 2. 正确的书写log的输出内容 76 | 3. 日志信息应该是简介且可描述的(建议使用自定义异常) 77 | 4. 正确的使用输出的模式 78 | 5. 尽量使用slf4j或者commons-logging等抽象日志框架,而不是具体的logging(jdk自带)、log4j、log4j2 79 | 80 | 81 | ### ELK 82 | ELK是三款软件的组合。是一整套完整的解决方案。分别是由Logstash(收集+分析)、ElasticSearch(搜索+存储)、Kibana(可视化展示)三款软件。ELK主要是为了在海量的日志系统里面实现分布式日志数据集中式管理和查询,便于监控以及排查故障。 83 | 84 | ElasticSearch 是一个基于 Lucene 的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于 RESTful API 的 web 接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。 85 | 86 | Logstash是一个数据采集、加工处理以及传输的工具,能够将所有的数据集中处理,使不同模式和不同数据的正常化,而且数据源能够随意轻松的添加。 87 | 88 | Kibana是一个开源的分析与可视化平台,可以使用各种不同的图表、表格、地图等kibana能够很轻易地展示高级数据分析与可视化。 89 | 90 | Apache kafka是消息中间件的一种,是一种分布式的,基于发布/订阅的消息系统。能实现一个为处理实时数据提供一个统一、高吞吐、低延迟的平台,且拥有分布式的,可划分的,冗余备份的持久性的日志服务等特点。 91 | 92 | `Filebeta README file` 93 | # Welcome to Filebeat 6.6.1 94 | Filebeat sends log files to Logstash or directly to Elasticsearch. 95 | ## Getting Started 96 | To get started with Filebeat, you need to set up Elasticsearch on 97 | your localhost first. After that, start Filebeat with: 98 | ./filebeat -c filebeat.yml -e 99 | This will start Filebeat and send the data to your Elasticsearch 100 | instance. To load the dashboards for Filebeat into Kibana, run: 101 | ./filebeat setup -e 102 | For further steps visit the 103 | [Getting started](https://www.elastic.co/guide/en/beats/filebeat/6.6/filebeat-getting-started.html) guide. 104 | ## Documentation 105 | Visit [Elastic.co Docs](https://www.elastic.co/guide/en/beats/filebeat/6.6/index.html) 106 | for the full Filebeat documentation. 107 | ## Release notes 108 | 109 | `common cmd` 110 | ./filebeat -e -c filebeat.yml -d "publish" 111 | 112 | `logstash` 113 | node { 114 | name => 'betas' 115 | } 116 | 117 | input { 118 | betas { 119 | host => "xxx" 120 | port => "5044" 121 | } 122 | } 123 | 124 | filter { 125 | } 126 | 127 | output { 128 | elasticsearch { 129 | hosts => ["xxx:9200"] 130 | } 131 | } 132 | 133 | http://www.importnew.com/16331.html -------------------------------------------------------------------------------- /system/architecture/spring-cloud-优雅上下线.md: -------------------------------------------------------------------------------- 1 | PL -------------------------------------------------------------------------------- /system/architecture/system.md: -------------------------------------------------------------------------------- 1 | ### OS的PageCache机制 2 | PageCache是OS对文件的缓存,用于加速对文件的读写。一般来说,程序对文件进行顺序读写的速度几乎接近于内存的读写访问,这里的主要原因就是在于OS使用PageCache机制对读写访问操作进行了性能优化,将一部分的内存用作PageCache 3 | 1、对于数据文件的读取 4 | 5 | 如果一次读取文件时出现未命中(cache miss)PageCache的情况,OS从物理磁盘上访问读取文件的同时,会顺序对其他相邻块的数据文件进行预读取(ps:顺序读入紧随其后的少数几个页面)。这样,只要下次访问的文件已经被加载至PageCache时,读取操作的速度基本等于访问内存 6 | 1、对于数据文件的写入 7 | 8 | OS会先写入至Cache内,随后通过异步的方式由pdflush内核线程将Cache内的数据刷盘至物理磁盘上 9 | 对于文件的顺序读写操作来说,读和写的区域都在OS的PageCache内,此时读写性能接近于内存。RocketMQ的大致做法是,将数据文件映射到OS的虚拟内存中(通过JDK NIO的MappedByteBuffer),写消息的时候首先写入PageCache,并通过异步刷盘的方式将消息批量的做持久化(同时也支持同步刷盘);订阅消费消息时(对CommitLog操作是随机读取),由于PageCache的局部性热点原理且整体情况下还是从旧到新的有序读,因此大部分情况下消息还是可以直接从Page Cache(cache hit)中读取,不会产生太多的缺页(Page Fault)中断而从磁盘读取PageCache机制也不是完全无缺点的,当遇到OS进行脏页回写,内存回收,内存swap等情况时,就会引起较大的消息读写延迟 10 | 对于这些情况,RocketMQ采用了多种优化技术,比如内存预分配,文件预热,mlock系统调用等,来保证在最大可能地发挥PageCache机制优点的同时,尽可能地减少其缺点带来的消息读写延迟. 11 | 12 | ### 引用 13 | * https://my.oschina.net/u/3180962/blog/3064148 -------------------------------------------------------------------------------- /system/architecture/tools.md: -------------------------------------------------------------------------------- 1 | ### 数据库相关 2 | * Flyway 是一款开源的数据库版本管理工具,它更倾向于规约优于配置的方式。Flyway 可以独立于应用实现管理并跟踪数据库变更,支持数据库版本自动升级,并且有一套默认的规约,不需要复杂的配置,Migrations 可以写成 SQL 脚本,也可以写在 Java 代码中,不仅支持 Command Line 和 Java API,还支持 Build 构建工具和 Spring Boot 等,同时在分布式环境下能够安全可靠地升级数据库,同时也支持失败恢复等。 3 | 4 | ### 帮助类相关 5 | * Hutool是一个Java工具包类库,对文件、流、加密解密、转码、正则、线程、XML等JDK方法进行封装,组成各种Util工具类 -------------------------------------------------------------------------------- /system/architecture/分布式ID生成方案.md: -------------------------------------------------------------------------------- 1 | ### 为什么要有分布式ID 2 | ### 号段模式 3 | https://time.geekbang.org/dailylesson/detail/100075738 -------------------------------------------------------------------------------- /system/architecture/分布式系统随笔.md: -------------------------------------------------------------------------------- 1 | ### 定义 2 | 分布式系统要做的任务就是把多台机器有机的组合、连接起来,让其协同完成一件任务,可以是计算任务,也可以是存储任务。 3 | 4 | ### 分类 5 | 1. 分布式存储系统 6 | 2. 分布式计算系统 7 | 3. 分布式管理系统 8 | 9 | ### 为什么会产生分布式系统? 10 | 11 | # 引用 12 | * [一篇读懂分布式架构下的负载均衡技术:分类、原理、算法、常见方案等](https://blog.csdn.net/hellojackjiang2011/article/details/89674268) 13 | 14 | ### 谈一谈你对分布式系统的理解 -------------------------------------------------------------------------------- /system/architecture/分布式锁.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | * [分布式锁需求](#分布式锁需求) 3 | * [分布式锁演进](#分布式锁演进) 4 | * [分布式锁面临的挑战](#面临的挑战) 5 | * [分布式锁的5个特性](#分布式锁的5个特性) 6 | * [分布式锁实现方案](#实现方式) 7 | * [SET EX|PX NX + 校验唯一值](#实现方式) 8 | * [开源框架Redisson](#实现方式) 9 | * [Redis集群实现分布式锁Redlock](#实现方式) 10 | * [数据库悲观锁X锁](#数据库悲观锁X锁) 11 | * [分布式锁常见问题](#分布式锁常见问题) 12 | * [java gc STW (stop the word)导致的锁过期问题](#分布式锁常见问题) 13 | 14 | ## 分布式锁需求 15 | 在多个服务间保证同一时刻同一时间段内只有一个用户能获取到锁 16 | 17 | ## 分布式锁演进 18 | 1. 基于数据库的悲观锁:X锁 19 | 2. 基于数据库的乐观锁:基于版本号 20 | 3. 基于Redis的分布式锁 21 | 4. 基于Zookeeper的分布式锁 22 | 23 | ## 面临的挑战 24 | 1. 死锁问题:线程A获取到了锁,但是程序执行异常,导致锁未及时释放。可通过try catch finally来在finally中执行程序异常释放锁的问题;另外,通过`set key value px nx`仅当key不存在的时候设置key,并设置过期时间(建议毫秒)来保证程序执行超时,锁自动释放。 25 | 2. 释放锁问题:线程A获取到了锁,线程A在某个操作上长时间执行,导致锁过期,自动释放;线程B获取到了这个锁;线程A执行完毕,准备释放锁,因为设置的`value`值一样,所以就释放了线程B的锁。这就要求释放锁的线程必须是加锁的线程,也就是说要给线程加标记,保证锁的唯一性,其实是区分线程,可以使用ThreadLocal+UUID来保证,使用lua脚本删除key,保证释放锁的原子操作。 26 | 3. 锁丢失 - 集群下的故障转移问题:Redis在进行主从复制时是异步完成的,线程A在master获取到了锁,但是在复制数据到slave的过程中master挂了,导致这个锁没有复制到slave中;然后redis选举一个升级为master,那么这个新的master中没有线程A的那个锁,这时候其他线程是可以获取到锁的,导致互斥失效。思路:原master上有线程A的锁,现master上有线程B的锁,那怎么办呢?如果线程B是在线程A获取的锁过期后获取的,就不存在这个互斥问题,或者线程B在px毫秒之后再获取锁,也不存在互斥问题。红锁RedLock 27 | 4. 多节点redis实现的分布式锁算法(RedLock): 有效防止单点故障。思路就是在线程A尝试去这N个节点拿锁,每次去一个节点拿锁的时间不能超过M毫秒,当拿到锁的个数超过总个数/2+1个,就认为拿锁成功。(简单来说是过半机制) 28 | 5. 锁续期 - 如何合理设置px过期时间,太短-逻辑还没走完,就过期了,太长-造成其他线程不必要的等待。太短-可以使用锁续期(redission的watchdog),太长-finally中主动设置过期 29 | 30 | ## 分布式锁的5个特性 31 | 1. 互斥性:在任意时刻 ,只有一个客户端能持有锁。 32 | 2. 不会发生死锁:即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁成功。 33 | 3. 具有容错性:只要大部分的Redis节点运行正常,客户端就可以加锁和解锁。 34 | 4. 解铃还须系铃人:加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。 35 | 5. 锁不能自己失效-续期策略:正常执行程序的过程中,锁不能因为某些原因失效。(控制锁的时间) 36 | 37 | ## 实现方式 38 | 1. SET EX|PX NX + 校验唯一值,再释放锁 39 | 优点:保证加锁的原子性,使用LUA脚本释放锁时,通过判断唯一值(如线程ID+时间戳),锁不会被其他线程释放 40 | 缺点:锁没有自动续期机制,锁无法支持重入 41 | 2. 开源框架Redisson 42 | 优点:锁支持自动续期。只要线程一加锁成功,就会启动一个watch dog看门狗,它是一个后台线程,会每隔10秒检查一下,如果线程1还持有锁,那么就会不断的延长锁key的生存时间。 43 | 缺点:主从模式可能造成锁丢失 44 | 3. Redis集群实现分布式锁Redlock - 红锁 45 | 优点:锁支持自动续期,同时能有效防止锁丢失 46 | 缺点:需要多台redis机器,极端情况下会造成两个线程同时获取锁(如5个节点,线程A拿到了1,2,3的锁,过半,加锁成功,1,2宕机,线程B去拿到了4,5的锁,也过半了,此时线程A,B同时持有锁)。实际项目中很少使用Redlock,因为红锁会影响并发环境下的性能,且耗费服务器 47 | 简化的实现步骤: 48 | ``` 49 | 按顺序向5个master节点请求加锁 50 | 根据设置的超时时间来判断,是不是要跳过该master节点。 51 | 如果大于等于三个节点加锁成功,并且使用的时间小于锁的有效期,即可认定加锁成功啦。 52 | 如果获取锁失败,解锁! 53 | ``` 54 | 使用Redisson实现Redlock。 在Redisson框架中,实现了红锁的机制,Redisson的RedissonRedLock对象实现了Redlock介绍的加锁算法。该对象也可以用来将多个RLock对象关联为一个红锁, 55 | 56 | 每个RLock对象实例可以来自于不同的Redisson实例。当红锁中超过半数的RLock加锁成功后,才会认为加锁是成功的,这就提高了分布式锁的高可用。 57 | ```java 58 | public void testRedLock(RedissonClient redisson1,RedissonClient redisson2, RedissonClient redisson3){ 59 | RLock lock1 = redisson1.getLock("lock1"); 60 | RLock lock2 = redisson2.getLock("lock2"); 61 | RLock lock3 = redisson3.getLock("lock3"); 62 | RedissonRedLock lock = new RedissonRedLock(lock1, lock2, lock3); 63 | try { 64 | // 同时加锁:lock1 lock2 lock3, 红锁在大部分节点上加锁成功就算成功。 65 | lock.lock(); 66 | // 尝试加锁,最多等待100秒,上锁以后10秒自动解锁 67 | boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS); 68 | } catch (InterruptedException e) { 69 | e.printStackTrace(); 70 | } finally { 71 | lock.unlock(); 72 | } 73 | } 74 | ``` 75 | 76 | 参考代码 77 | ------- 78 | ```lua 79 | // 释放锁 80 | if redis.call('get',KEYS[1]) == ARGV[1] then 81 | return redis.call('del', KEYS[1]); 82 | else 83 | return 0; 84 | end; 85 | ``` 86 | 4. 数据库悲观锁X锁 87 | 排它锁,又叫写锁,又叫X锁,如果事务T对A加了X锁,则其他事务不能对A加任何类型的锁 88 | 用法 SELECT * FOR UPDATE 89 | 可利用主键唯一性来达到加锁的目的,此方法并发性能低,同时对锁的过期时间需要额外处理 90 | 5. 基于数据库的乐观锁:基于版本号 91 | 92 | ## 分布式锁常见问题 93 | ### java gc STW (stop the word)导致的锁过期问题 94 | 1. 工作线程1,获取锁,并设置了超时淘汰时长 95 | 2. jvm gc垃圾回收时,会暂停工作线程,即STW 96 | 3. 当工作线程1恢复工作的时候,由于STW的时长稍长,可能锁已经超时淘汰了,但是该线程还不知道,此时工作线程2去获取,也是能获取到的,导致出现多个线程获取同一个锁的异常问题 97 | 这个问题的思路不能放在解决锁的互斥性上,要解决GC。watchdog也解决不了这类问题 98 | 99 | ### 参考文章 100 | * https://cloud.tencent.com/developer/article/1431873 101 | * https://www.cnblogs.com/woshare/p/15253014.html 102 | * https://www.cnblogs.com/crazymakercircle/p/14731826.html -------------------------------------------------------------------------------- /system/architecture/削峰填谷.md: -------------------------------------------------------------------------------- 1 | * 当消费端请求骤增时,可以为其配置排队等待的流控规则,以稳定的速度逐步处理这些请求,起到“削峰填谷”的效果,从而避免流量骤增造成系统负载过高。 -------------------------------------------------------------------------------- /system/architecture/如何设计一个对外安全的接口.md: -------------------------------------------------------------------------------- 1 | # 目录 2 | * [前言](#前言) 3 | * [发](#发) 4 | * [数据加密](#数据加密) 5 | * [传](#传) 6 | * [appid+密钥](#appid+密钥授权模式的传输,不适合需要首次登陆的模式) 7 | * [token机制](#token机制首次认证后开绿灯) 8 | * [防篡改](#防篡改) 9 | * [收](#收) 10 | * [限制流量](#限制流量) 11 | * [黑白名单](#黑白名单) 12 | * [时间戳机制](#时间戳机制) 13 | * [验](#验) 14 | * [数据合法性验证](#数据合法性验证) 15 | 16 | ## 前言 17 | 结合参阅的几篇文章,关于接口的安全性设计,做如下总结。数据传输的过程我认为可以分为`发`、`传`、`收`、`验`四个过程,安全性的设计围绕的也是这4个过程而来。 18 | 19 | ![](img/api.png) 20 | 21 | ## 发 22 | ### `数据加密` 23 | 24 | 数据在传输过程中是很容易被抓包的,如果直接传输比如通过http协议,那么用户传输的数据可以被任何人获取;所以必须对数据加密,常见的做法对关键字段加密比如用户密码直接通过md5加密;现在主流的做法是使用https协议,在http和tcp之间添加一层加密层(SSL层),这一层负责数据的加密和解密; 25 | 26 | 现在主流的加密方式有对称加密和非对称加密: 27 | * `对称加密`:对称密钥在加密和解密的过程中使用的密钥是相同的,常见的对称加密算法有DES,AES;优点是计算速度快,缺点是在数据传送前,发送方和接收方必须商定好秘钥,然后使双方都能保存好秘钥,如果一方的秘钥被泄露,那么加密信息也就不安全了; 28 | * `非对称加密`:服务端会生成一对密钥,私钥存放在服务器端,公钥可以发布给任何人使用;优点就是比起对称加密更加安全,但是加解密的速度比对称加密慢太多了;广泛使用的是RSA算法;RSA公钥每次加密得到的结果都不一样 29 | 30 | 两种方式各有优缺点,而https的实现方式正好是结合了两种加密方式,整合了双方的优点,在安全和性能方面都比较好;对称加密和非对称加密代码实现,jdk提供了相关的工具类可以直接使用;关于https如何配置使用相对来说复杂一些,可以参考本人的之前的文章HTTPS分析与实战 31 | 32 | ## 传 33 | ### `appid+密钥(授权模式的传输,不适合需要首次登陆的模式)` 34 | 需要使用我的API的用户,你首先得到我这注册下信息,然后我发给你一个appid(或者叫appkey),然后给你个密钥,你传过来的数据中都要带这两个参数,并且把这两个参数放到body中,使用https传输,因为Body中的数据在https下是加密的。 35 | 36 | 但是不管是否全局唯一最好让生成的Id有如下属性: 37 | * 趋势递增:这样在保存数据库的时候,使用索引性能更好; 38 | * 信息安全:尽量不要连续的,容易发现规律; 39 | 40 | 关于全局唯一Id生成的方式常见的有类snowflake方式等 41 | 42 | ### `token机制(首次认证后开绿灯)` 43 | 客户端使用用户名和密码请求登录。服务端收到请求,验证用户名和密码。验证成功后,服务端会生成一个token,然后把这个token发送给客户端。客户端收到token后把它存储起来,可以放在cookie或者Local Storage(本地存储)里。客户端每次向服务端发送请求的时候都需要带上服务端发给的token。服务端收到请求,然后去验证客户端请求里面带着token,如果验证成功,就向客户端返回请求的数据。token比较容易被截取,一般会有token的过期时间,或者每隔多长时间会生成新的token,token也要考虑下加密。 44 | 45 | ### `防篡改` 46 | 数据在传输过程中经过加密,理论上就算被抓包,也无法对数据进行篡改;但是我们要知道加密的部分其实只是在外网,现在很多服务在内网中都需要经过很多服务跳转,所以这里的加签可以防止内网中数据被篡改; 47 | 48 | 数据签名使用比较多的是md5算法,常用的做法如下: 49 | 1. 将要提交的数据先加密 50 | 2. 将数据做一次md5摘要,也就是签名 51 | [200526] md5的摘要是将数据和约定的密钥一起做签名,如果单纯摘要数据,那么数据被截取后,通过md5()也可以修改签名,这样服务端就没发验证数据是否被篡改了呀 52 | 3. 然后把摘要连同参数一起回传给服务器 53 | 4. 服务器拿到数据后,同样的方式做一次md5摘要 54 | 5. 两个摘要做对比,如果不相等就认为被篡改了,否则认为可信 55 | 56 | str:参数1={参数1}&参数2={参数2}&……&参数n={参数n}$key={用户密钥}; 57 | MD5.encrypt(str + "哈哈哈,我不告诉你我多加了啥"); 58 | 59 | 注意最后的用户密钥,客户端和服务端都有一份,这样会更加安全; 60 | 61 | ## 收 62 | ### `限流机制` 63 | 限流机制是为了防止恶意频繁请求造成的服务器瘫痪。 64 | 常用的限流算法包括:令牌桶限流,漏桶限流,计数器限流; 65 | 1. 令牌桶限流(能允许刺突,但是不会爆炸,流入的请求都是在能处理的范围之内,请求多了的话就不给你牌子) 66 | 令牌桶算法的原理是系统以一定速率向桶中放入令牌,填满了就丢弃令牌;请求来时会先从桶中取出令牌,如果能取到令牌,则可以继续完成请求,否则等待或者拒绝服务;令牌桶允许一定程度突发流量,只要有令牌就可以处理,支持一次拿多个令牌; 67 | 2. 漏桶限流(只能匀速处理请求) 68 | 漏桶算法的原理是按照固定常量速率流出请求,流入请求速率任意,当请求数超过桶的容量时,新的请求等待或者拒绝服务;可以看出漏桶算法可以强制限制数据的传输速度; 69 | 3. 计数器限流(容易产生刺突) 70 | 计数器是一种比较简单粗暴的算法,主要用来限制总并发数,比如数据库连接池、线程池、秒杀的并发数;计数器限流只要一定时间内的总请求数超过设定的阀值则进行限流; 71 | 72 | 具体基于以上算法如何实现,Google的Guava提供了RateLimiter工具类基于基于令牌桶算法: 73 | 74 | RateLimiter rateLimiter = RateLimiter.create(5); 75 | 以上代码表示一秒钟只允许处理五个并发请求,以上方式只能用在单应用的请求限流,不能进行全局限流;这个时候就需要分布式限流,可以基于redis+lua来实现; 76 | 77 | ### `时间戳机制` 78 | 数据是很容易被抓包的,但是经过如上的加密,加签处理,就算拿到数据也不能看到真实的数据;但是有不法者不关心真实的数据,而是直接拿到抓取的数据包进行恶意请求;这时候可以使用时间戳机制,在每次请求中加入当前的时间,服务器端会拿到当前时间和消息中的时间相减,看看是否在一个固定的时间范围内比如5分钟内;这样恶意请求的数据包是无法更改里面时间的,所以5分钟后就视为非法请求了; 79 | 80 | 解密后的数据,经过签名认证后,我们拿到数据包中的客户端时间戳字段,然后用服务器当前时间去减客户端时间,看结果是否在一个区间内,伪代码如下: 81 | ```java 82 | long interval=5*60*1000;//超时时间 83 | long clientTime=request.getparameter("clientTime"); 84 | long serverTime=System.currentTimeMillis(); 85 | if(serverTime-clientTime>interval){ 86 | return new Response("超过处理时长") 87 | } 88 | ``` 89 | 90 | ### `黑白名单` 91 | * 黑名单:拒绝该ip地址发过来的请求 92 | * 白名单:只允许该ip地址发过来的请求 93 | 94 | ## 验 95 | ### `数据合法性验证` 96 | 这个可以说是每个系统都会有的处理机制,只有在数据是合法的情况下才会进行数据处理;每个系统都有自己的验证规则,当然也可能有一些常规性的规则,比如身份证长度和组成,电话号码长度和组成等等; 97 | 98 | 合法性校验包括:常规性校验以及业务校验; 99 | 常规性校验:包括签名校验,必填校验,长度校验,类型校验,格式校验等; 100 | 业务校验:根据实际业务而定,比如订单金额不能小于0等; 101 | 102 | # 引用 103 | * [如何设计一个安全的对外接口](https://my.oschina.net/OutOfMemory/blog/3131916) 104 | * [为什么RSA公钥每次加密得到的结果都不一样?](https://www.jianshu.com/p/e300f7735c87) 105 | * [美团分布式ID方案](https://github.com/Meituan-Dianping/Leaf) 106 | * [Web数据安全-防篡改](https://blog.csdn.net/wxgxgp/article/details/81257877) 107 | -------------------------------------------------------------------------------- /system/architecture/异地多活总结.md: -------------------------------------------------------------------------------- 1 | # 异地多活设计那么难,其实你想多了 2 | 异地多活本质上是通过异地的数据冗余,来保证在极端异常的情况下业务也能够正常提供给用户,因此数据同步是异地多活设计方案的核心,但我们大部分人在考虑数据同步方案的时候,也会不知不觉的陷入完美主义误区:我要所有数据都实时同步!异地多活设计的理念可以总结为一句话:采用多种手段,保证绝大部分用户的核心业务异地多活。 3 | 4 | 有几种方法可以参考: 5 | * 尽量减少异地多活机房的距离,搭建高速网络; 6 | * 尽量减少数据同步; 7 | * 保证最终一致性,不保证实时一致性; -------------------------------------------------------------------------------- /system/architecture/推荐系统.md: -------------------------------------------------------------------------------- 1 | ### 学习计划 2 | 3 | ### 学习笔记 4 | * 搜索服务必备:数据源、搜索引擎、智能理解语义(能够准确理解用户输入) 5 | * 推荐系统必备:数据集、算法、评价指标(如转化率是否有提升) 6 | * LTR算法:Learning To Rank 7 | * 推荐系统1.0架构 8 | * 使用业务系统及数据库能力建设关键字搜索及二次聚合筛选能力 9 | * 结合lbs(腾讯map service)地理围栏通过距离和评价控制排序策略 10 | * 使用简单的线性推荐策略完成1.0的推荐系统 11 | * 搜索2.0架构 12 | * 通过中文分词器完成中文分词学习 13 | * 通过定制化分词器及同义词扩展丰富搜索准确性 14 | * 通过词性分析及相关性重塑算法打造可理解语义的搜索引擎 15 | * 借助logstash-input-jdbc学习全量及非实时增量的索引构建 16 | * 通过定制化canal中间件完成实时增量索引接入 17 | * 改造点评搜索应用,升级搜索2.0架构 18 | * 通过spark mllib的als算法实现个性化召回体系 19 | * 通过spark mllib的lr算法实现个性化排序体系 -------------------------------------------------------------------------------- /system/architecture/服务端如何防止重复提交.md: -------------------------------------------------------------------------------- 1 | ### 表单重复提交的场景 2 | 1. 服务端未能及时响应,导致前端页面没有及时刷新,用户多次提交 3 | 2. 用户提价表单成功后再次点击刷新按钮重新提交 4 | 5 | ### 重复提交表单带来的问题 6 | 1. 插入重复的数据 7 | 8 | ### 解决方案 9 | > 单机、集群版本 10 | 11 | 1. 前端通过设置标记位进行拦截,在提交的js中处理 12 | 2. 前端通过禁用按钮进行拦截 13 | 3. 前端页面每次请求时服务端返回该页面一个随机token,前端提交的时候把这个token带到后端,后端来做判断 14 | 15 | > 分布式 16 | 17 | 由于分布式的每次请求打到的服务器都不确定,因此需要一个公共的地方来标识这次请求,常用的解决方案是:在数据提交之前,根据规则生成一个key,然后判断这个key在redis中是否存在,如果不存在,则创建并设置过期时间(加锁),然后表单提交,业务结束释放锁(或者到期自动释放)。key的生成是按照用户维度,比如对请求进行md5计算得到一个值(需要考虑),也可以使用类+方法+token的方式来处理 -------------------------------------------------------------------------------- /system/architecture/架构设计随思录.md: -------------------------------------------------------------------------------- 1 | ### 学习笔记 2 | * 系统设计的难处在于,业务,成本,性能,三方面都有需求,但是往往不可能都满足。 3 | * 系统设计注意事项 4 | 1. 系统设计师要考虑后期对研发阶段、运维阶段的影响。 5 | 2. 在技术选型上要对技术的细节有较强的掌控力。 6 | 3. 设计时要带上版本号,为后期升级和线上排查推演提供依据。 7 | * 微服务是以业务拆分和分布式来应对业务复杂度高和重复开发的问题 8 | * 假设在10点到11点这一个小时内,有200W个用户访问我们的系统,假设平均每个用户请求的耗时是3秒,那么计算的结果如下: 9 | ``` 10 | QPS=2000000/60*60 = 556 (表示每秒钟会有556个请求发送到服务端) 11 | RT=3s(每个请求的平均响应时间是3秒) 12 | 并发数=556*3=1668 13 | ``` 14 | ### 架构和程序开发的区别 15 | 架构设计的关键思维是判断和取舍,程序设计的关键思维是逻辑和实现。 16 | 17 | ### 文章 18 | * 微服务与架构师 https://www.cnblogs.com/kiba/p/15497173.html 19 | ``` 20 | 讲了微服务与架构师之间的关系,以及对当前微服务之死的一种理解 21 | ``` -------------------------------------------------------------------------------- /system/architecture/系统架构安全设计.md: -------------------------------------------------------------------------------- 1 | * [如何设计一个对外安全的接口](如何设计一个对外安全的接口.md) 2 | * [反爬虫] 3 | * [SpringCloud确保服务只能通过gateway转发访问,禁止直接调用接口访问]() -------------------------------------------------------------------------------- /system/architecture/系统架构性能设计.md: -------------------------------------------------------------------------------- 1 | * [20万用户同时访问一个热点Key,如何优化缓存架构?](http://note.youdao.com/noteshare?id=76894225f153d8f0c96c3318aeb90b6b) -------------------------------------------------------------------------------- /system/architecture/系统架构设计其他注意事项.md: -------------------------------------------------------------------------------- 1 | * [集群环境下日志合并方案](architecture/集群环境下日志合并方案.md) 2 | * [数据中台架构随想](architecture/数据中台架构随想.md) 3 | * [分布式与微服务有关系吗](https://github.com/zhonghuasheng/Tutorial/wiki/%E5%BE%AE%E6%9C%8D%E5%8A%A1%E4%B8%8E%E5%88%86%E5%B8%83%E5%BC%8F%E6%9C%89%E5%85%B3%E7%B3%BB%E5%90%97) 4 | * TODO: [如何防止表单重复提交]() 5 | * TODO: [Maven+Jenkis+JMeter构建可持续自动化测试部署方案]() 6 | * 日志 7 | * [为什么使用log](architecture/log-note.md) 8 | * [深入理解JAVA日志基础](https://github.com/zhonghuasheng/Tutorial/wiki/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3JAVA%E6%97%A5%E5%BF%97%E5%9F%BA%E7%A1%80) 9 | * [如何解决Apache Server中Catalina.out文件过大的问题 - Cronolog](../../tool/shell/cronolog.md) 10 | * [通过查看access日志来了解系统的访问情况](../../tool/shell/linux命令在tomcat日志中的应用.md) 11 | * Linux 12 | * [Linux常用命令](../../tool/shell/linux.md) 13 | * [实时记录服务器CPU和内存的使用情况](../../tool/shell/linux.md#记录服务器CPU和内存的实时使用情况) 14 | -------------------------------------------------------------------------------- /system/architecture/系统架构高可用设计.md: -------------------------------------------------------------------------------- 1 | * [异地多活](architecture/异地多活.md) 2 | * 饿了么异地多活 3 | * [饿了么多活技术架构及运维挑战(零)](http://note.youdao.com/noteshare?id=84b980a643b09bcce110b73ae6447e1d&sub=wcp1578047241075851) 4 | * [饿了么异地多活技术实现(一)-总体介绍](http://note.youdao.com/noteshare?id=90d83005bebe9192ab31753294931ab7) 5 | * [饿了么异地多活技术实现(二)API-Router的设计与实现](http://note.youdao.com/noteshare?id=7c9ae9f38fb899202e50013243b76003&sub=wcp1578025898948893) 6 | * [饿了么异地多活技术实现(三)GZS&DAL](http://note.youdao.com/noteshare?id=6f714e7c80d1a0a26918fc69e96ecb72&sub=wcp1578028147171312) 7 | * [饿了么异地多活技术实现(四)- 实时双向复制工具(DRC)](http://note.youdao.com/noteshare?id=d496a2af54f7677d4a4548ca8b443fb2&sub=wcp1578028121631563) 8 | * [数据库异地多活方案](http://note.youdao.com/noteshare?id=0132260bad28e1b7eff8237d1b71ecde&sub=wcp1578029015234777) 9 | * [精华 - 异地多活设计辣么难?其实是你想多了!](http://note.youdao.com/noteshare?id=4c69460527777953567bf27e301386f4&sub=80933B302262460289A6132D1D2BFA19) 10 | * [阿里和微博的异地多活方案 - 思考较多](http://note.youdao.com/noteshare?id=ea3f9a9d404a8493eb8671759224e672&sub=wcp1578025746271204) 11 | * [削峰填谷](architecture/削峰填谷.md) 12 | * [58到家MQ如何快速实现流量削峰填谷](http://note.youdao.com/noteshare?id=5b75fab5a151731588d8c25472b52ece&sub=wcp1578276033980908) 13 | * [使用Nginx+Redis+Tomcat实现Session的全局共享、粘性Session](http://note.youdao.com/noteshare?id=61756a339ba0bd5175ec53340ac295ae&sub=wcp1579073336527942) 14 | * [限流](限流.md) -------------------------------------------------------------------------------- /system/architecture/系统设计注意事项.md: -------------------------------------------------------------------------------- 1 | PS: 如下内容是我在日常中阅读到的,从中结合工作/生活的所思,认为比较有借鉴意义的思考,不喜勿碰,取者自思! 2 | 3 | ### 目录 4 | - [目录](#目录) 5 | - [基本原则](#基本原则) 6 | 7 | #### 基本原则 8 | 1. KISS(Keep it simple, stupid): 保持每件事情都尽可能的简单,用简单的解决方案来解决问题。 9 | 2. 爬,走,跑[顺应自然]。通俗来讲,先保证跑通,然后再优化变得更好,然后继续优化让其变得伟大。迭代着做事情,敏捷开发的思路,对于每个功能点,创建里程碑(最大两周),然后去迭代。 10 | 3. 创建稳定、高质量的产品的唯一方法就是自动化测试。自动化测试的脚本在一开始做某些功能时就应该开始做起来,因为自动化测试中涉及逻辑上的验证,后期的更改如果修改了这个逻辑,就会触发错误,在一定程度上能让开发提前发现问题,同时也给QA省出来时间来做更重要的事情。 11 | 4. 开发也要时刻考虑产出比(ROI),不要一直关注技术而忽略使用者,通过与使用者交互来达到解决问题的平衡点。 12 | 5. 要知道一个server时如何运行的,从硬件到操作系统,直到编程语言,优化IO调用的数量是你通往最好架构的首选之路。 13 | 6. 无状态的系统是可直接扩展的。任何时候都要考虑这一点,不要搞个不可扩展的,有状态的东东出来。 14 | 7. 在分布式系统中,你永远无法避免延迟和失败。 15 | 8. 总是要为配置设置一个合理的默认值。 16 | 9. 永远不要悄悄地吞掉或忽略异常,这往往是找bug花几个小时的罪魁祸首。 17 | 10. 梦想着新的编程语言就会变得简单和明了,但往往想要掌握会很难,不要轻易去换编程语言。 18 | 11. 设计系统之初就要考虑后期遇到异常情况怎么还原现场 19 | ``` 20 | 我在做Timing的结伴学习功能的时候,客户端APP从服务端MS获取房间room的信息,然后去腾讯TRTC上麦,上麦成功后TRTC会发回调到MS,整个业务就形成了一个环,APP调TRTC,TRTC给回调给MS,MS提供数据给APP,任何一个环节出现错乱就造成了房间内上麦用户错乱,并且这里还涉及到秒杀(一个房间只有4个位置)的场景,用到分布式锁,但是到了快上线了,测试却测出来了5个用户在一个房间的情况,后面未能再重现。尽管后期我们压测,也未重现,如果当时我们做了详细的log,就能很好的还原当时的场景。另外,一个用户上麦,下麦,进入房间,观众和成员的角色切换,大量的TRTC回调日志充满了这个log,不便于排查,后期复盘觉得当时应该对每个进入房间的用户生成一个trackID,返回给客户端,客户端每次都带过来这个trackID,这样如果这个用户出现了问题,就能直接通过trackId来过滤出属于他的日志。 21 | ``` -------------------------------------------------------------------------------- /system/architecture/限流.md: -------------------------------------------------------------------------------- 1 | ### 限流算法 2 | 1. 计数器算法 3 | 使用计数器实现限流算法,限流策略为在1秒内只允许有100个请求通过,一旦计数满了,拒绝所有的后续请求。假设0.1秒内就达到了100,那么剩下的0.9秒就无法提供服务了,这样在图形上就形成了一个突刺,这种现象称为“突刺现象”。 4 | > PS: 在自己的第三个项目中,Mobila App调用后端的API就是用了这种限流策略,1个用户1s内最多允许调用的10次,使用的是Google的Guava SDK。另外在自己写的秒杀项目中也是用了这种限流算法,具体实现是自定义了一个注解,使用次数的统计是在Redis中做的,将注解添加到需要限流的API接口上。 5 | 6 | 2. 漏桶算法 7 | 漏桶算法通过一个比较大的容器来接收请求,然后另一端匀速取出请求处理,处理速率是固定的,在一定程度上解决了突刺现象。当容器满了,就拒绝请求。设计是容器的容量尽可能承载1s内的请求,代码实现时可以使用队列来存放需要处理的请求。 8 | > PS:在自己的第四个项目中使用了这种类似的策略,不是来限制流量,而是服务端处理不过来,也是采用了漏桶的方式来先接收所有的请求,然后按频率依次处理,使用了LinkedBlockQueue来接收请求。当然也可以使用MQ来做。 9 | 10 | 3. 令牌桶算法 11 | 令牌桶算法在漏桶算法的基础上进行了改进,漏桶算法只能均匀地处理请求,令牌桶可以解决这个问题。令牌桶需要一个容器存储令牌,令牌以一定的速率往令牌桶中存放(避免了突刺现象),当桶中的令牌数量超过了桶的容量,则丢弃掉。当一个请求过来时,需要从令牌桶中获取令牌,获取令牌成功,则请求通过;如果令牌桶中的令牌消耗完毕了,则获取令牌失败,拒绝请求。 12 | 当网络设备衡量流量是否超过额定带宽时,需要查看令牌桶,而令牌桶中会放置一定数量的令牌,一个令牌允许接口发送或接收1bit数据(有时是1 Byte数据),当接口通过1bit数据后,同时也要从桶中移除一个令牌。当桶里没有令牌的时候,任何流量都被视为超过额定带宽,只有当桶中有令牌时,数据才可以通过接口。令牌桶中的令牌不仅仅可以被移除,同样也可以往里添加,所以为了保证接口随时有数据通过,就必须不停地往桶里加令牌,由此可见,往桶里加令牌的速度,就决定了数据通过接口的速度。因此,我们通过控制往令牌桶里加令牌的速度从而控制用户流量的带宽。而设置的这个用户传输数据的速率被称为承诺信息速率(CIR),通常以秒为单位。比如我们设置用户的带宽为1000bit每秒,只要保证每秒钟往桶里添加1000个令牌即可。 13 | 14 | > Google开源的Guava项目中RateLimiter使用的就是令牌通算法 15 | 16 | ### 百问 17 | > Nginx中如何限流 18 | Nginx的限流主要是两种方式:限制访问频率和限制并发连接数。 19 | 1. 限制访问频率(正常流量) 20 | Nginx中我们使用 ngx_http_limit_req_module模块来限制请求的访问频率,基于漏桶算法原理实现。 21 | 2. 限制访问频率(突发流量) 22 | Nginx提供了 burst 参数来解决突发流量的问题,并结合 nodelay 参数一起使用。 23 | burst=20 nodelay表示这20个请求立马处理,不能延迟,相当于特事特办。不过,即使这20个突发请求立马处理结束,后续来了请求也不会立马处理。burst=20 相当于缓存队列中占了20个坑,即使请求被处理了,这20个位置这只能按 100ms一个来释放。这就达到了速率稳定,但突然流量也能正常处理的效果。 24 | 3. 限制并发连接数 25 | Nginx 的 ngx_http_limit_conn_module模块提供了对资源连接数进行限制的功能,使用 limit_conn_zone 和 limit_conn 两个指令就可以了。 26 | * limit_conn perip 20:对应的key是 $binary_remote_addr,表示限制单个IP同时最多能持有20个连接。 27 | * limit_conn perserver 100:对应的key是 $server_name,表示虚拟主机(server) 同时能处理并发连接的总数。注意,只有当 request header 被后端server处理后,这个连接才进行计数。 28 | 29 | > Tomcat中如何限流 30 | 通过maxThreads来限制Tomcat Connector中允许开启的最大线程数,当达到这个值后,请求就会被阻塞 31 | 32 | > SpringCloud Gateway中如何限流 -------------------------------------------------------------------------------- /system/architecture/集群环境下日志合并方案.md: -------------------------------------------------------------------------------- 1 | ### 问题 2 | 项目环境是一个服务器的集群,每次生产环境遇到问题,就需要逐个服务器进行排查,服务器多的情况下就显得很耗时。另外一个潜在的问题是如何服务器运行时间长,服务器上的日志体积增大,如果不定期处理,会造成服务器没有空余磁盘空间,进而引起服务不可用。 3 | 4 | ### 需求 5 | 1. 将服务器上的日志定期同步到单独的一台服务器 6 | 2. 生产环境遇到问题时,开发登陆到log服务器就能查看所有日志 7 | 3. 日志同步的问题,实时同步还是定期(隔天)同步 8 | 9 | ### 解决方案 10 | 1. 使用cronolog对日志进行按天分割 11 | 2. tomcat日志中记录当前服务器的真实IP 12 | 可参考tomcat日志设置 https://blog.csdn.net/loyachen/article/details/47302143 13 | 3. 合并每天的日志 14 | cat file1 file2 | sort -k 2 -t " " > daily-1.log 15 | cat可用于合并日志,-k表示第几个字段,-t 后面接空格表示以空格作为分隔 -------------------------------------------------------------------------------- /system/network/image/TCP-IP.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/system/network/image/TCP-IP.gif -------------------------------------------------------------------------------- /system/network/image/https.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/system/network/image/https.jpg -------------------------------------------------------------------------------- /system/network/image/https_request_process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/system/network/image/https_request_process.png -------------------------------------------------------------------------------- /system/network/network.md: -------------------------------------------------------------------------------- 1 | WebSocket 建立连接需要先通过一个 http 请求进行和服务端握手。握手通过后连接就建立并保持了。 2 | WebSocket 是为了满足基于 Web 的日益增长的实时通信需求而产生的。在传统的 Web 中,要实现实时通信,通用的方式是采用 HTTP 协议不断发送请求。但这种方式即浪费带宽(HTTP HEAD 是比较大的),又消耗服务器 CPU 占用(没有信息也要接受请求) 3 | * WebSocket(1)-- WebSocket API简介 https://blog.csdn.net/yl02520/article/details/7296223 4 | * WebSocket(2)--为什么引入WebSocket协议 https://blog.csdn.net/yl02520/article/details/7298309 5 | * WebSocket与http长连接的区别 https://www.jianshu.com/p/0c61f0e0cd1a 6 | * Socket 与 WebSocket https://blog.zengrong.net/post/socket-and-websocket/ 7 | * WebSocket(二)-WebSocket、Socket、TCP、HTTP区别 https://www.cnblogs.com/merray/p/7918977.html 8 | * TCP连接、Http连接与Socket连接的区别 http://note.youdao.com/noteshare?id=d045b8abde4101cb28892b3dd33f24c4&sub=wcp1578547786163252 9 | * Socket封包、拆包、粘包 http://note.youdao.com/noteshare?id=20da81a278dff7065c2ee932f1be41d6&sub=wcp1578550254412174 10 | * [域名](network/notes/second-level-domain.md) 11 | * [从HTTP到HTTPS到HSTS](network/notes/HTTP_HTTPS_SSL.md) 12 | * [DOS & DDOS的攻与防](https://github.com/zhonghuasheng/Tutorial/wiki/DOS-&-DDOS%E7%9A%84%E6%94%BB%E4%B8%8E%E9%98%B2) 13 | * [为什么是3次握手4次挥手](https://github.com/zhonghuasheng/Tutorial/issues/21) 14 | * [从浏览器输入URL到页面渲染都发生了什么 - 结合Tomcat架构解析](http://note.youdao.com/noteshare?id=cca91d065dc509bae387a16925efa497) 15 | * [彻底了解Cookies](network/彻底了解cookies.md) 16 | * [WebSocket的使用场景](http://note.youdao.com/noteshare?id=46d6403c9651f0fe41473cb11d523870&sub=wcp157847407045929) 17 | * [Http、TCP、Socket区别和使用场景](http://note.youdao.com/noteshare?id=d045b8abde4101cb28892b3dd33f24c4&sub=wcp1578547786163252) 18 | * [Socket粘包、拆包](http://note.youdao.com/noteshare?id=20da81a278dff7065c2ee932f1be41d6&sub=wcp1578550254412174) 19 | -------------------------------------------------------------------------------- /system/network/notes/HTTP_HTTPS_SSL.md: -------------------------------------------------------------------------------- 1 | ### HTTP是什么,为什么需要HTTPS 2 | HTTP中文命名为超文本传输协议是客户端和服务器必须以能够进行通信实现基本通信协议,它涵盖了诸如请求和响应,会话,缓存,身份验证等内容。HTTP协议以明文形式在浏览器和服务器之间传输信息,允许信息通过的网络查看传输的信息。互联网已经深入到每个人的日常生活,社交通讯、工作办公、休闲购物、娱乐游戏、投资理财,繁华的背后,也存在着一些网络诈骗、网络谣言、网络虚假信息等违法行为,已经严重影响互联网经济的正常发展,让人们在依赖互联网的同时,质疑互联网安全,畏惧互联网交易。解决互联网安全问题就需要对传输的信息进行加密处理,因此就有了SSL(Secure Socket Layer安全套接字层) 3 | 4 | HTTP+加密+认证+完整性保护=HTTPS 5 | HTTPS不是应用层的一种新协议,只是HTTP通信接口部分用SSL和TLS协议代替而已。 6 | 7 | ![image](../image/https.jpg) 8 | 9 | ### HTTPS提供了什么 10 | * 安全。HTTPS能有效防止中间人攻击 11 | 针对SSL的中间人攻击方式主要有两类,分别是SSL劫持攻击和SSL剥离攻击 12 | 13 | * SSL劫持攻击 14 | SSL劫持攻击即SSL证书欺骗攻击,攻击者为了获得HTTPS传输的明文数据,需要先将自己接入到客户端和目标网站之间;在传输过程中伪造服务器的证书,将服务器的公钥替换成自己的公钥,这样,中间人就可以得到明文传输带Key1、Key2和Pre-Master-Key,从而窃取客户端和服务端的通信数据; 15 | 16 | 但是对于客户端来说,如果中间人伪造了证书,在校验证书过程中会提示证书错误,由用户选择继续操作还是返回,由于大多数用户的安全意识不强,会选择继续操作,此时,中间人就可以获取浏览器和服务器之间的通信数据 17 | 18 | * SSL剥离攻击 19 | 这种攻击方式也需要将攻击者设置为中间人,之后见HTTPS范文替换为HTTP返回给浏览器,而中间人和服务器之间仍然保持HTTPS服务器。由于HTTP是明文传输的,所以中间人可以获取客户端和服务器传输数据 20 | * 防止流量劫持。针对 http 插入广告,甚至针对 http 强制跳转到其他网页,并且已经可以控制哪些时间段跳转,每个设备跳转几次,以增强隐蔽性。 21 | * 信任。在 chrome 68 以上的浏览器中,http 已经被标注为不安全,如果用户浏览网站时有这样的提示,会对网站产生不好的影响。 22 | 23 | * HTTPS访问过程 24 | 25 | HTTPS在进行数据传输之前会与网站服务器和Web浏览器进行一次握手,在握手时确定双方的加密密码信息。 26 | 1. Web 浏览器将支持的加密信息发送给网站服务器; 27 | 28 | 2. 网站服务器会选择出一套加密算法和哈希算法,将验证身份的信息以证书(证书发布CA机构、证书有效期、公钥、证书所有者、签名等)的形式发送给Web浏览器; 29 | 30 | 3. 当 Web 浏览器收到证书之后首先需要验证证书的合法性,如果证书受到浏览器信任则在浏览器地址栏会有标志显示,否则就会显示不受信的标识。当证书受信之后,Web 浏览器会随机生成一串密码,并使用证书中的公钥加密。之后就是使用约定好的哈希算法握手消息,并生成随机数对消息进行加密,再将之前生成的信息发送给网站; 31 | 32 | 4. 当网站服务器接收到浏览器发送过来的数据后,会使用网站本身的私钥将信息解密确定密码,然后通过密码解密Web浏览器发送过来的握手信息,并验证哈希是否与Web浏览器一致。然后服务器会使用密码加密新的握手信息,发送给浏览器; 33 | 34 | 5. 最后浏览器解密并计算经过哈希算法加密的握手消息,如果与服务发送过来的哈希一致,则此握手过程结束后,服务器与浏览器会使用之前浏览器生成的随机密码和对称加密算法进行加密交换数据。 35 | 36 | ![image](../image/https_request_process.png) 37 | 38 | ### HSTS(强制客户端使用HTTPS) 39 | HSTS在用户访问时无需手动在地址栏输入HTTPS,浏览器会自动采用HTTPS进行访问,避免请求被劫持。 40 | 从 HTTP 到 HTTPS 再到 HSTS,网站的安全系数一直在上升,防止 DNS 劫持、数据泄密的力度也再加大 -------------------------------------------------------------------------------- /system/network/notes/second-level-domain.md: -------------------------------------------------------------------------------- 1 | ### Wikipedia 2 | 3 | `二级域`(或`二级域名`;英语:Second-level domain;英文缩写:SLD)是互联网DNS等级之中,处于顶级域名之下的域。`二级域名是域名的倒数第二个部分`,例如在example.com这个域名中,二级域名是example。 4 | 5 | ### Baidu Baike 6 | 7 | 我国在国际互联网络信息中心(Inter NIC) 正式注册并运行的`顶级域名是CN`,这也是我国的一级域名。在顶级域名之下,我国的二级域名又分为类别域名和行政区域名两类。类别域名共7个,包括用于科研机构的ac;国际通用域名com、top;用于教育机构的edu;用于政府部门的gov;用于互联网络信息中心和运行中心的net;用于非盈利组织的org。而行政区域名有34个,分别对应于我国各省、自治区和直辖市。 8 | 9 | #### 定义 10 | 11 | 1) 二级域名是寄存在主域名之下的域名。 12 | 2) 二级域名属于一个独立的分支,他有自己的收录、快照、PR值、反链等。 13 | 3) 当主域名受到惩罚,二级域名也会连带惩罚。 14 | 15 | ### 二级域名权重对比 16 | 17 | 一般来说权重肯定是一级域名>二级域名>二级目录,但是很多网站都设置了301重定向,就是点击一级域名的时候,由于设置了301重定向,会直接跳转到设置好的二级域名上,这时一级域名的所有权重都转移到二级域名上,这时候一级域名的权重就和二级域名权重是相同的! 18 | 19 | ### 例子 20 | 21 | .com 顶级域名 22 | baidu.com 一级域名 23 | www.baidu.com 二级域名 24 | bbs.baidu .com 二级域名 25 | tieba.baidu .com 二级域名 -------------------------------------------------------------------------------- /system/network/彻底了解cookies.md: -------------------------------------------------------------------------------- 1 | # 前言 2 | 网络早期最大的问题之一是如何管理状态。简而言之,服务器无法知道两个请求是否来自同一个浏览器。当时最简单的方法是在请求时,在页面中插入一些参数,并在下一个请求中传回参数。这需要使用包含参数的隐藏的表单,或者作为URL参数的一部分传递。这两个解决方案都手动操作,容易出错。 3 | 4 | 网景公司当时一名员工Lou Montulli,在1994年将“cookies”的概念应用于网络通信,用来解决用户网上购物的购物车历史记录,目前所有浏览器都支持cookies。 5 | 6 | # cookie是什么 7 | cookie翻译过来是“饼干,甜品”的意思,cookie在网络应用中到处存在,当我们浏览之前访问过的网站,网页中可能会显示:你好,王三少,这就会让我们感觉很亲切,像吃了一块很甜的饼干一样。 8 | 9 | 由于http是无状态的协议,一旦客户端和服务器的数据交换完毕,就会断开连接,再次请求,会重新连接,这就说明服务器单从网络连接上是没有办法知道用户身份的。怎么办呢?那就给每次新的用户请求时,给它颁发一个身份证(独一无二)吧,下次访问,必须带上身份证,这样服务器就会知道是谁来访问了,针对不同用户,做出不同的响应。,这就是Cookie的原理。 10 | 11 | 其实cookie是一个很小的文本文件,是浏览器储存在用户的机器上的。Cookie是纯文本,没有可执行代码。储存一些服务器需要的信息,每次请求站点,会发送相应的cookie,这些cookie可以用来辨别用户身份信息等作用。 12 | 13 | # cookie的类型 14 | 可以按照过期时间分为两类:会话cookie和持久cookie。会话cookie是一种临时cookie,用户退出浏览器,会话Cookie就会被删除了,持久cookie则会储存在硬盘里,保留时间更长,关闭浏览器,重启电脑,它依然存在,通常是持久性的cookie会维护某一个用户周期性访问服务器的配置文件或者登录信息 15 | 16 | 持久cookie 设置一个特定的过期时间(Expires)或者有效期(Max-Age) 17 | 18 | `Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2019 07:28:00 GMT;` 19 | 20 | # cookie的属性 21 | ## cookie的域 22 | 产生Cookie的服务器可以向set-Cookie响应首部添加一个Domain属性来控制哪些站点可以看到那个cookie,例如下面: 23 | `Set-Cookie: name="wang"; domain="www.xxx.com"` 24 | 如果用户访问的是www.xxx.com那就会发送cookie: name="wang", 如果用户访问www.aaa.com(非www.xxx.com)就不会发送这个Cookie。 25 | 26 | ## cookie的路径 Path 27 | Path属性可以为服务器特定文档指定Cookie,这个属性设置的url且带有这个前缀的url路径都是有效的。 28 | 例如:www.xxx.com 和 www.xxx.com/user/这两个url。www.xxx.com 设置cookie 29 | ``` 30 | Set-cookie: id="123432";domain="www.xxx.com"; 31 | ``` 32 | www.xxx.com/user/ 设置cookie: 33 | 34 | ``` 35 | Set-cookie:user="wang", domain="www.xxx.com"; path=/user/ 36 | ``` 37 | 38 | 但是访问其他路径www.xxx.com/other/就会获得 39 | 40 | ``` 41 | cookie: id="123432" 42 | ``` 43 | 如果访问v/user/就会获得 44 | 45 | ``` 46 | cookie: id="123432" 47 | cookie: user="wang" 48 | ``` 49 | 50 | # 安全 51 | 多数网站使用cookie作为用户会话的唯一标识,因为其他的方法具有限制和漏洞。如果一个网站使用cookies作为会话标识符,攻击者可以通过窃取一套用户的cookies来冒充用户的请求。从服务器的角度,它是没法分辨用户和攻击者的,因为用户和攻击者拥有相同的身份验证。 下面介绍几种cookie盗用和会话劫持的例子: 52 | 53 | ## 网络窃听 54 | 网络上的流量可以被网络上任何计算机拦截,特别是未加密的开放式WIFI。这种流量包含在普通的未加密的HTTP清求上发送Cookie。在未加密的情况下,攻击者可以读取网络上的其他用户的信息,包含HTTP Cookie的全部内容,以便进行中间的攻击。比如:拦截cookie来冒充用户身份执行恶意任务(银行转账等)。 55 | 56 | 解决办法:服务器可以设置secure属性的cookie,这样就只能通过https的方式来发送cookies了。 57 | 58 | ## 跨站点脚本XSS 59 | 使用跨站点脚本技术可以窃取cookie。当网站允许使用javascript操作cookie的时候,就会发生攻击者发布恶意代码攻击用户的会话,同时可以拿到用户的cookie信息。 60 | 61 | 例子: 62 | ```html 63 | 领取红包 64 | ``` 65 | 66 | 当用户点击这个链接的时候,浏览器就会执行onclick里面的代码,结果这个网站用户的cookie信息就会被发送到abc.com攻击者的服务器。攻击者同样可以拿cookie搞事情。 67 | 68 | 解决办法:可以通过cookie的HttpOnly属性,设置了HttpOnly属性,javascript代码将不能操作cookie。 69 | 70 | ## 跨站请求伪造CSRF 71 | CSRF(Cross Site Request Forgery) 跨站请求伪造。也被称为One Click Attack和Session Riding,通常缩写为CSRF或XSRF。如果从名字你还不不知道它表示什么,你可以这样理解:攻击者(黑客,钓鱼网站)盗用了你的身份,以你的名义发送恶意请求,这些请求包括发送邮件、发送消息、盗取账号、购买商品、银行转账,从而使你的个人隐私泄露和财产损失。 72 | 73 | ### CSRF攻击实例 74 | 听了这么多,可能大家还云里雾里,光听概念可能大家对于CSRF还是不够了解,下面我将举一个例子来让大家对CSRF有一个更深层次的理解。 75 | 我们先假设支付宝存在CSRF漏洞,我的支付宝账号是lyq,攻击者的支付宝账号是xxx。然后我们通过网页请求的方式 http://zhifubao.com/withdraw?account=lyq&amount=10000&for=lyq2 可以把我账号lyq的10000元转到我的另外一个账号lyq2上去。通常情况下,该请求发送到支付宝服务器后,服务器会先验证该请求是否来自一个合法的session并且该session的用户已经成功登陆。攻击者在支付吧也有账号xxx,他知道上文中的URL可以进行转账操作,于是他自己可以发送一个请求 http://zhifubao.com/withdraw?account=lyq&amount=10000&for=xxx 到支付宝后台。但是这个请求是来自攻击者而不是来自我lyq,所以不能通过安全认证,因此该请求作废。这时,攻击者xxx想到了用CSRF的方式,他自己做了个黄色网站,在网站中放了如下代码:http://zhifubao.com/withdraw?account=lyq&amount=10000&for=xxx 并且通过黄色链接诱使我来访问他的网站。当我禁不住诱惑时就会点了进去,上述请求就会从我自己的浏览器发送到支付宝,而且这个请求会附带我的浏览器中的cookie。大多数情况下,该请求会失败,因为支付宝要求我的认证信息,但是我如果刚访问支付宝不久,还没有关闭支付宝页面,我的浏览器中的cookie存有我的认证信息,这个请求就会得到响应 76 | ,从我的账户中转10000元到xxx账户里,而我丝毫不知情,攻击者拿到钱后逍遥法外。所以以后一定要克制住自己,不要随便打开别人的链接 77 | 78 | # Cookie与Session的区别 79 | * cookie数据存放在客户的浏览器上,session数据放在服务器上; 80 | * cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用session; 81 | * session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能。考虑到减轻服务器性能方面,应当使用COOKIE; 82 | * 单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的COOKIE不能超过3K; 83 | Cookie和Session的方案虽然分别属于客户端和服务端,但是服务端的session的实现对客户端的cookie有依赖关系的,上面我讲到服务端执行session机制时候会生成session的id值,这个id值会发送给客户端,客户端每次请求都会把这个id值放到http请求的头部发送给服务端,而这个id值在客户端会保存下来,保存的容器就是cookie,因此当我们完全禁掉浏览器的cookie的时候,服务端的session也会不能正常使用(注意:有些资料说ASP解决这个问题,当浏览器的cookie被禁掉,服务端的session任然可以正常使用,ASP我没试验过,但是对于网络上很多用php和jsp编写的网站,我发现禁掉cookie,网站的session都无法正常的访问)。 -------------------------------------------------------------------------------- /tool/2023-03-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/tool/2023-03-24.png -------------------------------------------------------------------------------- /tool/api-testing-tool.md: -------------------------------------------------------------------------------- 1 | ## API测试工具(https://www.cnblogs.com/powertoolsteam/p/9772211.html) 2 | 3 | ### SoapUI 4 | * SoapUI是一个开源测试工具,通过soap/http来检查、调用、实现Web Service的功能/负载/符合性测试。该工具既可作为一个单独的测试软件使用,也可利用插件集成到Eclipse,maven2.X,Netbeans 和intellij中使用。SoapUI Pro是SoapUI的商业非开源版本,实现的功能较开源的SoapUI更多。 5 | 6 | * SoapUI支持: 7 | * API测试:Soap协议,Http协议 8 | * 压力测试 9 | * 安全测试 10 | 11 | * 团队协作 12 | * SoapUI:本身一个project是一个xml文件,但是可以通过配置变成一系列文件夹,每个Case、每个Suite均是独立的文件,这样可通过svn/git进行团队协作。支持性较好 13 | 14 | ### Postman 15 | * Postman是由Postdot Technologies公司打造的一款功能强大的调试HTTP接口的工具,它最早是Chrome中最受欢迎的插件之一,现已扩展到Mac,Windows和Linux客户端。 16 | 17 | * Postman支持: 18 | * http协议 19 | * 压力测试 20 | 21 | * 团队协作 22 | * Postman:有团队协作的功能,需要付费。也可以通过Imort/Export 成文件后通过svn/git进行团队协作,一个Collection 可以到处为一个文件。 23 | 24 | #### 综合评价 25 | SoapUI 相对Postman 多了一个Soap 协议测试。根据公司内API测试的要求,如果有需求就会很有用,但我们公司是不需要这个选项的。 26 | SoapUI 的功能复杂,界面使用多窗口方式实现,交互复杂,学习成本高,对于使用人员有较高要求。 27 | SoapUI进行API 测试时,是通过Java 直接发送API 请求,和Fiddler等抓包工具的配合需要额外配置。 28 | SoapUI 测返回内容对用中、日文支持不好,会出现乱码现象。 29 | SoapUI的API测试,自动测试需要更强的编程技能。 30 | Postman 脱胎于Chorme 的插件,只支持Http 协议的测试。 31 | Postman 的界面采用Tab形式,类似chrome 的操作方式,界面简单,功能设计简洁,工程的组织只有Collection 和folder ,层级,概念简洁,易学,易用,对于项目组的学习成本低。 32 | Postman 的API 测试,自动测试对于编程的要求相对低一些,可以从测试人员中挑选人员进行培训,培训后可以胜任API测试。 33 | 16.结论 34 | 综合考虑,如果只是进行Http,https 接口测试建议使用Postman 作为API测试工具,最主要的理由是,简洁易用,学习成本低。 -------------------------------------------------------------------------------- /tool/coding-life.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | * [记录自己的成长](#记录自己的成长) 3 | * [最好的建议](#最好的建议) 4 | * [正视自己的价值](#正视自己的价值) 5 | * [后端避坑心得](#后端避坑心得) 6 | 7 | ### 记录自己的成长 8 | 9 | * 2013-10 收到群硕(上海)软件开发有限公司的Offer 10 | * 2014-03 去群硕扬州实习 11 | * 2014-07 河南中医药大学毕业 12 | * 2014-07 - 2014-09 群硕(上海)软件开发有限公司 13 | * 2017-09 - 2020-06 群硕(武汉)软件开发有限公司 14 | * 2020-06 - 2021-03 武汉氪细胞网络技术有限公司(产品Timing App) 15 | * 千万级的用户量,百万DAU,3000左右的QPS,高并发场景较多。后来,国家对在线教育进行了整改。。。 16 | * 2021-04 - 2022-02 孚创武汉研发中心 17 | * 互联网+的产品,对手是途虎 18 | * 2022-03 - 至今 腾讯云科技 CSIG 19 | * JOOX音乐APP,QQ音乐的海外版 20 | 21 | ### 最好的建议 22 | 我毕业后就进入一家外企,在这家公司学的比较全,不论是技术,思想,管理都有了很大的提升。后期我整理了自己的思考,总结来说就是这几个词,人、事、共赢。管理上,我感觉我们都是做事情的人,那么一帮人,团队氛围很好,做事情很开心,这很重要。所谓的共赢,强调的是个人与企业,个人与其他人之间的关系。 23 | 24 | 1. 不要别人点什么,就做什么 - 做有思想的工程师 25 | ```txt 26 | 单单实现一个产品是不够的,你还必须参与决定怎么实现。好的工程师并不仅仅服从命令,而且还给出反馈,帮助产品的拥有者改进它。 27 | ``` 28 | 2. 推荐自己 29 | ```txt 30 | 将自己的建议和想法或者能促进集体效率的告诉其他人,从集体的角度出发,这也是一种自我推荐。做好自己的工作是本分,尽可能去发光发热。 31 | ``` 32 | 3. 学会带领团队 33 | ```txt 34 | 当今几乎所有的项目不可能靠一己之力完成,必须学会协同工作,一个好的领导者就是善于靠所有人之力,同时发挥每个人的长处,并适当通过做任务的形式促使一部分人提高,来完成整个项目 - 这是一种多赢的局面。带领团队是自我技术实力提升之后的下一个境界。 35 | ``` 36 | 4. 工作不是你的全部 37 | ```txt 38 | 你是一个完整的人,工作不是你的全部,你还有生活,把工作和生活分开,在生活中缓解工作上的压力,这对工作也是一种提升。 39 | ``` 40 | 5. 时刻抓住重点 41 | ```txt 42 | 你处在某一个位置时,对应的就有什么样的责任和义务,抓住此刻的重点,把事情做的完美,同时也要适当抓住下一个提升的重点,为下一次能够胜任更高的位置打好基础。 43 | ``` 44 | 6. 尽职尽责 45 | ```txt 46 | 把属于自己负责的事情做的完美,和自己相关的事情做好,是做事情的底线。总的来说就是对自己的上下游负责。 47 | ``` 48 | 7. 多交朋友 49 | ```txt 50 | 一个人的世界是片面的,在平时的沟通和交流中能获取额外的信息,帮助彼此成长。 51 | ``` 52 | 53 | ### 正视自己的价值 54 | ```txt 55 | 企业最关心的(或者说唯一在乎的)事情,就是增加收入、降低成本。 56 | 企业实际上需要的不是程序员,而是能够帮助它们增加收入、降低成本的人。 57 | 企业雇佣你,是为了让你帮它们完成某个可以增加收入、降低成本的项目,而不只是为了让你追求个人的软件成就。 58 | ``` 59 | 我想说的是,在实现公司价值的同时提升自己的能力,达到双赢的局面。 60 | 61 | ### 新工程师要干的五件事情 62 | * 了解系统的技术架构 63 | * 熟悉开发流程 64 | * 快速弥补项目所需技术 65 | * 从小的任务开始入手 66 | * 写文档 67 | * 可以熟悉项目 68 | * 可以提高表达能力 69 | * 可以提高技术能力,因为只有理解了代码才能表达出来,文档越清晰,就代表思路越清晰 70 | * 可以提高个人影响力,文档写得越好,看的人就越多 71 | 72 | ### 箴言 73 | * 核心链路永远要100%,深知00% 74 | * 隔行如隔山,保持对一个行业的敬畏心 75 | * 不了解行业,平等对话就是神话 76 | * 互联网+不是将互联网的一套塞给传统企业,而是在理解行业的基础之上再发挥互联网的价值 77 | * 烂尾楼产品,最小化可行产品MVP,现有滑板车,再有自行车,再有电动车,再有汽车,不要一下子就开始造汽车,迭代而行 78 | * 团队的战斗力来自一起熬夜,一起关过小黑屋...一起过事;团队的信任来自沟通和每次高质量的交付 79 | * 所以,我们不是要克服舒适区,盲目的挑战自我,而是要寻找合适的挑战区,去把它开拓成新的舒适区。 80 | * 重大问题的解决方案永远不可能在产生这个问题的维度上出现! 81 | 82 | ### 后端避坑心得 83 | 敬畏之心 - 敬畏之心 - 敬畏之心 84 | * 对得到的参数要质疑。前端传来的参数,要判断是否为空;数据库中的字段,要判断是不是一定有值,要看线上的数据 85 | * 写高质量的API。首先要保证结果的正确性,其次要保证健壮性,考虑了所有的异常情况,最后要保证高性能,应对多少量的数据查询不会造成慢API 86 | * 日志一定要打好。关键的日志一定要打好,这对后期排查问题非常重要。 -------------------------------------------------------------------------------- /tool/cronolog.md: -------------------------------------------------------------------------------- 1 | ### 问题描述 2 | Apach服务器会将日志输出到一个文件导致该文件后期过大。思路是将该文件按天切到不同的文件中,cronolog能完美解决这个问题。 3 | 4 | #### 下载工具 https://fossies.org/linux/www/old/cronolog-1.6.2.tar.gz/ 5 | * wget https://fossies.org/linux/www/old/cronolog-1.6.2.tar.gz 6 | 7 | #### 安装 8 | * cd cronolog-1.6.2 9 | * ./configure --prefix=/usr/local/cronolog //安装路径自己指定 10 | * make 11 | * make install 12 | 13 | #### 配置tomcat/bin/catalina.sh文件 14 | 将: 15 | ```sh 16 | touch "$CATALINA_OUT" 17 | if [ "$1" = "-security" ] ; then 18 | ...... 19 | org.apache.catalina.startup.Bootstrap "$@" start \ 20 | >> "$CATALINA_OUT" 2>&1 "&" 21 | else 22 | ...... 23 | org.apache.catalina.startup.Bootstrap "$@" start \ 24 | >> "$CATALINA_OUT" 2>&1 "&" 25 | fi 26 | ``` 27 | 修改为: 28 | ```sh 29 | if [ "$1" = "-security" ] ; then 30 | ...... 31 | org.apache.catalina.startup.Bootstrap "$@" start 2>&1 \ 32 | | /usr/local/cronolog/sbin/cronolog "$CATALINA_BASE"/logs/catalina.%Y-%m-%d.out >> /dev/null & 33 | else 34 | ...... 35 | org.apache.catalina.startup.Bootstrap "$@" start 2>&1 \ 36 | | /usr/local/cronolog/sbin/cronolog "$CATALINA_BASE"/logs/catalina.%Y-%m-%d.out >> /dev/null & 37 | fi 38 | ``` 39 | 此配置会在tomcat启动之前加载cronolog服务,无需将cronolog服务加入系统service 40 | 41 | #### 配置crontab job定期删除日志 42 | 30 3 * * * /bin/find /日志路径/logs/ -mtime +14 -type f -name "catalina*.*.out" -exec /bin/rm -f {} \; 43 | 44 | 建议删除14天以上的文件,根据阿里巴巴开发手册中建议,对于周期性发生的异常便于排查 -------------------------------------------------------------------------------- /tool/deployment.md: -------------------------------------------------------------------------------- 1 | # 常见部署方式 2 | 3 | ## 蓝绿部署 4 | 1. Blue/Green Deployment, 蓝绿部署的目的是减少发布的中断时间、能够快速撤回发布。 5 | 2. 蓝绿部署中一共有两套系统:一套是正在提供服务的系统,标记为“绿色”;另一套是准备发布的系统,标记为“蓝色”。两套系统都是功能完善的,并且正在运行的系统,只是系统版本和对外服务不同。 6 | 3. 蓝色系统经过反复的测试、修改、验证之后成功上线,直接将用户切换到蓝色系统。之前的绿色系统依旧运行,只是不让用户访问到,如果出现问题,直接切换到绿色系统。 7 | 8 | `思考` 9 | 1. 蓝绿部署需要两套环境,费用是需要考虑的,并且维护两套环境,人力成本也要考虑。 10 | 2. 如果蓝色系统和绿色系统共同使用同一个数据库,那么这就意味着在切换蓝色和绿色系统的时候不会涉及到数据的丢失,但是如果本次上线涉及到旧表的修改,则可能会造成蓝色系统部分功能不能正常工作。如果蓝色系统和绿色系统不共同使用同一个数据库,那么在切换蓝色和绿色系统的时候要核对系统的数据,避免在切换的间隙造成数据丢失。 11 | 3. 蓝色系统和绿色系统的切换最好选在夜深人静的时候切换。 12 | 13 | ## 金丝雀发布 14 | 1. Canary Deployment, 和灰度发布同属一种策略,是一种平滑过渡的发布策略。 15 | 2. 金丝雀部署是只有一套系统,逐步替换的方式。 16 | 3. 金丝雀发布的几个步骤 17 | * 准备阶段,脚本、包、配置文件等等 18 | * 从ELB中将“金丝雀”移除,在AWS中称为Outofservice 19 | * 升级“金丝雀”应用 20 | * 对应用进行测试 21 | * 将“金丝雀”服务器重新添加到ELB中 22 | * 测试通过后依次升级其他服务器 23 | 24 | 注释:矿井中的金丝雀 25 | 17世纪,英国矿井工人发现,金丝雀对瓦斯这种气体十分敏感。空气中哪怕有极其微量的瓦斯,金丝雀也会停止歌唱;而当瓦斯含量超过一定限度时,虽然鲁钝的人类毫无察觉,金丝雀却早已毒发身亡。当时在采矿设备相对简陋的条件下,工人们每次下井都会带上一只金丝雀作为“瓦斯检测指标”,以便在危险状况下紧急撤离。 26 | 27 | `思考` 28 | 1. 金丝雀发布后的测试可以通过配置host来访问站点测试 29 | 2. 金丝雀发布同样对一些表结构的修改有局限性 -------------------------------------------------------------------------------- /tool/git.md: -------------------------------------------------------------------------------- 1 | ## Git简介 2 | * https://baike.baidu.com/item/Git/12647237 3 | 4 | ## Github帐号注册 5 | * 注册地址: https://github.com 6 | 7 | ## 本地安装Git客户端 8 | * 下载地址: https://git-scm.com/ 9 | 10 | ## 配置本地Git信息 11 | * 配置邮箱,邮箱是注册Github的邮箱 `git config --global user.email xxx@126.com` 12 | 13 | * 配置用户名,建议使用字母而不是汉字 `git config --global user.name xxx` 14 | 15 | * 查看配置 `git config --list` 16 | 17 | ## 在Github配置SSH-Key 18 | * 参考文章 https://jingyan.baidu.com/article/dca1fa6f756777f1a44052e3.html 19 | 20 | ## 创建自己的代码仓库,并提交一个commit 21 | * 参考文章 https://jingyan.baidu.com/article/8cdccae9269b1f315413cde2.html 22 | 23 | ## Git Architecture 24 | 25 | ![](http://r3rutcmq2.hd-bkt.clouddn.com//githubgit-architecture.jpg) 26 | 1. Workspace: 工作区 27 | 2. Stage:暂存区 28 | 3. Repository: 本地仓库 29 | 4. Remote: 远程仓库 30 | 31 | ### Create a new git branch from an old commit 32 | 33 | * create a new branch and checkout it out 34 | 35 | ```shell 36 | git checkout -b newbranch commitid 37 | ``` 38 | 39 | * create a new branch 40 | 41 | ```shell 42 | git branch newbranch commitid 43 | ``` 44 | 45 | ### Update authuor for commited commit 46 | 47 | ```shell 48 | git commit --amend --author 'Hua Sheng' --email "xiaoyong6906@126.com" 49 | ``` 50 | ### Add tag for a release branch 51 | ```shell 52 | git tag -a V1.0.0 -m "Apr 1 release" 53 | git push --tag 54 | ``` 55 | 56 | ## Commit Message的格式 57 | * 参考[Angular规范](https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#heading=h.greljkmo14y0) 58 | 59 | ### 格式 60 | ``` 61 | (): #id 62 | ``` 63 | `eg` 64 | ``` 65 | feat(login): 添加了Login模块的后台验证逻辑 #11 66 | ``` 67 | 68 | ### 格式说明 69 | 70 | 1. `type`用于说明commit的类别,属于必填字段,只允许使用下面7个标识 71 | ``` 72 | * feat: 新功能(feature) 73 | * fix: 修补bug 74 | * docs: 文档(documentation) 75 | * style: 样式(不影响代码运行的变动) 76 | * refactor: 重构(既不是新增功能,也不是修补的bug的改动) 77 | * test: 增加测试 78 | * chore: 构建过程或辅助工具的变动 79 | ``` 80 | 2. `scope`用于说明commit影响的范围,scope是可选的,可以是多个,中间用,隔开,取值只能从该项目的label中取功能模块的值 81 | 3. `subject`是commit的简单描述,建议使用精简的语言描述,最好不超过50个字符。另外,由于我们是内部项目,commit使用中文描述 82 | 4. `id`是任务的编号,因此每个commit的提交都必须有对应的标号,id加#是能够让Gitlab识别并绑定到现有的任务中。注意#之前和subject是有个空格的 83 | 84 | 85 | ### Issue: 86 | 87 | * fatal: Refusing to fetch into current branch refs/heads/tutorial of non-bare repository 88 | 当你处于分支develop时,这个时候去fetch develop分支的代码的时候就会报这个错误,也就是说不可以在非bare的git仓库中通过fetch快进你的当前分支与远程同步。这个时候你要切换到其他分支,然后再去fetch非当前分支的代码。 89 | 90 | ### .gitignore can not work 91 | > If you already have a file checked in, and you want to ignore it, Git will not ignore the file if you add a rule later. In those cases, you must untrack the file first, by running the following command in your termianl: 92 | ``` 93 | $ git rm --cached . 清楚当前stage 94 | $ git add -A 95 | $ git commit -m 'your message, eg update .gitignore' 96 | ``` 97 | .gitignore文件只是ignore没有被staged(cached)文件 98 | 99 | ### fatal: LF would be replaced by CRLF in .idea/workspace.xml 100 | windows中的换行符为 CRLF,而在Linux下的换行符为LF,所以在执行add . 时出现提示 101 | 工作区的文件都应该用 CRLF 来换行。如果 102 | 改动文件时引入了 LF,提交改动时,git 会警告你哪些文件不是纯 CRLF 文件,但 git 不会擅自修改工作区的那些文件,而是对暂存区(我们对工作区的改动)进行修改。也因此,当我们进行 git add 的操作时,只要 git 发现改动的内容里有 LF 换行符,就还会出现这个警告。 103 | 104 | ``` 105 | rm -rf .git // 删除.git 106 | git config –-global core.autocrlf false //禁用自动转换 107 | git init //初始化git库 108 | git add –all //提交所有修改到暂存区 109 | ``` 110 | 111 | 或者设置workspace project .git目录下的conf文件 112 | ``` 113 | [Core] 114 | ... 115 | autocrlf = false 116 | ``` 117 | 118 | ## 解决github提交代码过慢的问题 119 | * ubuntu下编辑/etc/ssh/ssh_config,windows下在git的安装目录中找,在ssh_config末尾append 120 | ``` 121 | Host github.com 122 | User git 123 | Hostname ssh.github.com 124 | PreferredAuthentications publickey 125 | IdentityFile ~/.ssh/id_rsa 126 | Port 443 127 | ``` 128 | 129 | ## 拉取指定branch代码到各自单独的文件夹 130 | ```shell 131 | #!/bin/bash 132 | #basePath是clone的master分支文件夹的外层文件夹 133 | basePath="/xxx/" 134 | branchs="branch1,branch2" 135 | #要将$branchs分割开,先存储旧的分隔符 136 | OLD_IFS="$IFS" 137 | 138 | #设置分隔符 139 | IFS="," 140 | 141 | #如下会自动分隔 142 | arr=($branchs) 143 | 144 | #恢复原来的分隔符 145 | IFS="$OLD_IFS" 146 | 147 | #遍历数组 148 | for branch in ${arr[@]} 149 | do 150 | #为每个branch创建一个文件夹 151 | cd $basePath 152 | rm -rf $branch 153 | echo "Delete $branch Done......" 154 | mkdir $branch 155 | 156 | #进入master folder并拉取$s分支的代码 157 | cd $basePath/master 158 | git checkout $branch 159 | git pull --all 160 | cp -r ./* $basePath/$branch 161 | 162 | echo "Clone $branch Done......" 163 | done 164 | 165 | #当前是master文件夹,最后切换到master分支 166 | git checkout master 167 | ``` 168 | 169 | ### github和gitee双提交 170 | * 使本地库同时关联GitHub和码云,需要用不同的名称来标识不同的远程库,git给远程库起的默认名称是 origin,就是我们平时fetch/rebase origin那种 171 | 先删除 origin 172 | `git remote rm origin` 173 | 然后关联GitHub的远程库: 174 | `git remote add github git@github.com:xxx(用户名)/xxx(本地库名).git` 175 | 然后关联码云的远程库: 176 | `git remote add gitee git@gitee.com:xxx(用户名)/xxx(本地库名).git` 177 | 然后使用 git remote -v 来查看远程库信息,看到以下信息即表示成功: 178 | `gitee git@gitee.com:xxx/xxx.git (fetch)` 179 | `gitee git@gitee.com:xxx/xxx.git (push)` 180 | `github git@github.com:xxx/xxx.git (fetch)` 181 | `github git@github.com:xxx/xxx.git (push)` 182 | ``` 183 | git fetch github master:master 184 | git rebase github/master 185 | git push github/master 186 | ``` -------------------------------------------------------------------------------- /tool/hutool.md: -------------------------------------------------------------------------------- 1 | ## 学习笔记 2 | ### 简介 3 | * 官方网站 https://www.hutool.cn/docs/#/ 4 | 5 | ### 具体类 6 | * Convert 基础数据类型相互转化 7 | * 时间和日期 8 | * DateUtil 常用时间工具类 9 | * DateTime DateTime时间的处理 10 | * DatePattren 标准日期格式 11 | * ChineseDate 农历日期 12 | * FileUtil 文件帮助类 13 | * IOUtil IO流处理 14 | * StrUtil 字符串工具类 15 | * ArrayUtil 数组工具类 16 | * RandomUtil 随机工具类 17 | * IdUtil 唯一ID工具 18 | * ReUtil 正则工具类 19 | * IdCardUtil 身份证工具类 20 | * DesensitizedUtil 信息脱敏工具类 -------------------------------------------------------------------------------- /tool/intellij.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | 3 | * [idea moudle没有蓝色的小方块](#ideamoudle没有蓝色的小方块) 4 | 5 | ## 本着学习自用的态度 6 | * 参考文章:https://www.cnblogs.com/lubians/articles/12179654.html 7 | * 激活工具:链接:https://pan.baidu.com/s/1gzjNQe2bJ-wQeRTT_mdFGg 提取码:gf3j 8 | 9 | ## 常用设置 10 | 11 | ### 插件 12 | * 插件 Lombook, Easy Code(https://blog.csdn.net/qq_38225558/article/details/84479653) 13 | * RestfulToolkit 将url收集显示,点击url可转到代码 14 | * Grep Console插件能让你的Console丰富多彩,并且还能够过滤控制台输出(过滤的时候先选中要过滤的关键字,然后右键选择Grep) 15 | * Rainbow Brackets 让花括号用不同的颜色标记,别于代码阅读区分 16 | * SequenceDiagram:一键生成时序图.一般用它来生成简单的方法时序图,方便我们阅读代码,特别是在代码的调用层级比较多的时候。 17 | 使用方法很简单,选中方法名(注意不要选类名),然后点击鼠标右键,选择 Sequence Diagram 选项即可! 18 | * EasyCode: Easycode 可以直接对数据的表生成entity、controller、service、dao、mapper无需任何编码,简单而强大。 19 | 20 | ### 配置 21 | 1. 开始没开启显示空格的选项(Setting->Editor->Appearance->show whitespaces) 22 | 一些代码规范会要求编程时使用4个空格缩进而不是tab,好处是在不同编辑器下4个空格的宽度看起来是一致的,而tab则长短不一 23 | 设置好以后,可以按ctrl+alt+L整理格式,然后选中缩进的一部分,如果能选中缩进的一部分,证明是空格。 24 | https://jingyan.baidu.com/article/148a1921cbaaf04d71c3b1ee.html 25 | 26 | ![](png/idea-tab-whitespace.PNG) 27 | 28 | 2. properties文件显示中文。所有的都改成UTF-8 29 | 30 | ![](png/idea-encode-utf8.png) 31 | 32 | 3. 缩放字体 33 | 34 | ![](png/idea-font-size.png) 35 | 36 | ### 社区版IDEA如何添加tomcat服务器 37 | 1. 在pom.xml中plugins节点下添加tomcat-maven-plugin,目前比较稳定的是tomcat7-maven-plugin, tomcat8-maven-plugin支持不是很好 38 | ```xml 39 | 40 | 41 | org.apache.tomcat.maven 42 | tomcat7-maven-plugin 43 | 2.2 44 | 45 | 8080 46 | / 47 | UTF-8 48 | tomcat7 49 | 50 | 51 | 52 | ``` 53 | 54 | 2. 安装smart tomcat插件 55 | ``` 56 | 1. Go to File -> Settings 57 | 2. Click Plugins, search smart tomcat 58 | 3. Install and restart IDEA 59 | 4. Edit Configurations(在IDEA右上边,Run左边的下拉框) 60 | 5. Click +, select Smart Tomcat 61 | 6. Config Tomcat Server, Deployment, Context Path 62 | ``` 63 | 64 | ## 快捷键 65 | * idea常用快捷键设置(改为eclipse相似): File-> Settings -> search eclipse -> Keymap(change to Eclipse) 66 | ``` 67 | ctrl + alt +B 查看接口的实现类 68 | ctrl + e 查看Recent Files 69 | Alt + Ins 实现接口的方法,toString(), 构造函数,重写方法 70 | double shift调出Everywhere Search 71 | ``` 72 | ## FAQ 73 | ### requested without authorization, you can copy URL and open it in browser to trust it 74 | ``` 75 | Settings > Build, Execution.. > Debugger 勾选Allow unsigned requests 76 | ``` 77 | ### IDEA 无法找到jdk,只能找到jre解决方式 78 | ``` 79 | 在IDEA的菜单栏中选中File, 选中Project Structure, 然后,弹出来的对话框左边有一个SDK单击它, 在中间的一栏中有个+号单击它,一单击会出现Add New SDK然后选中第一个JDK; 80 | ``` 81 | ### IntelliJ IDEA:无法创建Java Class文件 82 | ``` 83 | 右键新建不了java class文件 84 | File -> Project Structure -> Project Settings -> Modules 85 | 选中 mian folder,然后邮件设置为Sources 86 | 保存 87 | ``` 88 | 89 | ### idea moudle没有蓝色的小方块 90 | * https://blog.csdn.net/wt_better/article/details/86380826 91 | 1. 右边Maven -> Generate Source and Update Project 92 | 2. 更新.idea中的modules.xml 93 | 94 | ### java.nio.charset.MalformedInputException: Input length = 1 95 | 1. 可能是编码问题 96 | 2. 配置文件,ctrl+x, ctrl+v解决 97 | 98 | ### IDEA右下角显示内存指示器 99 | 双shift,输入 Show Memory Indicator 100 | 101 | ### DBeaver连接mysql时Public Key Retrieval is not allowed 102 | 编辑连接->驱动属性->allowPublicKeyRetrieval=TRUE -------------------------------------------------------------------------------- /tool/maven.md: -------------------------------------------------------------------------------- 1 | ### 配置与安装 2 | tar -zxvf apache-maven-3.5.3-bin.tar.gz /usr/local/ 3 | vi ~/.bashrc 4 | export M2_HOME=/usr/local/apache-maven-3.5.3 5 | export PATH=${M2_HOME}/bin:$PATH 6 | source ~/.bashrc 7 | mvn -v 8 | ### 添加阿里镜像 9 | 找到.m2/settings.xml文件 10 | 11 | ``` 12 | 13 | 14 | alimaven 15 | aliyun maven 16 | http://maven.aliyun.com/nexus/content/groups/public/ 17 | central 18 | 19 | 20 | ``` 21 | 22 | ### Configure Proxy 23 | 24 | * Configure in settings.xml 25 | 26 | ``` 27 | 28 | 29 | myhttpproxy 30 | true 31 | http 32 | 192.168.1.2 33 | 3128 34 | localhost 35 | 36 | 37 | myhttpsproxy 38 | true 39 | https 40 | 192.168.1.2 41 | 3128 42 | localhost 43 | 44 | 45 | ``` 46 | 47 | * Using mvn command 48 | 49 | ``` 50 | -Dhttps.proxyHost=x.x.x.x -Dhttps.proxyPort=? 51 | 52 | `example` mvn install -Dhttp.proxyHost=10.10.0.100 -Dhttp.proxyPort=8080 -Dhttp.nonProxyHosts=localhost|127.0.0.1 53 | 54 | ``` -------------------------------------------------------------------------------- /tool/png/CNZZ网站流量统计分析.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/tool/png/CNZZ网站流量统计分析.PNG -------------------------------------------------------------------------------- /tool/png/git-file-status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/tool/png/git-file-status.png -------------------------------------------------------------------------------- /tool/png/git-file-storage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/tool/png/git-file-storage.png -------------------------------------------------------------------------------- /tool/png/idea-encode-utf8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/tool/png/idea-encode-utf8.png -------------------------------------------------------------------------------- /tool/png/idea-font-size.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/tool/png/idea-font-size.png -------------------------------------------------------------------------------- /tool/png/idea-tab-whitespace.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhonghuasheng/Tutorial/8020e588b124c0141e90aba6d956a337bf123a0c/tool/png/idea-tab-whitespace.PNG -------------------------------------------------------------------------------- /tool/postman.md: -------------------------------------------------------------------------------- 1 | ### Linux下安装Postman 2 | wget https://dl.pstmn.io/download/latest/linux64 -O chromecj.com-postman.tar.gz 3 | sudo tar -xzf chromecj.com-postman.tar.gz -C /opt 4 | rm chromecj.com-postman.tar.gz 5 | sudo ln -s /opt/Postman/Postman /usr/bin/postman 6 | 启动时执行postman即可,当然也可以设置快捷启动方式 7 | 8 | cat > ~/.local/share/applications/postman.desktop < /root/luke/ci/auto-commit-tutorial.log 70 | 10 3 * * * /root/luke/ci/auto-commit-musicstore-jsp.sh > /root/luke/ci/auto-commit-musicstore-jsp.log 71 | 72 | 73 | # musicstore-jsp 74 | server { 75 | listen 80; 76 | server_name musicstore-jsp.justdo.fun; 77 | # root /root/luke/ci/apache-tomcat-8.5.42/webapps/musicstore; 78 | location / { 79 | proxy_pass http://127.0.0.1:8018; 80 | } 81 | } 82 | 83 | 84 | sslocal -s ip -p remotepot -k pwd -m rc4-md5 -l localport -b 0.0.0.0 & 85 | 86 | #!/bin/sh 87 | nohup java -jar -Dserver.port=9999 /root/luke/ci/services/musicstore-1.0-SNAPSHOT.jar & 88 | -------------------------------------------------------------------------------- /tool/shell/linux.md: -------------------------------------------------------------------------------- 1 | ### 学习笔记 2 | * [Zero-Copy的前世今生](http://note.youdao.com/noteshare?id=872d76d04ec285d105c3d31d68dbcc00&sub=FF49E845C211478B9777CBBAEFA6A753) 3 | 4 | * 清空文件 sudo sh -c "echo '' > a.txt" 5 | * 重命名 mv folderAName newFolderName 6 | * 创建软链 ln -s sourcefile targetfile 7 | > ln -s /xxx/xx/eclipse eclipseLink 8 | * 使用代理下载文件 wget -e use_proxy=yes -e http_proxy=x.x.x.x:1080 9 | * 设置ulimit sudo sh -c "ulimit -n 65535 && exec su userA" 10 | ## 网络篇 11 | ### ssh 12 | * lsof -i:22 13 | * 安装基础工具 14 | * sudo apt-get install openssh-server openssh-client 15 | ### 查看所有开放的端口 16 | * 可以通过`netstat -anp`来查看哪些端口被打开 17 | * -a 显示所有 18 | * -n 不用别名显示,只用数字显示 19 | * -p 显示进程号和进程名 20 | * `netstat -natpl` 显示tcp的侦听端口 21 | * `netstat -naupl` 显示udp的侦听端口 22 | ### CentOS7开放端口:CentOS7已经使用firewall作为防火墙,不再使用iptables 23 | * root用户 24 | * 开启防火墙 systemctl start firewalld.service 25 | * 开启端口 firewall-cmd --zone=public --add-port=50013/tcp --permanent 26 | * --zone-public:表作用域的公共 27 | * --add-port=8080/tcp:添加tcp协议的端口为8080 28 | * --permanent: 永久生效,无此参数表示临时生效 29 | * 重启防火墙 systemctl restart firewalld.service 30 | * 重新载入配置 firewall-cmd --reload 31 | * firewall-cmd --list-ports 32 | 33 | ### 测试域名能不能解析 34 | * nslookup server 35 | * eg: `nslookup www.baidu.com` 36 | 37 | ### 测试端口是否开放 38 | * `telnet ip port` 39 | 40 | ### Linux邮件服务器:Postfix 41 | http://cn.linux.vbird.org/linux_server/0380mail.php 42 | 43 | * Linux输出重定向 44 | ``` 45 | linux 环境中支持输入输出重定向,用符号<和>来表示。 46 | 0、1和2分别表示标准输入、标准输出和标准错误信息输出, 47 | 将一个脚本的执行过程及执行结果打印到日志的常用命令: 48 | ./myscript.sh 2>&1 | tee mylog.log 49 | 可以用来指定需要重定向的标准输入或输出,比如 2>a.txt 表示将错误信息输出到文件a.txt中。 50 | 同时,还可以在这三个标准输入输出之间实现重定向,比如将错误信息重定向到标准输出,可以用 2>&1来实现。 51 | Linux下还有一个特殊的文件/dev/null,它就像一个无底洞,所有重定向到它的信息都会消失得无影无踪。这一点非常有用,当我们不需要回显程序的所有信息时,就可以将输出重定向到/dev/null。 52 | ``` 53 | * 查看环境变量 env | grep -E 'M2|MAVEN' 54 | 55 | ### Shadowsocks服务器端安装 56 | * 安装pip `curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py` 有可能python的版本低了 57 | * python get-pip.py 58 | * pip install shadowsocks 59 | * 配置shadowsocks 60 | * vi /etc/shadowsocks.json 61 | ```json 62 | { 63 | "server":"0.0.0.0", 64 | "server_port":0, 65 | "local_port":1080, 66 | "password":"xxx", 67 | "timeout":600, 68 | "method":"aes-256-cfb" 69 | } 70 | ``` 71 | * 将shadowsocks加入系统服务 72 | * vi /etc/systemd/system/shadowsocks.service 73 | ```xml 74 | [Unit] 75 | Description=Shadowsocks 76 | [Service] 77 | TimeoutStartSec=0 78 | ExecStart=/usr/local/bin/ssserver -c /etc/shadowsocks.json 79 | [Install] 80 | WantedBy=multi-user.target 81 | ``` 82 | ```shell 83 | # 设置开机自启命令 84 | systemctl enable shadowsocks 85 | 86 | # 启动命令 87 | systemctl start shadowsocks 88 | 89 | #查看状态命令 90 | systemctl status shadowsocks 91 | ``` 92 | * 客户端 93 | * 创建一个sh脚本,加入 `nohup sslocal -s remoteserverip -p remoteserverport -b 127.0.0.1 -l localserverport -k password -m aes-256-cfb >/dev/null 2>&1 &` 94 | 95 | nohup sslocal -s 3.14.3.65 -p 15432 -b 127.0.0.1 -l 1080 -k abc123_ -m aes-256-cfb >ssl.log 2>&1 & 96 | 97 | # 记录服务器CPU和内存的实时使用情况 98 | ```shell 99 | #!/bin/bash 100 | fileName=$1 101 | 102 | echo "CPU%,MEM%,TIME" > $fileName 103 | for (( i = 0; i < 3000; i++ )) do 104 | output=`top -b -n1 | grep "Cpu(s)" | awk '{print $2 ","}' | tr -d '\n' && free -m | grep 'Mem' | awk '{print $3/$2 * 100 ","}' | tr -d '\n' && date | awk '{print $4}'`>temp 105 | echo "$output" >> $fileName 106 | sleep 1 107 | done 108 | ``` 109 | * cat redis.conf | grep -v "#" | grep -v "^$" 查看配置文件,去除所有的#,去除所有的空格 110 | # Linux中禁止修改目录及内部文件,这个命令我用在了缩小nginx的权限,将静态文件放在tmp目录下,nginx user能够访问 111 | 单个文件 chattr +i aaa.txt 112 | 去除则chattr -i aaa.txt 113 | 目录及文件 chattr -R +i ttt 114 | 使用 chattr -R +i A (-R 递归地修改目录以及其下内容的属性) , 即可保护好A目录下的所有内容. 115 | 设置了’i’属性的文件不能进行修改,只有超级用户可以设置或清除该属性. 116 | 117 | # Linux命令在tomcat中的应用 118 | * 模板 119 | 120 | `192.168.1.189 - - [03/May/2019:19:47:21 +0000] "GET /html/css/main.css?browserId=other HTTP/1.1" 200 19858` 121 | 122 | `注意` 123 | 1. access log的配置,格式不一定和上面的log一样 124 | 2. cut -f1 -d " "是按照空格来截取字符串的, -fn表示第几个 125 | 126 | * 访问量排名前20的IP地址 127 | ```shell 128 | cat access_log.2019-0* | cut -f1 -d " " | sort | uniq -c | sort -k 1 -n -r | head -20 129 | ``` 130 | 131 | * 访问量排名前20的页面url 132 | ```shell 133 | cat access_log.2019-0* | cut -f7 -d " " | sort | uniq -c | sort -k 1 -n -r | head -20 134 | ``` 135 | * 查看最耗时页面 136 | ```shell 137 | cat access_log.2019-0* | sort -k 10 -n -r | head -20 138 | ``` 139 | 140 | * 统计4xx/5xx 请求的占比 141 | ```shell 142 | total requests: wc -l access_log.2019-0* 143 | 404 requests: awk '$9=='404'' access_log.2019-0* | wc -l 144 | 500 requests: awk '$9=='500'' access_log.2019-0* | wc -l 145 | ``` 146 | 147 | * 查找包含某个关键字的log 148 | ```shell 149 | awk '/keywords/' access_log* | head -10 150 | awk '/keywords/{print $5,$6}' access_log* | head -10 // 查找包含keywords的关键字并打印第5/6列 151 | ``` 152 | ### vim编辑文件 153 | * 现在还不是在编辑模式,需要在键盘上输入i键进入 154 | * 比如删除第六行,将光标移至要删除的第六行,连续输入两次小写的d,即dd 155 | 156 | ### CentOS查看实时网络带宽占用 157 | * 安装iftop, yum install iftop 158 | * 查看网卡 ifconfig 159 | * iftop -i eth0 160 | 161 | ### 保持server与client的连接不掉 162 | 修改ssh配置文件 /etc/ssh/sshd_config,添加或者修改ClientAliveInterval为“ClientAliveInterval 60”。这个参数的是意思是每1分钟,服务器向客户端发一个消息,用于保持连接。保存后记得重启ssh服务`service sshd restart`。 163 | 164 | ### 百问 165 | > 65535怎么来的 166 | 计算机是按照二进制储存数据的,一般用 unsigned int 这种数据类型来储存正整数 167 | 在计算机中,每个整数都是用 16 位 2 进制数来表示的,所以最大的数就是 16 个 1,也就是 11111111 11111111 168 | 把二进制数 11111111 11111111 转化位十进制数就是 65535 169 | 170 | > Linux下profile和bashrc区别 171 | 1. /etc/profile 172 | 用来设置系统环境参数,比如$PATH. 这里面的环境变量是对系统内所有用户生效的。 173 | 2. /etc/bashrc 174 | 这个文件设置系统bash shell相关的东西,对系统内所有用户生效。只要用户运行bash命令,那么这里面的东西就在起作用。 175 | 3. ~/.bash_profile 176 | 用来设置一些环境变量,功能和/etc/profile 类似,但是这个是针对用户来设定的,也就是说,你在/home/user1/.bash_profile 中设定了环境变量,那么这个环境变量只针对 user1 这个用户生效. 177 | 4. ~/.bashrc 178 | 作用类似于/etc/bashrc, 只是针对用户自己而言,不对其他用户生效。 179 | 另外/etc/profile中设定的变量(全局)的可以作用于任何用户,而~/.bashrc等中设定的变量(局部)只能继承/etc/profile中的变量,他们是”父子”关系. 180 | -------------------------------------------------------------------------------- /tool/todo.md: -------------------------------------------------------------------------------- 1 | 20220101 2 | -------- 3 | * ~~RedisLock 红锁 与 Redission中的分布式锁区别~~ -> 数据库中的锁 4 | * ~~消息平台架构图绘制~~ 5 | * ~~SpringCloud知识点整理~~ -> 可以继续完善 6 | * MQ常见问题整理 7 | * ZGC梳理(CMS的三次标记一次清除[浮动垃圾]流程)-> 待整理(整理到了processon),后期整理到github 8 | * ~~Mybatis中${}和#{}区别~~ 9 | * AQS整理 10 | 20220111 11 | -------- 12 | * RocketMQ实现事务消息机制 13 | * Kafka实现事务消息机制 14 | * Zookeeper实现分布式锁方案和代码 15 | * MySQL源码分析 -------------------------------------------------------------------------------- /tool/tools.md: -------------------------------------------------------------------------------- 1 | ### 持久化相关 2 | * Flyway 是一款开源的数据库版本管理工具,它更倾向于规约优于配置的方式。Flyway 可以独立于应用实现管理并跟踪数据库变更,支持数据库版本自动升级,并且有一套默认的规约,不需要复杂的配置,Migrations 可以写成 SQL 脚本,也可以写在 Java 代码中,不仅支持 Command Line 和 Java API,还支持 Build 构建工具和 Spring Boot 等,同时在分布式环境下能够安全可靠地升级数据库,同时也支持失败恢复等。 3 | 4 | * DB连接工具 5 | * DBeaver Community https://dbeaver.io/ 6 | * Yearning MySQL DBA SQL审计 http://yearning.io/ 7 | 8 | * S3 9 | * Minio是GlusterFS创始人之一Anand Babu Periasamy发布新的开源项目。Minio兼容Amason的S3分布式对象存储项目,采用Golang实现,客户端支持Java,Python,Javacript, Golang语言。Minio可以做为云存储的解决方案用来保存海量的图片,视频,文档。由于采用Golang实现,服务端可以工作在Windows,Linux, OS X和FreeBSD上。 10 | * Aliyun 11 | * Tablestore 表格存储(集存储和搜索于一体,无需单独构建ES) 12 | * Wide Column: 列存储 13 | * Timeline模型:主要用于消息数据,使用于IM, Feed流和物联网设备 14 | * Timestream模型:适用于时序数据、时空数据 15 | * Grid模型:适用于科学大数据的存储和查询场景 16 | * Tair 阿里云Tair是阿里云数据库Redis企业版,是基于阿里集团内部使用的Tair产品研发的云上托管键值对缓存服务。Tair作为一个高可用、高性能的分布式NoSQL数据库,专注于多数据结构的缓存与高速存储场景,完全兼容Redis协议。相比云Redis社区版,Tair支持更强的性能、更多的数据结构和更灵活的存储方式。专属集群内Redis实例和Redis实例一样。 17 | 18 | * Log 19 | * Flume最早是Cloudera提供的日志收集系统,是Apache下的一个孵化项目,Flume支持在日志系统中定制各类数据发送方,用于收集数据。Flume提供对数据进行简单处理,并写到各种数据接受方(可定制)的能力 。Flume提供了从console(控制台)、RPC(Thrift-RPC)、text(文件)、tail(UNIX tail)、syslog(syslog日志系统),支持TCP和UDP等2种模式,exec(命令执行)等数据源上收集数据的能力。 20 | * Rsyslog 是一个 syslogd 的多线程增强版。它提供高性能、极好的安全功能和模块化设计。 21 | * ELK 22 | * 阿里云SLS日志产品 23 | 24 | ### Linux系统相关 25 | * Terminal 26 | * Linux系统下使用Terminators 27 | * MobaXterm https://mobaxterm.mobatek.net/ 28 | 29 | ### 搜索相关 30 | * 搜索 31 | * magi.com AI智能搜索 32 | 33 | ### OutofBox框架 34 | * 框架 35 | * Ant Design Pro前端中后台开箱即用的框架 https://pro.ant.design/ 36 | * Liferay 功能丰富的CMS系统 37 | 38 | ### 开发相关 39 | * 代码行统计工具 40 | * cloc.exe windows中cmd使用cloc.exe folderPath/ 41 | * IDEA plugin statistic 42 | * Java诊断工具 43 | * 阿里JAVA诊断工具Arthas 44 | 45 | ### 帮助类相关 46 | * Hutool是一个Java工具包类库,对文件、流、加密解密、转码、正则、线程、XML等JDK方法进行封装,组成各种Util工具类 -------------------------------------------------------------------------------- /tool/vscode-settings.md: -------------------------------------------------------------------------------- 1 | ``` 2 | { 3 | "editor.renderWhitespace": true, 4 | "editor.tabSize":4, 5 | "editor.folding": true, 6 | "diffEditor.ignoreTrimWhitespace": true, 7 | "files.trimTrailingWhitespace": true, 8 | "editor.insertSpaces": true, 9 | "update.channel": "none", 10 | "vsicons.dontShowNewVersionMessage": true, 11 | "spell.StopAsking": true 12 | } 13 | ``` 14 | * vscode相同内容多选,同时修改: 先选中所要修改的内容,然后按 `ctrl + alt + l`,接着进行修改,修改完后保存,再次按`ctrl + alt + l`释放操作 15 | * 多行成一行:选中全部-> ctrl+alt+j --------------------------------------------------------------------------------