├── LICENSE ├── README.en.md ├── README.md ├── algorithm算法 └── 10大排序算法.md ├── db └── mysql │ └── mysql基于binlog日志还原数据.md ├── docker ├── Docker 给运行中的容器设置端口映射的方法.md ├── Jenkins.md ├── docker 更新配置.md ├── docker-compose │ ├── mysql │ │ ├── ReadMe.md │ │ ├── conf │ │ │ ├── my.cnf │ │ │ └── my2.cnf │ │ └── docker-compose.yml │ └── mysql主从 │ │ ├── ReadMe.md │ │ ├── docker-compose.yml │ │ ├── error.md │ │ ├── init-node.sh │ │ ├── master.cnf │ │ └── slave.cnf ├── docker-elasticsearch.md ├── docker-gitlab.md ├── docker-gitlab修改域名配置.md ├── docker-gitlab内存占用太多.md ├── docker-hbase.md ├── docker-mongo-恢复备份.md ├── docker-mongodb.md ├── docker-mysql.md ├── docker-redis.md ├── docker-sonarqube.md ├── docker-yapi.md ├── docker-禅道.md ├── docker.md ├── docker国内镜像.md ├── docker清理空间.md ├── docker部署jar.md ├── docker限制资源内存cpu.md ├── git │ └── docker-gitea.md ├── jenkins重置密码.md ├── mq │ └── docker-rocketmq.md ├── nexus私服 │ └── docker-nexus.md └── 注册中心 │ ├── docker-nacos.md │ └── docker-zookeeper.md ├── ide ├── eclipse │ └── eclipse 设置启动jdk版本.md └── idea │ └── idea模板.md ├── images └── basic │ └── algorithm.png ├── js └── file │ └── excel_deal.md ├── linux ├── linux编译安装nginx.md └── ubuntu │ ├── dpkg.md │ └── 错误解决.md ├── maven └── Maven定制化打包后的包名(加入时间戳).md ├── mq ├── RocketMQ 怎么保证的消息不丢失.md └── rocketmq-start-linux.md ├── tool └── alibaba-tool.md ├── 持续集成 ├── git │ ├── Git 中 SSH key 生成步骤.md │ ├── gitlab令牌.md │ ├── gitlab重置密码.md │ ├── git分支命令.md │ └── git记住密码.md ├── gitea.md └── jenkins │ ├── build-front.md │ ├── jenkins-docker安装.md │ ├── jenkins安装.md │ ├── shell 到达一定数量文件自动删除最久时间文件.md │ ├── shell以日期重命名.md │ ├── ubuntu-install-jenkins.md │ ├── webhooks配置.md │ └── 使用shell脚本删除30天以前的文件.md ├── 版本控制器 └── git │ └── git同时提交到2个仓库gitee.github.md ├── 问题排查 └── JAVA 线上故障排查完整套路,从 CPU、磁盘、内存、网络、GC 一条龙.md └── 高效工作 ├── 时间管理.png └── 时间管理.xmind /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.en.md: -------------------------------------------------------------------------------- 1 | # javaRoad 2 | 3 | #### Description 4 | java学习之路,包含基础、高并发、高可用、分布式、微服务知识 5 | 6 | #### Software Architecture 7 | Software architecture description 8 | 9 | #### Installation 10 | 11 | 1. xxxx 12 | 2. xxxx 13 | 3. xxxx 14 | 15 | #### Instructions 16 | 17 | 1. xxxx 18 | 2. xxxx 19 | 3. xxxx 20 | 21 | #### Contribution 22 | 23 | 1. Fork the repository 24 | 2. Create Feat_xxx branch 25 | 3. Commit your code 26 | 4. Create Pull Request 27 | 28 | 29 | #### Gitee Feature 30 | 31 | 1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md 32 | 2. Gitee blog [blog.gitee.com](https://blog.gitee.com) 33 | 3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) 34 | 4. The most valuable open source project [GVP](https://gitee.com/gvp) 35 | 5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) 36 | 6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # javaRoad 2 | 3 | #### 介绍 4 | java学习之路,包含基础、高并发、高可用、分布式、微服务知识 5 | 6 | ##目录 7 | -[基础]() 8 | -[java基础]() 9 | -[10大排序算法](algorithm算法/10大排序算法.md) 10 | -[数据结构算法]() 11 | 12 | -[JVM]() 13 | -[Docker]() 14 | -[docker-compose]() 15 | -[mysql](docker/docker-compose/mysql/ReadMe.md) 16 | -[mysql主从](docker/docker-compose/mysql主从/ReadMe.md) 17 | -[docker清理空间](docker/docker清理空间.md) 18 | 19 | -[Linux]() 20 | -[ubuntu]() 21 | -[dpkg用法](linux/ubuntu/dpkg.md) 22 | -[linux编译安装nginx.md](linux/linux编译安装nginx.md) 23 | -[持续集成](持续集成) 24 | -[jenkins](持续集成/jenkins) 25 | -[jenkins安装](持续集成/jenkins/jenkins安装.md) 26 | -[jenkins-docker安装.md](持续集成/jenkins/jenkins-docker安装.md) 27 | -[nexus私服](docker/nexus私服/docker-nexus.md) 28 | -[gitea](持续集成/gitea.md) 29 | -[问题排查](问题排查) 30 | -[JAVA 线上故障排查完整套路,从 CPU、磁盘、内存、网络、GC 一条龙.md](问题排查/JAVA%20线上故障排查完整套路,从%20CPU、磁盘、内存、网络、GC%20一条龙.md) 31 | -[dpkg用法](linux/ubuntu/dpkg.md) 32 | -[高效工作] 33 | -[时间管理](高效工作/时间管理.png) 34 | 35 | 36 | #### 安装教程 37 | 38 | 1. xxxx 39 | 2. xxxx 40 | 3. xxxx 41 | 42 | #### 使用说明 43 | 44 | 1. xxxx 45 | 2. xxxx 46 | 3. xxxx 47 | 48 | #### 参与贡献 49 | 50 | 1. Fork 本仓库 51 | 2. 新建 Feat_xxx 分支 52 | 3. 提交代码 53 | 4. 新建 Pull Request 54 | 55 | 56 | #### 码云特技 57 | 58 | 1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md 59 | 2. 码云官方博客 [blog.gitee.com](https://blog.gitee.com) 60 | 3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解码云上的优秀开源项目 61 | 4. [GVP](https://gitee.com/gvp) 全称是码云最有价值开源项目,是码云综合评定出的优秀开源项目 62 | 5. 码云官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) 63 | 6. 码云封面人物是一档用来展示码云会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) 64 | -------------------------------------------------------------------------------- /algorithm算法/10大排序算法.md: -------------------------------------------------------------------------------- 1 | 十大经典排序算法最强总结(JAVA代码实现) 2 | 最近几天在研究排序算法,看了很多博客,发现网上有的文章中对排序算法解释的并不是很透彻,而且有很多代码都是错误的,例如有的文章中在“桶排序”算法中对每个桶进行排序直接使用了Collection.sort()函数,这样虽然能达到效果,但对于算法研究来讲是不可以的。所以我根据这几天看的文章,整理了一个较为完整的排序算法总结,本文中的所有算法均有JAVA实现,经本人调试无误后才发出,如有错误,请各位前辈指出。 3 | 0、排序算法说明 4 | 0.1 排序的定义 5 | 对一序列对象根据某个关键字进行排序。 6 | 7 | 0.2 术语说明 8 | 9 | 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面; 10 | 不稳定:如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面; 11 | 内排序:所有排序操作都在内存中完成; 12 | 外排序:由于数据太大,因此把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行; 13 | 时间复杂度: 一个算法执行所耗费的时间。 14 | 空间复杂度:运行完一个程序所需内存的大小。 15 | 0.3 算法总结 16 | 17 | 18 | 图片名词解释: 19 | 20 | n: 数据规模 21 | k: “桶”的个数 22 | In-place: 占用常数内存,不占用额外内存 23 | Out-place: 占用额外内存 24 | 0.5 算法分类 25 | 26 | 27 | 0.6 比较和非比较的区别 28 | 常见的快速排序、归并排序、堆排序、冒泡排序等属于比较排序。在排序的最终结果里,元素之间的次序依赖于它们之间的比较。每个数都必须和其他数进行比较,才能确定自己的位置。 29 | 在冒泡排序之类的排序中,问题规模为n,又因为需要比较n次,所以平均时间复杂度为O(n²)。在归并排序、快速排序之类的排序中,问题规模通过分治法消减为logN次,所以时间复杂度平均O(nlogn)。 30 | 比较排序的优势是,适用于各种规模的数据,也不在乎数据的分布,都能进行排序。可以说,比较排序适用于一切需要排序的情况。 31 | 32 | 计数排序、基数排序、桶排序则属于非比较排序。非比较排序是通过确定每个元素之前,应该有多少个元素来排序。针对数组arr,计算arr[i]之前有多少个元素,则唯一确定了arr[i]在排序后数组中的位置。 33 | 非比较排序只要确定每个元素之前的已有的元素个数即可,所有一次遍历即可解决。算法时间复杂度O(n)。 34 | 非比较排序时间复杂度底,但由于非比较排序需要占用空间来确定唯一位置。所以对数据规模和数据分布有一定的要求。 35 | 36 | 37 | 38 | 1、冒泡排序(Bubble Sort) 39 | 冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。 40 | 41 | 1.1 算法描述 42 | 比较相邻的元素。如果第一个比第二个大,就交换它们两个; 43 | 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数; 44 | 针对所有的元素重复以上的步骤,除了最后一个; 45 | 重复步骤1~3,直到排序完成。 46 | 1.2 动图演示 47 | 48 | 49 | 50 | 1.3 代码实现 51 | 复制代码 52 | 1   /** 53 | 2 * 冒泡排序 54 | 3 * 55 | 4 * @param array 56 | 5 * @return 57 | 6 */ 58 | 7 public static int[] bubbleSort(int[] array) { 59 | 8 if (array.length == 0) 60 | 9 return array; 61 | 10 for (int i = 0; i < array.length; i++) 62 | 11 for (int j = 0; j < array.length - 1 - i; j++) 63 | 12 if (array[j + 1] < array[j]) { 64 | 13 int temp = array[j + 1]; 65 | 14 array[j + 1] = array[j]; 66 | 15 array[j] = temp; 67 | 16 } 68 | 17 return array; 69 | 18 } 70 | 复制代码 71 | 72 | 73 | 1.4 算法分析 74 | 最佳情况:T(n) = O(n) 最差情况:T(n) = O(n2) 平均情况:T(n) = O(n2) 75 | 76 | 2、选择排序(Selection Sort) 77 | 表现最稳定的排序算法之一,因为无论什么数据进去都是O(n2)的时间复杂度,所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。理论上讲,选择排序可能也是平时排序一般人想到的最多的排序方法了吧。 78 | 79 | 选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。 80 | 81 | 2.1 算法描述 82 | n个记录的直接选择排序可经过n-1趟直接选择排序得到有序结果。具体算法描述如下: 83 | 84 | 初始状态:无序区为R[1..n],有序区为空; 85 | 第i趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为R[1..i-1]和R(i..n)。该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1..i]和R[i+1..n)分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区; 86 | n-1趟结束,数组有序化了。 87 | 2.2 动图演示 88 |    89 | 90 | 2.3 代码实现 91 | 复制代码 92 |   /** 93 | * 选择排序 94 | * @param array 95 | * @return 96 | */ 97 | public static int[] selectionSort(int[] array) { 98 | if (array.length == 0) 99 | return array; 100 | for (int i = 0; i < array.length; i++) { 101 | int minIndex = i; 102 | for (int j = i; j < array.length; j++) { 103 | if (array[j] < array[minIndex]) //找到最小的数 104 | minIndex = j; //将最小数的索引保存 105 | } 106 | int temp = array[minIndex]; 107 | array[minIndex] = array[i]; 108 | array[i] = temp; 109 | } 110 | return array; 111 | } 112 | 复制代码 113 | 114 | 115 | 2.4 算法分析 116 | 最佳情况:T(n) = O(n2) 最差情况:T(n) = O(n2) 平均情况:T(n) = O(n2) 117 | 118 | 3、插入排序(Insertion Sort) 119 | 插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。 120 | 121 | 3.1 算法描述 122 | 一般来说,插入排序都采用in-place在数组上实现。具体算法描述如下: 123 | 124 | 从第一个元素开始,该元素可以认为已经被排序; 125 | 取出下一个元素,在已经排序的元素序列中从后向前扫描; 126 | 如果该元素(已排序)大于新元素,将该元素移到下一位置; 127 | 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置; 128 | 将新元素插入到该位置后; 129 | 重复步骤2~5。 130 | 3.2 动图演示 131 | 132 | 133 | 3.2 代码实现 134 | 复制代码 135 |   /** 136 | * 插入排序 137 | * @param array 138 | * @return 139 | */ 140 | public static int[] insertionSort(int[] array) { 141 | if (array.length == 0) 142 | return array; 143 | int current; 144 | for (int i = 0; i < array.length - 1; i++) { 145 | current = array[i + 1]; 146 | int preIndex = i; 147 | while (preIndex >= 0 && current < array[preIndex]) { 148 | array[preIndex + 1] = array[preIndex]; 149 | preIndex--; 150 | } 151 | array[preIndex + 1] = current; 152 | } 153 | return array; 154 | } 155 | 复制代码 156 | 157 | 158 | 3.4 算法分析 159 | 最佳情况:T(n) = O(n) 最坏情况:T(n) = O(n2) 平均情况:T(n) = O(n2) 160 | 161 | 4、希尔排序(Shell Sort) 162 | 希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法。希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序,同时该算法是冲破O(n2)的第一批算法之一。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。 163 | 164 | 希尔排序是把记录按下表的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。 165 | 166 | 4.1 算法描述 167 | 我们来看下希尔排序的基本步骤,在此我们选择增量gap=length/2,缩小增量继续以gap = gap/2的方式,这种增量选择我们可以用一个序列来表示,{n/2,(n/2)/2...1},称为增量序列。希尔排序的增量序列的选择与证明是个数学难题,我们选择的这个增量序列是比较常用的,也是希尔建议的增量,称为希尔增量,但其实这个增量序列不是最优的。此处我们做示例使用希尔增量。 168 | 169 | 先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述: 170 | 171 | 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1; 172 | 按增量序列个数k,对序列进行k 趟排序; 173 | 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。 174 | 4.2 过程演示 175 | 176 | 177 | 178 | 179 | 4.3 代码实现 180 | 复制代码 181 |   /** 182 | * 希尔排序 183 | * 184 | * @param array 185 | * @return 186 | */ 187 | public static int[] ShellSort(int[] array) { 188 | int len = array.length; 189 | int temp, gap = len / 2; 190 | while (gap > 0) { 191 | for (int i = gap; i < len; i++) { 192 | temp = array[i]; 193 | int preIndex = i - gap; 194 | while (preIndex >= 0 && array[preIndex] > temp) { 195 | array[preIndex + gap] = array[preIndex]; 196 | preIndex -= gap; 197 | } 198 | array[preIndex + gap] = temp; 199 | } 200 | gap /= 2; 201 | } 202 | return array; 203 | } 204 | 复制代码 205 | 206 | 207 | 4.4 算法分析 208 | 最佳情况:T(n) = O(nlog2 n) 最坏情况:T(n) = O(nlog2 n) 平均情况:T(n) =O(nlog2n)  209 | 210 | 5、归并排序(Merge Sort) 211 | 和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是O(n log n)的时间复杂度。代价是需要额外的内存空间。 212 | 213 | 归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。归并排序是一种稳定的排序方法。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。 214 | 215 | 5.1 算法描述 216 | 把长度为n的输入序列分成两个长度为n/2的子序列; 217 | 对这两个子序列分别采用归并排序; 218 | 将两个排序好的子序列合并成一个最终的排序序列。 219 | 5.2 动图演示 220 | 221 | 222 | 5.3 代码实现 223 | 复制代码 224 |   /** 225 | * 归并排序 226 | * 227 | * @param array 228 | * @return 229 | */ 230 | public static int[] MergeSort(int[] array) { 231 | if (array.length < 2) return array; 232 | int mid = array.length / 2; 233 | int[] left = Arrays.copyOfRange(array, 0, mid); 234 | int[] right = Arrays.copyOfRange(array, mid, array.length); 235 | return merge(MergeSort(left), MergeSort(right)); 236 | } 237 | /** 238 | * 归并排序——将两段排序好的数组结合成一个排序数组 239 | * 240 | * @param left 241 | * @param right 242 | * @return 243 | */ 244 | public static int[] merge(int[] left, int[] right) { 245 | int[] result = new int[left.length + right.length]; 246 | for (int index = 0, i = 0, j = 0; index < result.length; index++) { 247 | if (i >= left.length) 248 | result[index] = right[j++]; 249 | else if (j >= right.length) 250 | result[index] = left[i++]; 251 | else if (left[i] > right[j]) 252 | result[index] = right[j++]; 253 | else 254 | result[index] = left[i++]; 255 | } 256 | return result; 257 | } 258 | 复制代码 259 | 260 | 261 | 5. 4 算法分析 262 | 最佳情况:T(n) = O(n) 最差情况:T(n) = O(nlogn) 平均情况:T(n) = O(nlogn) 263 | 264 | 6、快速排序(Quick Sort) 265 | 快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。 266 | 267 | 6.1 算法描述 268 | 快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下: 269 | 270 | 从数列中挑出一个元素,称为 “基准”(pivot); 271 | 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作; 272 | 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。 273 | 5.2 动图演示 274 | 275 | 276 | 5.3 代码实现 277 | 复制代码 278 |   /** 279 | * 快速排序方法 280 | * @param array 281 | * @param start 282 | * @param end 283 | * @return 284 | */ 285 | public static int[] QuickSort(int[] array, int start, int end) { 286 | if (array.length < 1 || start < 0 || end >= array.length || start > end) return null; 287 | int smallIndex = partition(array, start, end); 288 | if (smallIndex > start) 289 | QuickSort(array, start, smallIndex - 1); 290 | if (smallIndex < end) 291 | QuickSort(array, smallIndex + 1, end); 292 | return array; 293 | } 294 | /** 295 | * 快速排序算法——partition 296 | * @param array 297 | * @param start 298 | * @param end 299 | * @return 300 | */ 301 | public static int partition(int[] array, int start, int end) { 302 | int pivot = (int) (start + Math.random() * (end - start + 1)); 303 | int smallIndex = start - 1; 304 | swap(array, pivot, end); 305 | for (int i = start; i <= end; i++) 306 | if (array[i] <= array[end]) { 307 | smallIndex++; 308 | if (i > smallIndex) 309 | swap(array, i, smallIndex); 310 | } 311 | return smallIndex; 312 | } 313 | 314 | /** 315 | * 交换数组内两个元素 316 | * @param array 317 | * @param i 318 | * @param j 319 | */ 320 | public static void swap(int[] array, int i, int j) { 321 | int temp = array[i]; 322 | array[i] = array[j]; 323 | array[j] = temp; 324 | } 325 | 复制代码 326 | 327 | 328 | 5.4 算法分析 329 | 最佳情况:T(n) = O(nlogn) 最差情况:T(n) = O(n2) 平均情况:T(n) = O(nlogn)  330 | 331 | 7、堆排序(Heap Sort) 332 | 堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。 333 | 334 | 7.1 算法描述 335 | 将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区; 336 | 将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n]; 337 | 由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。 338 | 7.2 动图演示 339 | 340 | 341 | 7.3 代码实现 342 | 注意:这里用到了完全二叉树的部分性质:详情见《数据结构二叉树知识点总结》 343 | 344 | 复制代码 345 | //声明全局变量,用于记录数组array的长度; 346 | static int len; 347 | /** 348 | * 堆排序算法 349 | * 350 | * @param array 351 | * @return 352 | */ 353 | public static int[] HeapSort(int[] array) { 354 | len = array.length; 355 | if (len < 1) return array; 356 | //1.构建一个最大堆 357 | buildMaxHeap(array); 358 | //2.循环将堆首位(最大值)与末位交换,然后在重新调整最大堆 359 | while (len > 0) { 360 | swap(array, 0, len - 1); 361 | len--; 362 | adjustHeap(array, 0); 363 | } 364 | return array; 365 | } 366 | /** 367 | * 建立最大堆 368 | * 369 | * @param array 370 | */ 371 | public static void buildMaxHeap(int[] array) { 372 | //从最后一个非叶子节点开始向上构造最大堆 373 | for (int i = (len/2 - 1); i >= 0; i--) { //感谢 @让我发会呆 网友的提醒,此处应该为 i = (len/2 - 1) 374 | adjustHeap(array, i); 375 | } 376 | } 377 | /** 378 | * 调整使之成为最大堆 379 | * 380 | * @param array 381 | * @param i 382 | */ 383 | public static void adjustHeap(int[] array, int i) { 384 | int maxIndex = i; 385 | //如果有左子树,且左子树大于父节点,则将最大指针指向左子树 386 | if (i * 2 < len && array[i * 2] > array[maxIndex]) 387 | maxIndex = i * 2; 388 | //如果有右子树,且右子树大于父节点,则将最大指针指向右子树 389 | if (i * 2 + 1 < len && array[i * 2 + 1] > array[maxIndex]) 390 | maxIndex = i * 2 + 1; 391 | //如果父节点不是最大值,则将父节点与最大值交换,并且递归调整与父节点交换的位置。 392 | if (maxIndex != i) { 393 | swap(array, maxIndex, i); 394 | adjustHeap(array, maxIndex); 395 | } 396 | } 397 | 复制代码 398 | 399 | 7.4 算法分析 400 | 最佳情况:T(n) = O(nlogn) 最差情况:T(n) = O(nlogn) 平均情况:T(n) = O(nlogn) 401 | 402 | 8、计数排序(Counting Sort) 403 | 计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。 404 | 405 | 计数排序(Counting sort)是一种稳定的排序算法。计数排序使用一个额外的数组C,其中第i个元素是待排序数组A中值等于i的元素的个数。然后根据数组C来将A中的元素排到正确的位置。它只能对整数进行排序。 406 | 407 | 8.1 算法描述 408 | 找出待排序的数组中最大和最小的元素; 409 | 统计数组中每个值为i的元素出现的次数,存入数组C的第i项; 410 | 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加); 411 | 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1。 412 | 8.2 动图演示 413 | 414 | 415 | 8.3 代码实现 416 | 复制代码 417 | /** 418 | * 计数排序 419 | * 420 | * @param array 421 | * @return 422 | */ 423 | public static int[] CountingSort(int[] array) { 424 | if (array.length == 0) return array; 425 | int bias, min = array[0], max = array[0]; 426 | for (int i = 1; i < array.length; i++) { 427 | if (array[i] > max) 428 | max = array[i]; 429 | if (array[i] < min) 430 | min = array[i]; 431 | } 432 | bias = 0 - min; 433 | int[] bucket = new int[max - min + 1]; 434 | Arrays.fill(bucket, 0); 435 | for (int i = 0; i < array.length; i++) { 436 | bucket[array[i] + bias]++; 437 | } 438 | int index = 0, i = 0; 439 | while (index < array.length) { 440 | if (bucket[i] != 0) { 441 | array[index] = i - bias; 442 | bucket[i]--; 443 | index++; 444 | } else 445 | i++; 446 | } 447 | return array; 448 | } 449 | 复制代码 450 | 8.4 算法分析 451 | 当输入的元素是n 个0到k之间的整数时,它的运行时间是 O(n + k)。计数排序不是比较排序,排序的速度快于任何比较排序算法。由于用来计数的数组C的长度取决于待排序数组中数据的范围(等于待排序数组的最大值与最小值的差加上1),这使得计数排序对于数据范围很大的数组,需要大量时间和内存。 452 | 453 | 最佳情况:T(n) = O(n+k) 最差情况:T(n) = O(n+k) 平均情况:T(n) = O(n+k) 454 | 455 | 9、桶排序(Bucket Sort) 456 | 桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。 457 | 458 | 桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排 459 | 460 | 9.1 算法描述 461 | 人为设置一个BucketSize,作为每个桶所能放置多少个不同数值(例如当BucketSize==5时,该桶可以存放{1,2,3,4,5}这几种数字,但是容量不限,即可以存放100个3); 462 | 遍历输入数据,并且把数据一个一个放到对应的桶里去; 463 | 对每个不是空的桶进行排序,可以使用其它排序方法,也可以递归使用桶排序; 464 | 从不是空的桶里把排好序的数据拼接起来。 465 | 注意,如果递归使用桶排序为各个桶排序,则当桶数量为1时要手动减小BucketSize增加下一循环桶的数量,否则会陷入死循环,导致内存溢出。 466 | 467 | 9.2 图片演示 468 | 469 | 470 | 9.3 代码实现 471 | 复制代码 472 | /** 473 | * 桶排序 474 | * 475 | * @param array 476 | * @param bucketSize 477 | * @return 478 | */ 479 | public static ArrayList BucketSort(ArrayList array, int bucketSize) { 480 | if (array == null || array.size() < 2) 481 | return array; 482 | int max = array.get(0), min = array.get(0); 483 | // 找到最大值最小值 484 | for (int i = 0; i < array.size(); i++) { 485 | if (array.get(i) > max) 486 | max = array.get(i); 487 | if (array.get(i) < min) 488 | min = array.get(i); 489 | } 490 | int bucketCount = (max - min) / bucketSize + 1; 491 | ArrayList> bucketArr = new ArrayList<>(bucketCount); 492 | ArrayList resultArr = new ArrayList<>(); 493 | for (int i = 0; i < bucketCount; i++) { 494 | bucketArr.add(new ArrayList()); 495 | } 496 | for (int i = 0; i < array.size(); i++) { 497 | bucketArr.get((array.get(i) - min) / bucketSize).add(array.get(i)); 498 | } 499 | for (int i = 0; i < bucketCount; i++) { 500 | if (bucketSize == 1) { // 如果带排序数组中有重复数字时 感谢 @见风任然是风 朋友指出错误 501 | for (int j = 0; j < bucketArr.get(i).size(); j++) 502 | resultArr.add(bucketArr.get(i).get(j)); 503 | } else { 504 | if (bucketCount == 1) 505 | bucketSize--; 506 | ArrayList temp = BucketSort(bucketArr.get(i), bucketSize); 507 | for (int j = 0; j < temp.size(); j++) 508 | resultArr.add(temp.get(j)); 509 | } 510 | } 511 | return resultArr; 512 | } 513 | 复制代码 514 | 9.4 算法分析 515 | 桶排序最好情况下使用线性时间O(n),桶排序的时间复杂度,取决与对各个桶之间数据进行排序的时间复杂度,因为其它部分的时间复杂度都为O(n)。很显然,桶划分的越小,各个桶之间的数据越少,排序所用的时间也会越少。但相应的空间消耗就会增大。 516 | 517 | 最佳情况:T(n) = O(n+k) 最差情况:T(n) = O(n+k) 平均情况:T(n) = O(n2)   518 | 519 | 10、基数排序(Radix Sort) 520 | 基数排序也是非比较的排序算法,对每一位进行排序,从最低位开始排序,复杂度为O(kn),为数组长度,k为数组中的数的最大的位数; 521 | 522 | 基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。基数排序基于分别排序,分别收集,所以是稳定的。 523 | 524 | 10.1 算法描述 525 | 取得数组中的最大数,并取得位数; 526 | arr为原始数组,从最低位开始取每个位组成radix数组; 527 | 对radix进行计数排序(利用计数排序适用于小范围数的特点); 528 | 10.2 动图演示 529 | 530 | 531 | 10.3 代码实现 532 | 复制代码 533 |   /** 534 | * 基数排序 535 | * @param array 536 | * @return 537 | */ 538 | public static int[] RadixSort(int[] array) { 539 | if (array == null || array.length < 2) 540 | return array; 541 | // 1.先算出最大数的位数; 542 | int max = array[0]; 543 | for (int i = 1; i < array.length; i++) { 544 | max = Math.max(max, array[i]); 545 | } 546 | int maxDigit = 0; 547 | while (max != 0) { 548 | max /= 10; 549 | maxDigit++; 550 | } 551 | int mod = 10, div = 1; 552 | ArrayList> bucketList = new ArrayList>(); 553 | for (int i = 0; i < 10; i++) 554 | bucketList.add(new ArrayList()); 555 | for (int i = 0; i < maxDigit; i++, mod *= 10, div *= 10) { 556 | for (int j = 0; j < array.length; j++) { 557 | int num = (array[j] % mod) / div; 558 | bucketList.get(num).add(array[j]); 559 | } 560 | int index = 0; 561 | for (int j = 0; j < bucketList.size(); j++) { 562 | for (int k = 0; k < bucketList.get(j).size(); k++) 563 | array[index++] = bucketList.get(j).get(k); 564 | bucketList.get(j).clear(); 565 | } 566 | } 567 | return array; 568 | } 569 | 复制代码 570 | 571 | 572 | 10.4 算法分析 573 | 最佳情况:T(n) = O(n * k) 最差情况:T(n) = O(n * k) 平均情况:T(n) = O(n * k) 574 | 575 | 基数排序有两种方法: 576 | 577 | MSD 从高位开始进行排序 LSD 从低位开始进行排序 578 | 579 | 580 | 581 | 基数排序 vs 计数排序 vs 桶排序 582 | 583 | 这三种排序算法都利用了桶的概念,但对桶的使用方法上有明显差异: 584 | 585 | 基数排序:根据键值的每位数字来分配桶 586 | 计数排序:每个桶只存储单一键值 587 | 桶排序:每个桶存储一定范围的数值 588 | 589 | 出处 590 | https://www.cnblogs.com/guoyaohua/p/8600214.html -------------------------------------------------------------------------------- /db/mysql/mysql基于binlog日志还原数据.md: -------------------------------------------------------------------------------- 1 | ##1.开启日志 2 | 修改配置文件 vi /etc/my.cnf 3 | 增加 4 | ```$xslt 5 | server-id=1 6 | log-bin=binlog 7 | ``` 8 | 重启数据库服务 9 | systemctl restart mysqld 10 | 11 | ##2.操作数据库 12 | mysql> create database mydb charset utf8mb4; 13 | mysql> use mydb; 14 | mysql> create table test(id int)engine=innodb charset=utf8mb4; 15 | mysql> insert into test values(1); 16 | mysql> insert into test values(2); 17 | mysql> insert into test values(3); 18 | mysql> insert into test values(4); 19 | mysql> commit; 20 | mysql> update test set id=10 where id=4; 21 | mysql> commit; 22 | 23 | 24 | ##3.查看二进制日志信息 25 | ```$xslt 26 | show master status\G; 27 | ``` 28 | 29 | 30 | ##4.查找创库和删库的点,为219和1868 31 | ```$xslt 32 | mysql> show binlog events in 'binlog.000001'; 33 | 34 | ``` 35 | 36 | ##5.另存为二进制日志信息 37 | ```$xslt 38 | mysqlbinlog --start-position=219 --stop-position=1868 /var/lib/mysql/binlog.000001 > /tmp/binlog.sql 39 | ``` 40 | 41 | ##恢复数据 42 | #临时关闭二进制日志记录以免重复记录 43 | mysql> set sql_log_bin=0; 44 | #恢复数据 45 | mysql> source /tmp/binlog.sql 46 | #重启二进制日志记录 47 | mysql> set sql_log_bin=1; 48 | 49 | ##6.查看数据恢复情况 50 | show databases; -------------------------------------------------------------------------------- /docker/Docker 给运行中的容器设置端口映射的方法.md: -------------------------------------------------------------------------------- 1 | 方法1 2 | 1、获得容器IP 3 | 4 | 将container_name 换成实际环境中的容器名 5 | docker inspect container_name | grep IPAddress 6 | docker inspect mysql | grep IPAddress 7 | 2、 iptable转发端口 8 | 9 | 将容器的8000端口映射到docker主机的8001端口 10 | 复制代码 代码如下: 11 | 12 | iptables -t nat -A DOCKER -p tcp --dport 8001 -j DNAT --to-destination 172.17.0.19:8000 13 | iptables -t nat -A DOCKER -p tcp --dport 3308 -j DNAT --to-destination 172.17.0.8:3306 14 | 15 | 16 | 方法2 17 | 1.提交一个运行中的容器为镜像 18 | 19 | docker commit containerid foo/live 20 | docker commit mysql 0619/mysql 21 | 2.运行镜像并添加端口 22 | 23 | docker run -d -p 8000:80 foo/live /bin/bash 24 | docker run -d -p 3339:3306 0619/mysql /bin/bash 25 | docker run -d -p 3339:3306 0619/mysql --name mysql-test 26 | docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=db123456! --name mysql8 -v /mnt/mysql8:/var/lib/mysql57 mysql:8 --character-set-server=utf8 --collation-server=utf8_unicode_ci --character-set-client-handshake=FALSE -e TZ=Asia/Shanghai 27 | -------------------------------------------------------------------------------- /docker/Jenkins.md: -------------------------------------------------------------------------------- 1 | #jenkins docker 启动 2 | docker run -d --name jenkins -p 8880:8080 -v /root/java/jenkins_docker:/jenkins_docker jenkins/jenkins:lts 3 | #时区 加 -v /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime 4 | 先 cat /usr/share/zoneinfo/Asia/Shanghai 查看 5 | docker pull jenkins/jenkins:lts 6 | docker run -d --name jenkins -p 8880:8080 -v /root/java/jenkins_docker:/jenkins_docker -v /usr/share/zoneinfo/Asia/Shanghai:/etc/timezone -v /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime jenkins/jenkins:lts 7 | docker run -d --name jenkins3 -p 8881:8080 -v /root/java/jenkins_docker3:/jenkins_docker -v /usr/share/zoneinfo/Asia/Shanghai:/etc/timezone -v /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime jenkins/jenkins:lts 8 | #守护进程 9 | docker update --restart=on-failure:3 jenkins 10 | 11 | 12 | docker run -it -p 80:8080 -v /外部Docker目录:/var/jenkins_home -v /外部DocketWar文件目录/jenkins.war:/usr/share/jenkins/jenkins.war jenkins 13 | 14 | jenkins插件清华大学镜像地址 15 | https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json 16 | http://mirror.xmission.com/ 17 | 18 | https://updates.jenkins-zh.cn/update-center.json 19 | https://www.oschina.net/news/111266/jenkins-plugin-mirror 20 | https://mirrors.tuna.tsinghua.edu.cn/jenkins/plugins/ 21 | #码云镜像 22 | https://jenkins-zh.gitee.io/update-center-mirror/tsinghua/update-center.json 23 | 24 | #默认 25 | https://updates.jenkins.io/update-center.json 26 | 27 | #jenkins密码 28 | docker exec -it jenkins bash 29 | cat /var/jenkins_home/secrets/initialAdminPassword 30 | f41b167b420a478a9c2cf1a9e7111627 31 | 32 | 33 | 需要的插件 34 | Folders Plugin 35 | Folders Plugin OWASP Markup 36 | Formatter 37 | Build Timeout 38 | Credentials Binding 39 | Timestamper 40 | Workspace Cleanup 41 | Ant 42 | Gradle 43 | Pipeline GitHub Branch Source 44 | Pipeline: GitHub Groovy Libraries 45 | Pipeline: Stage View 46 | Git 47 | Subversion 48 | SSH Build Agents 49 | Matrix Authorization Strategy 50 | PAM Authentication 51 | LDAP 52 | Email Extension 53 | Mailer 54 | Localization: Chinese (Simplified) -------------------------------------------------------------------------------- /docker/docker 更新配置.md: -------------------------------------------------------------------------------- 1 | 2 | docker容器设置自动启动 3 | 启动时加 --restart=always 4 | docker run -tid --name isaler_v0.0.11 -p 8081:8080 --restart=always -v /alidata/iDocker/run/projectImages/isaler/v0.0.11/log:/usr/local/tomcat/logs isaler_v0.0.11 5 | 6 | 7 | Flag Description 8 | no 不自动重启容器. (默认value) 9 | on-failure 容器发生error而退出(容器退出状态不为0)重启容器 10 | unless-stopped 在容器已经stop掉或Docker stoped/restarted的时候才重启容器 11 | always 在容器已经stop掉或Docker stoped/restarted的时候才重启容器 12 | 如果已经过运行的项目 13 | 如果已经启动的项目,则使用update更新: 14 | docker update --restart=always isaler_v0.0.11 15 | 16 | --restart=on-failure:3 重试三次 -------------------------------------------------------------------------------- /docker/docker-compose/mysql/ReadMe.md: -------------------------------------------------------------------------------- 1 | 文章目录 2 | docker实践之docker-compose部署mysql 3 | 1、安装部署docker 4 | 2、编写docker-compose文件 5 | 3、编写配置文件和初始化文件 6 | 4、启动数据库 7 | 5、检查初始化的数据 8 | 6、验证远程连接 9 | docker实践之docker-compose部署mysql 10 | 前面用golang写了一个api server,但是要用到一些测试数据,又要方便给别人,想来用docker部署环境最简单了。只需要简单执行两个命令就可以搞定了。博主的环境是windows然后在windows里面部署一个centos7的虚拟机。在虚拟机里面安装部署了docker。 11 | 12 | 1、安装部署docker 13 | 在linux下面只需简单的一个命令: 14 | 15 | yum install docker 16 | 1 17 | 其他的系统类似。 18 | 19 | 2、编写docker-compose文件 20 | version: '2' 21 | services: 22 | mysql: 23 | network_mode: "host" 24 | environment: 25 | MYSQL_ROOT_PASSWORD: "yourpassword" 26 | MYSQL_USER: 'test' 27 | MYSQL_PASS: 'yourpassword' 28 | image: "docker.io/mysql:latest" 29 | restart: always 30 | volumes: 31 | - "./db:/var/lib/mysql" 32 | - "./conf/my.cnf:/etc/my.cnf" 33 | - "./init:/docker-entrypoint-initdb.d/" 34 | 35 | 这里稍微解释一下,其中,network_mode为容器的网络模式,一般自己测试用host模式就可以了。MYSQL_ROOT_PASSWORD为数据库的密码,也就是root用户的密码。MYSQL_USER和MYSQL_PASS另外一个用户名和密码。image为你拉取镜像的地址和版本,当然也可以换成自己的镜像仓库,这里使用官方的。volumes里面的参数为映射本地和docker容器里面的文件夹和目录。./db 用来存放了数据库表文件,./conf/my.cnf存放自定义的配置文件,./init存放初始化的脚本。ports 为映射主机和容器的端口。写好docker-compose.yml后把相应的文件夹建好,当然也可以换成你自己的。下面的是博主的文件夹结构。 36 | 37 | root@localhost mysql # tree 38 | . 39 | ├── conf 40 | │ └── my.cnf 41 | ├── db 42 | ├── docker-compose.yml 43 | └── init 44 | └── init.sql 45 | 46 | 3、编写配置文件和初始化文件 47 | root@localhost conf # cat my.cnf 48 | [mysqld] 49 | user=mysql 50 | default-storage-engine=INNODB 51 | character-set-server=utf8 52 | [client] 53 | default-character-set=utf8 54 | [mysql] 55 | default-character-set=utf8 56 | 57 | 这里的配置文件只是一个简单的举例,大家需要根据自己的配置来更改。 58 | 59 | root@localhost init # cat init.sql 60 | use mysql; 61 | ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'yourpassword'; 62 | create database test; 63 | use test; 64 | create table user 65 | ( 66 | id int auto_increment primary key, 67 | username varchar(64) unique not null, 68 | email varchar(120) unique not null, 69 | password_hash varchar(128) not null, 70 | avatar varchar(128) not null 71 | ); 72 | insert into user values(1, "zhangsan","test12345@qq.com","passwd","avaterpath"); 73 | insert into user values(2, "lisi","12345test@qq.com","passwd","avaterpath"); 74 | 75 | ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'yourpassword';这一句比较重要,放开root登入权限,如果你要在其他的主机用root用户登入到数据库就需要写入这句话。其他的语句就是建表操作和插入数据的操作了。 76 | 77 | 4、启动数据库 78 | root@localhost mysql # docker-compose pull 79 | 80 | .......下载镜像过程 81 | 82 | root@localhost mysql # docker-compose up -d 83 | 84 | mysql_mysql_1_234be9b015e4 is up-to-date 85 | root@localhost mysql # 86 | 1 87 | 2 88 | 3 89 | 4 90 | 5 91 | 6 92 | 7 93 | 8 94 | 此处需要在存放docker-compose.yml的文件夹进行操作。 95 | 96 | 5、检查初始化的数据 97 | root@localhost mysql # docker ps 98 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 99 | cffe8d56f222 docker.io/mysql:latest "docker-entrypoint..." 21 minutes ago Up 21 minutes mysql_mysql_1_234be9b015e4 100 | root@localhost mysql # docker exec -it cffe8d56f222 bash 101 | root@localhost:/# mysql -uroot -p 102 | Enter password: 103 | Welcome to the MySQL monitor. Commands end with ; or \g. 104 | Your MySQL connection id is 11 105 | Server version: 8.0.13 MySQL Community Server - GPL 106 | 107 | Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. 108 | 109 | Oracle is a registered trademark of Oracle Corporation and/or its 110 | affiliates. Other names may be trademarks of their respective 111 | owners. 112 | 113 | Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. 114 | 115 | mysql> use test; 116 | Reading table information for completion of table and column names 117 | You can turn off this feature to get a quicker startup with -A 118 | 119 | Database changed 120 | mysql> select * from user; 121 | +----+----------+------------------+---------------+------------+ 122 | | id | username | email | password_hash | avatar | 123 | +----+----------+------------------+---------------+------------+ 124 | | 1 | zhangsan | test12345@qq.com | passwd | avaterpath | 125 | | 2 | lisi | 12345test@qq.com | passwd | avaterpath | 126 | +----+----------+------------------+---------------+------------+ 127 | 2 rows in set (0.00 sec) 128 | 129 | 可以看到数据存入到数据库当中去。 130 | -------------------------------------------------------------------------------- /docker/docker-compose/mysql/conf/my.cnf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stylesmile/javaRoad/500e28dd78804c915df06cef32a3e95d3b989465/docker/docker-compose/mysql/conf/my.cnf -------------------------------------------------------------------------------- /docker/docker-compose/mysql/conf/my2.cnf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stylesmile/javaRoad/500e28dd78804c915df06cef32a3e95d3b989465/docker/docker-compose/mysql/conf/my2.cnf -------------------------------------------------------------------------------- /docker/docker-compose/mysql/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | mysql: 4 | network_mode: "host" 5 | environment: 6 | MYSQL_ROOT_PASSWORD: "yourpassword" 7 | MYSQL_USER: 'test' 8 | MYSQL_PASS: 'yourpassword' 9 | image: "docker.io/mysql:latest" 10 | restart: always 11 | volumes: 12 | - "./db:/var/lib/mysql" 13 | - "./conf/my.cnf:/etc/my.cnf" 14 | - "./init:/docker-entrypoint-initdb.d/" 15 | -------------------------------------------------------------------------------- /docker/docker-compose/mysql主从/ReadMe.md: -------------------------------------------------------------------------------- 1 | 2 | ##主库 3 | ###主服务器log-bin日志 4 | 执行 show master status; 5 | 记下File, Position 6 | ##查看binlog是否开启 7 | show variables like "%log_bin%"; 8 | ##日志位置 9 | show variables like 'general_log_file'; 10 | 11 | 12 | 13 | ## 配置mysql主从复制 14 | 在从机上需要进行CHANGE MASTER TO操作,以确定需要同步的主机IP,用户名,密码,binlog文件,binlog位置等信息。 15 | CHANGE MASTER TO 16 | MASTER_HOST='192.168.0.38', 17 | MASTER_PORT=3316, 18 | MASTER_USER='root', 19 | MASTER_PASSWORD='123456', 20 | MASTER_LOG_FILE='binlog.000002', 21 | MASTER_LOG_POS=1660; 22 | 23 | 24 | start slave; 25 | stop slave; 26 | ##查看状态 27 | show slave status; 28 | 当 Slave_IO_Running: Yes Slave_SQL_Running: Yes时 配置成功! 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 3.根据配置文件生成容器并运行 37 | 在Linux Shell中执行 38 | 39 | docker-compose up -d 40 | 1 41 | 会如下输出类似的信息 42 | 43 | Creating network "wen_jznet" with driver "bridge" 44 | Creating wen_mysql-slave_1 45 | Creating wen_mysql-master_1 46 | 1 47 | 2 48 | 3 49 | 4.在主库中创建同步用户 50 | 此时使用数据库客户端工具连接上Master主数据库, 51 | 52 | 或直接使用 53 | 54 | docker exec -it “容器ID” /bin/bash 55 | 1 56 | 进入容器,使用 57 | 58 | mysql -u root -p 59 | 1 60 | 输入在docker-compose.yml中配置的MYSQL_ROOT_PASSWORD为密码进入到MySQL Shell,输入以下命令创建允许主从复制的用户 repl ,密码为 Ron_master_1 61 | 62 | CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY 'Ron_master_1'; 63 | GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%'; 64 | 1 65 | 2 66 | ⚠️注意,用户权限问题 67 | 此时的用户没有创建库或表的权限,以root用户登录主库并执行以下命令赋予repl用户权限 68 | 69 | GRANT ALL PRIVILEGES ON *.* TO ‘repl’@‘%’ IDENTIFIED BY 'Ron_master_1’; 70 | 1 71 | 5.在从库中配置主库信息 72 | 切换到 Slave数据库,执行以下命令,设置主库信息 73 | 74 | CHANGE MASTER TO 75 | MASTER_HOST='172.18.4.24', 76 | MASTER_USER='repl', 77 | MASTER_PASSWORD='Ron_master_1', 78 | MASTER_LOG_FILE='binlog.000002', 79 | MASTER_LOG_POS=642; 80 | 1 81 | 2 82 | 3 83 | 4 84 | 5 85 | 6 86 | 6.开始同步 87 | 然后在Slave数据库中再执行以下命令,开始同步 88 | 89 | start slave; 90 | 1 91 | 7.查看从库同步状态 92 | 可以执行以下命令查看从库状态 93 | 94 | show slave status\G; 95 | 1 96 | 输出结果如下表示从库运行正常 97 | 98 | mysql> show slave status\G; 99 | *************************** 1. row *************************** 100 | Slave_IO_State: Waiting for master to send event 101 | Master_Host: 172.18.4.24 102 | Master_User: repl 103 | Master_Port: 3306 104 | Connect_Retry: 60 105 | Master_Log_File: binlog.000003 106 | Read_Master_Log_Pos: 4067 107 | Relay_Log_File: f3f3d65fee1e-relay-bin.000002 108 | Relay_Log_Pos: 1730 109 | Relay_Master_Log_File: binlog.000003 110 | Slave_IO_Running: Yes 111 | Slave_SQL_Running: Yes 112 | Replicate_Do_DB: 113 | Replicate_Ignore_DB: 114 | Replicate_Do_Table: 115 | Replicate_Ignore_Table: 116 | Replicate_Wild_Do_Table: 117 | Replicate_Wild_Ignore_Table: 118 | Last_Errno: 0 119 | Last_Error: 120 | Skip_Counter: 0 121 | Exec_Master_Log_Pos: 4067 122 | Relay_Log_Space: 1946 123 | Until_Condition: None 124 | Until_Log_File: 125 | Until_Log_Pos: 0 126 | Master_SSL_Allowed: No 127 | Master_SSL_CA_File: 128 | Master_SSL_CA_Path: 129 | Master_SSL_Cert: 130 | Master_SSL_Cipher: 131 | Master_SSL_Key: 132 | Seconds_Behind_Master: 0 133 | Master_SSL_Verify_Server_Cert: No 134 | Last_IO_Errno: 0 135 | Last_IO_Error: 136 | Last_SQL_Errno: 0 137 | Last_SQL_Error: 138 | Replicate_Ignore_Server_Ids: 139 | Master_Server_Id: 1 140 | Master_UUID: 2388be4b-9b3a-11ea-8561-0242ac120418 141 | Master_Info_File: mysql.slave_master_info 142 | SQL_Delay: 0 143 | SQL_Remaining_Delay: NULL 144 | Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates 145 | Master_Retry_Count: 86400 146 | Master_Bind: 147 | Last_IO_Error_Timestamp: 148 | Last_SQL_Error_Timestamp: 149 | Master_SSL_Crl: 150 | Master_SSL_Crlpath: 151 | Retrieved_Gtid_Set: 152 | Executed_Gtid_Set: 153 | Auto_Position: 0 154 | Replicate_Rewrite_DB: 155 | Channel_Name: 156 | Master_TLS_Version: 157 | Master_public_key_path: 158 | Get_master_public_key: 0 159 | Network_Namespace: 160 | 1 row in set (0.00 sec) 161 | 162 | ERROR: 163 | No query specified 164 | 67 165 | 查看主库状态,需要在主库中执行 166 | 167 | show master status; 168 | 1 169 | 输出如下 170 | 171 | mysql> show master status; 172 | +---------------+----------+--------------+------------------+-------------------+ 173 | | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | 174 | +---------------+----------+--------------+------------------+-------------------+ 175 | | binlog.000003 | 4067 | | | | 176 | +---------------+----------+--------------+------------------+-------------------+ 177 | 178 | 其中File表示主从库同步所依赖的二进制文件,Position代表位置, 179 | 180 | Position和Read_Master_Log_Pos数值一致代表此时主从库是一致的。 181 | 182 | ⚠️注意 183 | 主库必须使用具有从库同步权限的用户登录并进行操作才可以同步至从库。 184 | 185 | 附:安装过程中出现的错误 186 | 安装完成后主库和从库不会同步,在从库中查看从库状态 187 | 188 | show slave status\G; 189 | 输出如下, 190 | 191 | mysql> show slave status\G; 192 | *************************** 1. row *************************** 193 | Slave_IO_State: 194 | Master_Host: 172.18.4.24 195 | Master_User: repl 196 | Master_Port: 3306 197 | Connect_Retry: 60 198 | Master_Log_File: binlog.000002 199 | Read_Master_Log_Pos: 642 200 | Relay_Log_File: f3f3d65fee1e-relay-bin.000010 201 | Relay_Log_Pos: 321 202 | Relay_Master_Log_File: binlog.000002 203 | Slave_IO_Running: No 204 | Slave_SQL_Running: Yes 205 | Replicate_Do_DB: 206 | Replicate_Ignore_DB: 207 | Replicate_Do_Table: 208 | Replicate_Ignore_Table: 209 | Replicate_Wild_Do_Table: 210 | Replicate_Wild_Ignore_Table: 211 | Last_Errno: 0 212 | Last_Error: 213 | Skip_Counter: 0 214 | Exec_Master_Log_Pos: 642 215 | Relay_Log_Space: 702 216 | Until_Condition: None 217 | Until_Log_File: 218 | Until_Log_Pos: 0 219 | Master_SSL_Allowed: No 220 | Master_SSL_CA_File: 221 | Master_SSL_CA_Path: 222 | Master_SSL_Cert: 223 | Master_SSL_Cipher: 224 | Master_SSL_Key: 225 | Seconds_Behind_Master: NULL 226 | Master_SSL_Verify_Server_Cert: No 227 | Last_IO_Errno: 13114 228 | Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master; the first event 'binlog.000002' at 642, the last event read from './binlog.000002' at 125, the last byte read from './binlog.000002' at 661.' 229 | Last_SQL_Errno: 0 230 | Last_SQL_Error: 231 | Replicate_Ignore_Server_Ids: 232 | Master_Server_Id: 1 233 | Master_UUID: 2388be4b-9b3a-11ea-8561-0242ac120418 234 | Master_Info_File: mysql.slave_master_info 235 | SQL_Delay: 0 236 | SQL_Remaining_Delay: NULL 237 | Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates 238 | Master_Retry_Count: 86400 239 | Master_Bind: 240 | Last_IO_Error_Timestamp: 200521 08:55:15 241 | Last_SQL_Error_Timestamp: 242 | Master_SSL_Crl: 243 | Master_SSL_Crlpath: 244 | Retrieved_Gtid_Set: 245 | Executed_Gtid_Set: 246 | Auto_Position: 0 247 | Replicate_Rewrite_DB: 248 | Channel_Name: 249 | Master_TLS_Version: 250 | Master_public_key_path: 251 | Get_master_public_key: 0 252 | Network_Namespace: 253 | 1 row in set (0.00 sec) 254 | 255 | ERROR: 256 | No query specified 257 | 258 | 259 | 经一番搜索后发现是从库的同步点和主库不一致造成的,此时在主库中查看二进制文件同步位置, 260 | 261 | show master status; 262 | 1 263 | 输出如下, 264 | 265 | mysql> show master status; 266 | +---------------+----------+--------------+------------------+-------------------+ 267 | | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | 268 | +---------------+----------+--------------+------------------+-------------------+ 269 | | binlog.000003 | 2658 | | | | 270 | +---------------+----------+--------------+------------------+-------------------+ 271 | 1 row in set (0.01 sec) 272 | 273 | 对比发现,主库的Position为2658,从库的Exec_Master_Log_Pos为642。 274 | 275 | 停止从库同步, 276 | 277 | stop slave; 278 | 279 | 在仓库中执行以下命令,手动把从库的同步点与主库对齐, 280 | 281 | change master to Master_Log_File='binlog.000003',Master_Log_Pos=2658; 282 | 283 | 开启同步 284 | 285 | start slave 286 | 287 | 此时使用具有同步权限的用户登录主库,创建数据库,从库可以同步,完成。 288 | 289 | ⚠️注意 290 | 在手动将主库和从库的同步点对齐之前,即在执行以下命令之前, 291 | 292 | change master to Master_Log_File='binlog.000003',Master_Log_Pos=2658; 293 | 1 294 | 要手动将主库中的数据库和表及表中的数据同步至从库,否则从库在同步时,会出现没有此数据库或此表的错误。 295 | 296 | 例如,查看Slave状态时,输出如下, 297 | 298 | ysql> show slave status\G; 299 | *************************** 1. row *************************** 300 | Slave_IO_State: Waiting for master to send event 301 | Master_Host: 172.18.4.24 302 | Master_User: repl 303 | Master_Port: 3306 304 | Connect_Retry: 60 305 | Master_Log_File: binlog.000003 306 | Read_Master_Log_Pos: 1491 307 | Relay_Log_File: f3f3d65fee1e-relay-bin.000012 308 | Relay_Log_Pos: 540 309 | Relay_Master_Log_File: binlog.000003 310 | Slave_IO_Running: Yes 311 | Slave_SQL_Running: No 312 | Replicate_Do_DB: 313 | Replicate_Ignore_DB: 314 | Replicate_Do_Table: 315 | Replicate_Ignore_Table: 316 | Replicate_Wild_Do_Table: 317 | Replicate_Wild_Ignore_Table: 318 | Last_Errno: 1049 319 | Last_Error: Error 'Unknown database 'test'' on query. Default database: 'test'. Query: '/* ApplicationName=DataGrip 2020.1.3 */ create table test( 320 | id bigint primary key not null unique auto_increment, 321 | name varchar(255) 322 | )' 323 | Skip_Counter: 0 324 | Exec_Master_Log_Pos: 881 325 | Relay_Log_Space: 1531 326 | Until_Condition: None 327 | Until_Log_File: 328 | Until_Log_Pos: 0 329 | Master_SSL_Allowed: No 330 | Master_SSL_CA_File: 331 | Master_SSL_CA_Path: 332 | Master_SSL_Cert: 333 | Master_SSL_Cipher: 334 | Master_SSL_Key: 335 | Seconds_Behind_Master: NULL 336 | Master_SSL_Verify_Server_Cert: No 337 | Last_IO_Errno: 0 338 | Last_IO_Error: 339 | Last_SQL_Errno: 1049 340 | Last_SQL_Error: Error 'Unknown database 'test'' on query. Default database: 'test'. Query: '/* ApplicationName=DataGrip 2020.1.3 */ create table test( 341 | id bigint primary key not null unique auto_increment, 342 | name varchar(255) 343 | )' 344 | Replicate_Ignore_Server_Ids: 345 | Master_Server_Id: 1 346 | Master_UUID: 2388be4b-9b3a-11ea-8561-0242ac120418 347 | Master_Info_File: mysql.slave_master_info 348 | SQL_Delay: 0 349 | SQL_Remaining_Delay: NULL 350 | Slave_SQL_Running_State: 351 | Master_Retry_Count: 86400 352 | Master_Bind: 353 | Last_IO_Error_Timestamp: 354 | Last_SQL_Error_Timestamp: 200521 09:23:00 355 | Master_SSL_Crl: 356 | Master_SSL_Crlpath: 357 | Retrieved_Gtid_Set: 358 | Executed_Gtid_Set: 359 | Auto_Position: 0 360 | Replicate_Rewrite_DB: 361 | Channel_Name: 362 | Master_TLS_Version: 363 | Master_public_key_path: 364 | Get_master_public_key: 0 365 | Network_Namespace: 366 | 1 row in set (0.00 sec) 367 | 368 | ERROR: 369 | No query specified 370 | 371 | ———————————————— 372 | 版权声明:本文为CSDN博主「梵莫」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 373 | 原文链接:https://blog.csdn.net/weixin_43981099/article/details/106267634 -------------------------------------------------------------------------------- /docker/docker-compose/mysql主从/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | mysql-master: 4 | image: docker.io/mysql 5 | networks: 6 | jznet: 7 | ipv4_address: 172.18.4.24 8 | volumes: 9 | - /root/data/mysql-master:/var/lib/mysql 10 | - ./master.cnf:/etc/mysql/my.cnf 11 | ports: 12 | - "3316:3306" 13 | environment: 14 | - MYSQL_DATABASE=root 15 | - MYSQL_ROOT_PASSWORD=123456 16 | mysql-slave: 17 | image: docker.io/mysql 18 | networks: 19 | jznet: 20 | ipv4_address: 172.18.4.25 21 | volumes: 22 | - /root/data/mysql-slave:/var/lib/mysql 23 | - ./slave.cnf:/etc/mysql/my.cnf 24 | ports: 25 | - "3317:3306" 26 | environment: 27 | - MYSQL_DATABASE=root 28 | - MYSQL_ROOT_PASSWORD=123456 29 | networks: 30 | jznet: 31 | driver: bridge 32 | ipam: 33 | driver: default 34 | config: 35 | - subnet: 172.18.4.0/26 36 | -------------------------------------------------------------------------------- /docker/docker-compose/mysql主从/error.md: -------------------------------------------------------------------------------- 1 | Slave failed to initialize relay log info structure from the repository 2 | 3 | ##日志位置 4 | show variables like 'general_log_file'; 5 | ##查看日志 6 | tail -30 /var/lib/mysqld.log 7 | 8 | 可以看到报错,原来是找不到./server246-relay-bin.index文件,找到原因所在了,由于我使用的是冷备份文件恢复的实例,在mysql库中的slave_relay_log_info表中依然保留之前relay_log的信息,所以导致启动slave报错。 9 | mysql提供了工具用来删除记录:slave reset; 10 | slave reset执行候做了这样几件事: 11 | 1、删除slave_master_info ,slave_relay_log_info两个表中数据; 12 | 2、删除所有relay log文件,并重新创建新的relay log文件; 13 | 3、不会改变gtid_executed 或者 gtid_purged的值 14 | ———————————————— 15 | 版权声明:本文为CSDN博主「无知的蜗牛」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 16 | 原文链接:https://blog.csdn.net/weixin_37998647/article/details/79950133 -------------------------------------------------------------------------------- /docker/docker-compose/mysql主从/init-node.sh: -------------------------------------------------------------------------------- 1 | # set node master 2 | 3 | MYSQL_PWD=${MYSQL_ROOT_PASSWORD} mysql -u root \ 4 | -e "CHANGE MASTER TO MASTER_HOST='mysql-master', \ 5 | MASTER_USER='${MYSQL_REPLICATION_USER}', \ 6 | MASTER_PASSWORD='${MYSQL_REPLICATION_PASSWORD}', \ 7 | MASTER_LOG_FILE='${LOG_FILE}', \ 8 | MASTER_LOG_POS=${LOG_POS};" 9 | 10 | # start slave and show slave status 11 | 12 | MYSQL_PWD=${MYSQL_ROOT_PASSWORD} mysql -u root -e "START SLAVE;show slave status\G" -------------------------------------------------------------------------------- /docker/docker-compose/mysql主从/master.cnf: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; version 2 of the License. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | 16 | # 17 | # The MySQL Server configuration file. 18 | # 19 | # For explanations see 20 | # http://dev.mysql.com/doc/mysql/en/server-system-variables.html 21 | 22 | [mysqld] 23 | pid-file = /var/run/mysqld/mysqld.pid 24 | socket = /var/run/mysqld/mysqld.sock 25 | datadir = /var/lib/mysql 26 | secure-file-priv= NULL 27 | server-id=1 28 | # Disabling symbolic-links is recommended to prevent assorted security risks 29 | symbolic-links=0 30 | 31 | # Custom config should go here 32 | !includedir /etc/mysql/conf.d/ 33 | -------------------------------------------------------------------------------- /docker/docker-compose/mysql主从/slave.cnf: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; version 2 of the License. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | 16 | # 17 | # The MySQL Server configuration file. 18 | # 19 | # For explanations see 20 | # http://dev.mysql.com/doc/mysql/en/server-system-variables.html 21 | 22 | [mysqld] 23 | pid-file = /var/run/mysqld/mysqld.pid 24 | socket = /var/run/mysqld/mysqld.sock 25 | datadir = /var/lib/mysql 26 | secure-file-priv= NULL 27 | server-id=2 28 | relay_log_recovery=0 29 | # Disabling symbolic-links is recommended to prevent assorted security risks 30 | symbolic-links=0 31 | 32 | # Custom config should go here 33 | !includedir /etc/mysql/conf.d/ 34 | -------------------------------------------------------------------------------- /docker/docker-elasticsearch.md: -------------------------------------------------------------------------------- 1 | docker run -d -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e "cluster.name=elasticsearch" -e "node.name=elasticsearch" docker.elastic.co/elasticsearch/elasticsearch:6.6.1 2 | -------------------------------------------------------------------------------- /docker/docker-gitlab.md: -------------------------------------------------------------------------------- 1 | docker run -d -p 444:443 -p 808:80 -p 222:22 --name gitlab --restart always -v /home/gitlab/config:/etc/gitlab -v /home/gitlab/logs:/var/log/gitlab -v /home/gitlab/data:/var/opt/gitlab gitlab/gitlab-ce 2 | docker run -d -p 444:443 -p 808:80 -p 222:22 --name gitlab --restart always gitlab/gitlab-ce 3 | docker run -d -p 445:443 -p 809:80 -p 223:22 --name gitlab2 --restart always gitlab/gitlab-ce 4 | docker run -d -p 808:80 --name gitlab --restart always gitlab/gitlab-ce 5 | docker update -m 2000M --memory-swap 2000M gitlab 6 | docker update --restart=always gitlab 7 | 8 | 密码chenye1234567890 9 | 10 | 11 | 12 | # -d:后台运行 13 | # -p:将容器内部端口向外映射 14 | # --name:命名容器名称 15 | # -v:将容器内数据文件夹或者日志、配置等文件夹挂载到宿主机指定目录 16 | 运行成功后出现一串字符串 17 | 18 | 19 | 运行成功 20 | 3.配置 21 | 按上面的方式,gitlab容器运行没问题,但在gitlab上创建项目的时候,生成项目的URL访问地址是按容器的hostname来生成的,也就是容器的id。作为gitlab服务器,我们需要一个固定的URL访问地址,于是需要配置gitlab.rb(宿主机路径:/home/gitlab/config/gitlab.rb)。 22 | 23 | # gitlab.rb文件内容默认全是注释 24 | $ vim /home/gitlab/config/gitlab.rb 25 | # 配置http协议所使用的访问地址,不加端口号默认为80 26 | external_url 'http://192.168.199.231' 27 | 28 | # 配置ssh协议所使用的访问地址和端口 29 | gitlab_rails['gitlab_ssh_host'] = '192.168.199.231' 30 | gitlab_rails['gitlab_shell_ssh_port'] = 222 # 此端口是run时22端口映射的222端口 31 | :wq #保存配置文件并退出 32 | 修改gitlab.rb文件 33 | # 重启gitlab容器 34 | $ docker restart gitlab 35 | 此时项目的仓库地址就变了。如果ssh端口地址不是默认的22,就会加上ssh:// 协议头 36 | 打开浏览器输入ip地址(因为我的gitlab端口为80,所以浏览器url不用输入端口号,如果端口号不是80,则打开为:ip:端口号) 37 | 38 | 4.创建一个项目 39 | 第一次进入要输入新的root用户密码,设置好之后确定就行 40 | 41 | gitlab页面 42 | 下面我们就可以新建一个项目了,点击Create a project 43 | 44 | Create a project 45 | 创建完成后: 46 | 47 | 48 | 创建完成! 49 | 二、用户使用 50 | 1.下载git.exe 51 | 双击git.exe安装git(一直点下一步,直到完成) 52 | 点击电脑桌面空白地方右键看到如下两行即安装成功 53 | 54 | image.png 55 | 2.登录gitlab网页 56 | url:http://192.168.1.111 57 | 填写账号密码登录 58 | 59 | 登录页面 60 | 3.设置ssh 61 | 1.打开本地git bash,使用如下命令生成ssh公钥和私钥对 62 | 63 | $ ssh-keygen -t rsa -C 'xxx@xxx.com' 64 | 然后一路回车(-C 参数是你的邮箱地址) 65 | 66 | 生成密匙 67 | 2.然后输入命令: 68 | 69 | # ~表示用户目录,比如我的windows就是C:\Users\Administrator,并复制其中的内容 70 | $ cat ~/.ssh/id_rsa.pub 71 | 公匙 72 | 3.打开gitlab,找到Profile Settings-->SSH Keys--->Add SSH Key,并把上一步中复制的内容粘贴到Key所对应的文本框 73 | 74 | 75 | 添加公匙到gitlab 76 | 4.从gitlab克隆代码 77 | 1.回到gitlab页面点击projects->your projects 78 | 79 | 80 | 2.选择一个需要克隆的项目,进入 81 | 82 | 我的项目页面 83 | 3.点击按钮复制地址 84 | 85 | 复制ssh地址 86 | 4.新建一个文件夹,我在这里在我的电脑D盘下新建project文件夹 87 | 88 | 89 | 5.进入projects文件夹右键选择->Git Bash Here 90 | 91 | 点击Git Bash Here 92 | 6.设置用户名和邮箱 93 | 94 | $ git config --global user.name "你的名字" 95 | $ git config --global user.email "你的邮箱" 96 | 设置名字和邮箱 97 | 7.克隆项目 98 | 99 | $ git clone 项目地址 100 | 克隆项目 101 | 8.查看projects文件夹,项目已经克隆下来了 102 | 103 | 项目目录 104 | 5.提交代码到gitlab 105 | 1.基于以上步骤,在克隆的项目文件夹下新增一个测试文件 106 | 107 | 新增txt文件 108 | 2.查看同步状态 109 | 在项目文件夹下右键点击->Git Bash Here 110 | 111 | 112 | 输入 113 | 114 | $ git status 115 | 状态 116 | 可以看到红色部分有需要提交的文件 117 | 3.提交代码 118 | 输入 119 | 120 | $ git add 测试提交的文件.txt 121 | (“git add“后加“.”则添加全部文件,也可以加"*.txt"表示添加全部需要提交的txt文件 ) 122 | 123 | add需要提交的文件 124 | 然后输入以下命令提交并添加提交信息 125 | 126 | $ git commit -m "message" 127 | commit 128 | 最后输出以下命令提交到gitlab 129 | 130 | $ git push origin master 131 | push 132 | 133 | 提交完成啦 134 | 再回到gitlab上看该项目就可以看到多了一个txt测试文件 135 | 136 | gitlab password 137 | root root1234567890 138 | chenye chenye123456 139 | 140 | -------------------------------------------------------------------------------- /docker/docker-gitlab修改域名配置.md: -------------------------------------------------------------------------------- 1 | ##进入容器 2 | docker exec -it gitlab bash 3 | 4 | ##停止 5 | sudo gitlab-ctl stop 6 | 7 | ##修改/etc/gitlab/gitlab.rb中的如下一行: 8 | vi /etc/gitlab/gitlab.rb 9 | 10 | ##修改/etc/gitlab/gitlab.rb中的如下一行: 11 | external_url ‘http://gitlab.xxxxx.cn’ 12 | gitlab_rails['gitlab_ssh_host'] = 'gitlab.futve.com' 13 | 14 | ##执行更新配置操作 15 | sudo gitlab-ctl reconfigure 16 | sudo gitlab-ctl start 17 | 18 | ##退出容器 19 | exit -------------------------------------------------------------------------------- /docker/docker-gitlab内存占用太多.md: -------------------------------------------------------------------------------- 1 | docker gitlab占用内存太多 2 | 3 | 进入容器 4 | docker exec -it gitlab bash 5 | 编辑配置文件 6 | vim /etc/gitlab/gitlab.rb 7 | 8 | ###1、减少进程数 9 | 修改配置文件/etc/gitlab/gitlab.rb中的worker_processes: 10 | unicorn['work_processes'] = 2 11 | 默认是被注释掉的,官方建议该值是CPU核心数加一,可以提高服务器的响应速度,如果内存只有4G,或者服务器上有其它业务,就不要改了,以免内存不足。另外,这个参数最小值是2,设为1,服务器可能会卡死。 12 | ###2、减少数据库缓存 13 | postgresql['shared_buffers'] = "256MB" 14 | 默认为256MB,可适当改小 15 | ###3、减少数据库并发数 16 | postgresql['max_worker_processes'] = 8 17 | 默认为8,可适当改小 18 | ###4、减少sidekiq并发数 19 | sidekiq['concurrency'] = 25 20 | 默认是25,可适当改小 21 | ###5、启用Swap分区 22 | 使用Swap的方法,请自行搜索 23 | 24 | 25 | 之后执行 26 | 重载配置 27 | docker exec -it gitlab gitlab-ctl reconfigure 28 | 重启 29 | docker exec -it gitlab gitlab-ctl restart 30 | 查看内存 31 | docker stats 32 | 查看内存 33 | docker stats 34 | 35 | http://www.loveqzhi.cn/index.php/archives/43/ -------------------------------------------------------------------------------- /docker/docker-hbase.md: -------------------------------------------------------------------------------- 1 | docker run -d --name hbase001 -P harisekhon/hbase:1.3 2 | 3 | 或 4 | 5 | docker run -d --name hbase001 -p 16010:16010 harisekhon/hbase:1.3 6 | 7 | 或 8 | 9 | docker run -d -h myhbase -p 2181:2181 -p 8081:8080 -p 8085:8085 -p 9090:9090 -p 9095:9095 -p 16000:16000 -p 16010:16010 -p 16201:16201 -p 16301:16301 --name hbase1.3 harisekhon/hbase:1.3 10 | docker run -d -h myhbase -p 2181:2181 -p 8081:8080 -p 8085:8085 -p 9090:9090 -p 9095:9095 -p 16000:16000 -p 16010:16010 -p 16201:16201 -p 16301:16301 --name hbase harisekhon/hbase 11 | 12 | -p : 指定主机的端口 16010映射到宿主机上(容器)的开放端口 16010 13 | -P :主机随机分配端口与宿主机上的端口进行映射 14 | 15 | 注意:hbase60010端口无法访问web页面,web端访问的接口变更为16010 -------------------------------------------------------------------------------- /docker/docker-mongo-恢复备份.md: -------------------------------------------------------------------------------- 1 | 进入容器: 2 | docker exec -it mongo bash 3 | 4 | 官方推荐 5 | 备份 6 | mongodump -d 数据库名称 --username "root" --password "xxxxxx" --out /home/dump/ 7 | mongodump -d tasks --out /root/mongo-back/2020-0318-2243 8 | mongodump --out /root/mongo-back/2020-0318-2242 --gzip 9 | mongodump -d tasks --gzip --archive=/root/mongo-back/2020-0318-2237tasks.archive 10 | mongodump -h 192.168.0.37:27017 -d tasks --gzip --archive=/root/mongo-back/2020-0616-1953tasks.archive 11 | mongodump -h 192.168.0.36:27015 -d tasks --username "tasks" --password "admin123456!" --gzip --archive=/root/mongo-back/2020-0724-1953tasks.archive 12 | 13 | mongodump -h 192.168.0.37:27017 -d tasks --username "tasks" --password "m6pCEPrTZI84Lvka" --out /root/mongo-back/2020-0511-1511-pro 14 | mongodump -h 192.168.0.38:27018 -d tasks --username "tasks" --password "admin123456!" --out /root/mongo-back/2020-0512-1810-test8 15 | mongodump -h 192.168.0.37:27017 -d tasks --username "tasks" --password "m6pCEPrTZI84Lvka" --out /root/mongo-back/2020-0526-1822-pro 16 | mongodump -h 192.168.0.36:27015 -d tasks --username "tasks" --password "admin123456!" --out /root/mongo-back/2020-0722-0703-pro 17 | 18 | mongodump -h localhost:27017 --username "root" --password "root123456!" --out /root/mongo-back/2020-0327-1551-test32 19 | mongodump -h localhost:27017 --username "root" --password "root123456!" --out /root/mongo-back/2020-0327-1551-test32 20 | #mongo32备份 21 | mongodump -h localhost:27017 --out /root/mongo-back/2020-0327-1551-test32 22 | 23 | mongorestore -d 数据库名称 --username "root" --password "xxxxxx" /home/dump/ 24 | mongorestore -d tasks --drop --gzip --archive=/root/mongo-back/2020-0318-2237tasks.archive 25 | mongorestore -d tasks --username "tasks" --password "admin123456!" /root/mongo-back/2020-0318-2242 26 | mongorestore -d tasks --username "tasks" --password "admin123456!" /root/mongo-back/2020-0318-2242 27 | mongorestore -h 127.0.0.1:27018 -d tasks --username "tasks" --password "admin123456!" /root/mongo-back/2020-0319-1416/tasks --drop 28 | mongorestore -d tasks --username "tasks" --password "admin123456!" /root/mongo-back/2020-0319-1416/tasks --drop 29 | mongorestore -d tasks --username "tasks" --password "admin123456!" /root/mongo-back/2020-0319-1416-pro 30 | mongorestore -d tasks --username "tasks" --password "admin123456!" /root/mongo-back/2020-0319-1519-pro 31 | mongorestore -d tasks --username "root" --password "root123456!" /root/mongo-back/2020-0318-2242 32 | mongorestore --username "root" --password "root123456!" /root/mongo-back/2020-0319-1519-pro 33 | mongorestore --username "root" --password "root123456!" /root/mongo-back/2020-0320-2132-pro 34 | mongorestore --username "root" --password "root123456!" /root/mongo-back/2020-0407-0956-pro 35 | 36 | #mongo34还原 -- 该方式很吃内存,可用少于4g,容易卡死 37 | mongorestore --username "root" --password "root123456!" /root/mongo-back/2020-0327-1551-test32 38 | mongorestore -h 127.0.0.1:27017 /root/mongo-back/2020-0327-1551-test32 39 | mongorestore -h 127.0.0.1:27016 -d data --username "data" --password "admin123456!" /root/mongo-back/2020-0327-1551-test32/data 40 | mongorestore -h 127.0.0.1:27016 -d yapi --username "yapi" --password "admin123456!" /root/mongo-back/2020-0327-1551-test32/yapi 41 | mongorestore -h 127.0.0.1:27016 -d tasks --username "tasks" --password "admin123456!" /root/mongo-back/2020-0327-1551-test32/tasks 42 | mongorestore -h 127.0.0.1:27016 -d tasks --username "tasks" --password "admin123456!" /root/mongo-back/2020-0407-0956-pro/tasks 43 | mongorestore -h 127.0.0.1:27016 -d tasks --username "tasks" --password "admin123456!" /root/mongo-back/2020-0409-0853-pro/tasks 44 | mongorestore -h 127.0.0.1:27016 -d tasks --username "tasks" --password "admin123456!" /root/mongo-back/2020-0418-2020-pro/tasks 45 | mongorestore -h 127.0.0.1:27018 -d tasks --username "tasks" --password "admin123456!" /root/mongo-back/2020-0507-1749-pro/tasks 46 | mongorestore -h 127.0.0.1:27018 -d tasks --username "tasks" --password "admin123456!" /root/mongo-back/2020-0511-1511-pro/tasks 47 | mongorestore -h 127.0.0.1:27016 -d tasks --username "tasks" --password "admin123456!" /root/mongo-back/2020-0512-1810-test8/tasks 48 | mongorestore -h 127.0.0.1:27015 -d tasks --username "tasks" --password "admin123456!" /root/mongo-back/2020-0526-1822-pro/tasks 49 | mongorestore -h 127.0.0.1:27015 -d tasks --username "tasks" --password "admin123456!" /root/mongo-back/2020-0526-1822-pro/tasks 50 | mongorestore -h 127.0.0.1:27015 -d tasks --username "tasks" --password "admin123456!" /root/mongo-back/2020-0512-1810-test8/tasks 51 | mongorestore -h 127.0.0.1:27015 -d tasks --username "tasks" --password "admin123456!" //root/mongo-back/2020-0527-test/tasks 52 | mongorestore -h 127.0.0.1:27014 -d tasks --username "tasks" --password "admin123456!" /root/mongo-back/2020-0722-0703-pro/tasks 53 | 54 | 55 | 56 | 57 | 58 | 备份为archive 59 | mongodump -d tasks --gzip --archive=/root/mongo-back/2020-0318-2237tasks.archive 60 | 恢复备份 61 | 62 | mongorestore -h {host}:27017 -u {user} -p {user_password} -d {db_name} --drop --gzip --archive={back_path}.archive 63 | -h 指定ip port 64 | -u用户 65 | -p 密码 66 | --drop 删除 67 | mongorestore -h 127.0.0.1:27017 -d tasks --drop --gzip --archive=/root/mongo-back/tasks.archive 68 | mongorestore -h 127.0.0.1:27017 -d tasks --drop --gzip --archive=/root/mongo-back/2020-0318-2237tasks.archive 69 | 70 | mongorestore -h 192.168.0.37:27017 -d tasks --drop --gzip --archive=/root/mongo-back/2020-0318-2237tasks.archive 71 | 72 | mongorestore -h 127.0.0.1:27015 -d tasks --username "tasks" --password "admin123456!" --drop --gzip --archive=/root/mongo-back/2020-0527tasks.archive 73 | mongorestore -h 192.168.0.36:27015 -d tasks --username "tasks" --password "admin123456!" --drop --gzip --archive=/root/mongo-back/2020-0616tasks.archive 74 | mongorestore -h 192.168.0.36:27015 -d tasks --username "tasks" --password "admin123456!" --drop --gzip --archive=/root/mongo-back/2020-0616-1953tasks.archive 75 | 76 | docker命令 77 | docker run -v /rootmongo-back:/root/mongo-back -d -p 27018:27017 --name mongo mongo 78 | 79 | 映射/root:/root/mongo-back -------------------------------------------------------------------------------- /docker/docker-mongodb.md: -------------------------------------------------------------------------------- 1 | 2 | docker run -v /root/mongo-back:/root/mongo-back -d -p 27018:27017 --name mongo mongo 3 | #2020-0314最新稳定版为4.2.3 4 | docker run -v /root/mongo-back:/root/mongo-back -d -p 27018:27017 --name mongo423 mongo:4.2.3 5 | docker run -v /root/mongo-back:/root/mongo-back -d -p 27018:27017 --name mongo423 mongo:4.2.3 6 | docker run -v /root/mongo-back:/root/mongo-back -d -p 27018:27017 --name mongo423 mongo:4.2.3 --auth 7 | docker run -v /root/mongo-back:/root/mongo-back -d -p 27016:27017 --name mongo34 mongo:3.4 --auth 8 | docker run -v /root/mongo-back:/root/mongo-back -d -p 27015:27017 --name mongo3420 mongo:3.4.20 --auth 9 | docker update --restart=always mongo423 10 | docker run -v /root/mongo-back:/root/mongo-back -d -p 27018:27017 --name mongo mongo --auth 11 | docker run -v /root/mongo-back:/root/mongo-back -d -p 27018:27017 --name mongo mongo:3.2 --auth 12 | docker run -v /root/mongo-back:/root/mongo-back -d -p 27017:27017 --name mongo mongo:3.4 13 | 14 | docker update --restart=always mongo 15 | docker update --restart=always mongo34 16 | docker update --restart=on-failure:3 mongo34 17 | 18 | 19 | docker run --name mongo-server \ 20 | -p 27019:27017 \ 21 | --mount type=bind,src=/root/mongo-back,dst=/data/configdb \ 22 | --restart=on-failure:3 \ 23 | -d mongo 24 | 25 | docker run --name mongo-server \ 26 | -p 27017:27017 \ 27 | --mount type=bind,src=/root/docker/mongo/conf,dst=/root/mongo-back \ 28 | --mount type=bind,src=/root/docker/mongo/data,dst=/data/db \ 29 | --restart=on-failure:3 \ 30 | -d mongo 31 | 32 | 33 | --name:为容器指定一个名字 34 | -p:指定端口映射,格式为:主机(宿主)端口:容器端口 35 | -e:username="xxx",设置环境变量 36 | --restart=on-failure:3:是指容器在未来出现异常退出(退出码非0)的情况下循环重启3次 37 | -mount:绑定挂载 38 | -d:后台运行容器,并返回容器 id 39 | 40 | #管理员方式进入容器 41 | docker exec -it mongo423 mongo admin 42 | docker exec -it mongo34 mongo admin 43 | docker exec -it mongo3420 mongo admin 44 | docker exec -it mongo mongo admin 45 | #进入容器 46 | docker exec -it mongo bash 47 | #创建admin(所有数据库角色) 48 | db.createUser({ user: 'root', pwd: 'root123456!', roles: [ { role: "userAdminAnyDatabase", db: "admin" } ] }); 49 | db.grantRolesToUser ( "root", [ { role: "dbAdminAnyDatabase", db: "admin" } ] ) 50 | db.grantRolesToUser ( "root", [ { role: "dbAdminAnyDatabase", db: "admin" } ] ) 51 | db.grantRolesToUser ( "root", [ { role: "readWriteAnyDatabase", db: "admin" } ] ) 52 | 53 | #认证用户 54 | db.getSiblingDB("admin").auth("root", "root123456!") 55 | db.auth("root", "root123456!") 56 | use tasks 57 | db.createUser({ user: 'tasks', pwd: 'admin123456!', roles: [ { role: "dbAdmin", db: "tasks" } ] }); 58 | db.grantRolesToUser ( "tasks", [ { role: "dbOwner", db: "tasks" } ] ) 59 | db.grantRolesToUser ( "tasks", [ { role: "dbAdmin", db: "tasks" } ] ) 60 | db.auth("tasks", "admin123456!") 61 | db.auth("tasks", "m6pCEPrTZI84Lvka") 62 | db.test1.insert({1:1}) 63 | 64 | use logs 65 | db.createUser({ user: 'logs', pwd: 'admin123456!', roles: [ { role: "dbAdmin", db: "logs" } ] }); 66 | db.grantRolesToUser ( "logs", [ { role: "dbOwner", db: "logs" } ] ) 67 | db.auth("logs", "admin123456!") 68 | db.test1.insert({1:1}) 69 | 70 | 71 | use yapi 72 | db.createUser({ user: 'yapi', pwd: 'admin123456!', roles: [ { role: "dbAdmin", db: "yapi" } ] }); 73 | db.grantRolesToUser ( "yapi", [ { role: "dbOwner", db: "yapi" } ] ) 74 | db.auth("yapi", "admin123456!") 75 | db.test1.insert({1:1}) 76 | 77 | use data 78 | db.createUser({ user: 'data', pwd: 'admin123456!', roles: [ { role: "dbAdmin", db: "data" } ] }); 79 | db.grantRolesToUser ( "data", [ { role: "dbOwner", db: "data" } ] ) 80 | db.auth("data", "admin123456!") 81 | db.test1.insert({1:1}) 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 备份 92 | mongodump --host 192.168.0.1 --port 37017 --username user --password "pass" --gzip --out /opt/backup/mongodump-2019-04-17 93 | mongodump -h dbhost -d dbname -o dbdirectory 94 | mongodump -h 127.0.0.1:27017 -d tasks --gzip --out /root/mongo-back/20200103tasks.archive 95 | mongodump -h 127.0.0.1:27017 -d tasks --gzip --archive=/root/mongo-back/20200115-1054tasks.archive 96 | mongodump -h 127.0.0.1:27017 -d tasks --gzip --archive=/root/mongo-back/20200314-1607tasks.archive 97 | mongodump -h 127.0.0.1:27017 -d tasks --gzip --archive=/root/mongo-back/20200314-1607tasks.archive -u root -p root123456! 98 | mongodump -h 127.0.0.1:27017 -d tasks --gzip --archive=/root/mongo-back/20200314-1655tasks.archive -u tasks -p admin123456! 99 | mongodump -h 127.0.0.1:27017 -d tasks --gzip --archive=/root/mongo-back/20200115-1054tasks.archive -u tasks -p admin123456! 100 | mongodump -h 127.0.0.1:27017 -d tasks --gzip --archive=/root/20200314-1616tasks.archive -u tasks -p m6pCEPrTZI84Lvka! 101 | 102 | 103 | 恢复 104 | mongo i27.0.0.1:27017/admin -u root -p root123456! 105 | 106 | mongorestore -h {host}:27017 -u {user} -p {user_password} -d {db_name} --drop --gzip --archive={back_path}.archive 107 | mongorestore -h 127.0.0.1:27017 -d tasks --drop --gzip --archive=/root/mongo-back/mongo-back/tasks.archive 108 | mongorestore -h 127.0.0.1:27017 -d tasks --drop --gzip --archive=/root/mongo-back/tasks.archive 109 | mongorestore -h 127.0.0.1:27017 -d tasks --drop --gzip --archive=/root/mongo-back/20200120tasks.archive 110 | mongorestore -h 127.0.0.1:27017 -d tasks --drop --gzip --archive=/root/mongo-back/tasks2020-0308.archive 111 | mongorestore -u tasks -p admin123456! -h 127.0.0.1:27017 -d tasks --drop --gzip --archive=/root/mongo-back/tasks2020-0308.archive 112 | 113 | 114 | 报错处理 115 | 如果navicat连接Mongo报错 not authorized on root to execute command 116 | 117 | docker exec -it mongo423 mongo admin 118 | db.auth("root","root123456!") 119 | #增加权限 120 | db.grantRolesToUser ( "root", [ { role: "__system", db: "admin" } ] ) 121 | db.grantRolesToUser ( "tasks", [ { role: "__system", db: "tasks" } ] ) 122 | db.grantRolesToUser ( "tasks", [ { role: "__system", db: "logs" } ] ) 123 | 124 | db.grantRolesToUser ( "tasks", [ { role: "dbAdmin", db: "tasks" } ] ) 125 | db.grantRolesToUser ( "tasks", [ { role: "dbOwner", db: "tasks" } ] ) 126 | db.grantRolesToUser ( "logs", [ { role: "dbOwner", db: "logs" } ] ) 127 | db.grantRolesToUser ( "logs", [ { data: "dbAdmin", db: "data" } ] ) 128 | db.grantRolesToUser ( "logs", [ { role: "dbAdmin", db: "tasks" } ] ) 129 | 130 | 1.数据库用户角色:read、readWrite; 131 | 2.数据库管理角色:dbAdmin、dbOwner、userAdmin; 132 | 3.集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager; 133 | 4.备份恢复角色:backup、restore 134 | 5.所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase 135 | 6.超级用户角色:root 136 | 137 | 138 | ./mongod --dbpath=/path/mongodb 139 | ./mongod --dbpath=/var/lib/mongodb 140 | /var/lib/mongodb 141 | /usr/bin/mongod --dbpath=/var/lib/mongodb 142 | /usr/bin/mongod --dbpath=/var/lib/mongodb & 143 | /usr/mongodb/bin/mongod --config /usr/mongodb/mongodb.conf 144 | /usr/bin/mongod --config /usr/mongodb/mongodb.conf 145 | -------------------------------------------------------------------------------- /docker/docker-mysql.md: -------------------------------------------------------------------------------- 1 | #正确 2 | docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=db123456! --name mysql -v /mnt/mysql:/var/lib/mysql57 mysql:5.7 --character-set-server=utf8 --collation-server=utf8_unicode_ci --character-set-client-handshake=FALSE 3 | docker run -d -p 3304:3306 -e MYSQL_ROOT_PASSWORD=db123456! --name mysql -v /mnt/mysql:/var/lib/mysql57 mysql:5.7 --character-set-server=utf8 --collation-server=utf8_unicode_ci --character-set-client-handshake=FALSE 4 | docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=db123456! --name mysql8 -v /mnt/mysql8:/var/lib/mysql57 mysql:8 --character-set-server=utf8 --collation-server=utf8_unicode_ci --character-set-client-handshake=FALSE 5 | docker run -d -p 3304:3306 -e MYSQL_ROOT_PASSWORD=db123456! --name mysql8-futve -v /mnt/mysql8:/var/lib/mysql57 mysql:8 --character-set-server=utf8 --collation-server=utf8_unicode_ci --character-set-client-handshake=FALSE 6 | docker run -d -p 3305:3306 -e MYSQL_ROOT_PASSWORD=db123456!@ --name mysql8 -v /mnt/mysql8:/var/lib/mysql8 mysql:8 --character-set-server=utf8 --collation-server=utf8_unicode_ci --character-set-client-handshake=FALSE 7 | docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=db123456!@ --name mysql8 -v /mnt/mysql8:/var/lib/mysql8 mysql:8 --character-set-server=utf8 --collation-server=utf8_unicode_ci --character-set-client-handshake=FALSE 8 | docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql8 -v /mnt/mysql8:/var/lib/mysql57 mysql:8 --character-set-server=utf8 --collation-server=utf8_unicode_ci --character-set-client-handshake=FALSE 9 | 10 | 11 | #错误,测试 12 | docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=db123456! --name mysql8 -v /mnt/mysql8:/var/lib/mysql mysql:8 --character-set-server=utf8 --collation-server=utf8_unicode_ci --character-set-client-handshake=FALSE 13 | docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=db123456! --name mysql8 -v /mnt/mysql8:/var/lib/mysql57 mysql:8 --character-set-server=utf8 --collation-server=utf8_unicode_ci --character-set-client-handshake=FALSE -e TZ=Asia/Shanghai 14 | #说明,mysql8不支持映射空文件映射, 15 | 例如,-v /mnt/mysql8:/var/lib/mysql 16 | 旧的时区换方式也不能用了 这个-e TZ=Asia/Shanghai 17 | 18 | 19 | 开机启动 20 | docker update --restart=always mysql 21 | 22 | --还原 23 | mysql  -u  user   -p    [dbname]  <  filename.sql   24 | mysql  -u  root db123456! will_art < will_art.sql  25 | mysql  -u  root will_art < will_art.sql  26 | mysql –uroot –proot will_art < /var/lib/mysql/backup/will_art.sql 27 | user  是执行  backup.sql  文件中语句的用户名;  p 表示用户密码;dbname 是数据库名。如果  filename.sgl  文件为mysqldump 工具创建的包含创建数据库语句的文件,执行的时候不需要指定数据库名。 28 | 29 | --备份 30 | mysqldump -h 192.168.1.100 -p 3306 -u root -p password --database cmdb > /data/backup/cmdb.sql 31 | 32 | /var/lib/mysql/backup# pwd 33 | /var/lib/mysql/backup 34 | root@67e0113f3f23:/var/lib/mysql/backup# 35 | 36 | 37 | 38 | 39 | 40 | mysql -u root -p booksDB < F:\backup\booksDB_20180603.sql 41 | -------------------------------------------------------------------------------- /docker/docker-redis.md: -------------------------------------------------------------------------------- 1 | docker run --name redis -d -p 6380:6379 redis --appendonly yes 2 | docker run --name redis -d -p 6379:6379 redis --appendonly yes 3 | docker run --name redis -d -p 6379:6379 redis --appendonly yes -v /root/db 4 | docker run --name redis78 -d -v /root/mongo-back:/root/mongo-back -p 6380:6379 redis --appendonly yes 5 | docker run --name redis -d -v /root/db-backup:/root/db-backup -p 6380:6379 redis:6.0.5 --appendonly yes 6 | docker update --restart=always redis 7 | 8 | #redis 备份 9 | redis-cli -p 6379 10 | 生成dump.rdb 11 | SAVE 12 | 查看dump.rdb目录 13 | config get dir 14 | ##还原 15 | 把dump.rdb替换 16 | /var/lib/redis的dump.rdb 17 | 18 | -------------------------------------------------------------------------------- /docker/docker-sonarqube.md: -------------------------------------------------------------------------------- 1 | docker run --name sonarqube -d -v /root/mongo-back:/root/mongo-back -p 9009:9000 sonarqube 2 | docker run --name sonarqube -d -p 9009:9000 sonarqube 3 | docker run -d --name sonarqube3 -p 9020:9000 sonarqube 4 | 5 | docker update --restart=always sonarqube 6 | 7 | -------------------------------------------------------------------------------- /docker/docker-yapi.md: -------------------------------------------------------------------------------- 1 | 管理员账号:admin@docker.yapi 2 | 管理员密码:adm1n 3 | 4 | 15002770045@139.com 5 | ganyinglai123@foxmail.com 6 | xujiebing1992@foxmail.com 7 | # 8 | docker run --rm -p 40001:3000 jayfong/yapi:play 9 | docker run -d -p 40001:3000 jayfong/yapi:play 10 | docker run -d -p 40001:3000 -p 2701:27017 jayfong/yapi:play 11 | 12 | ##开机启动 13 | docker update --restart=always yapi 14 | 15 | 参考 16 | https://github.com/fjc0k/docker-YApi 17 | https://github.com/YMFE/yapi 18 | https://gitee.com/mirrors/YApi 19 | 20 | 备份 21 | mongodump -h 127.0.0.1:2701 -d yapi --gzip --archive=/root/mongo-back/2020-0620-yapi.archive 22 | 还原 23 | mongorestore -h 127.0.0.1:2701 -d yapi --drop --gzip --archive=/root/mongo-back/2020-0620-yapi.archive 24 | -------------------------------------------------------------------------------- /docker/docker-禅道.md: -------------------------------------------------------------------------------- 1 | docker pull idoop/zentao 2 | 3 | docker run -d -p 83:80 -p 3309:3306 -e USER="root" -e PASSWD="password" -e BIND_ADDRESS="false" -e SMTP_HOST="163.177.90.125 smtp.exmail.qq.com" -v /data/zbox/:/opt/zbox/ --name zentao-server idoop/zentao:latest 4 | 5 | 禅道默认用户密码为admin-123456 6 | 39.97.250.105修改为Chenye15002770045 7 | -------------------------------------------------------------------------------- /docker/docker.md: -------------------------------------------------------------------------------- 1 | cd /home/chenye 2 | 3 | 查看容器docker ps -a 4 |   5 | 6 | 停止容器docker stop dfafc85bd908 7 |   8 | 9 | 删除容器 docker rm dfafc85bd908 10 | 查看 镜像 11 | 12 | docker images 13 | 14 | 删除镜像 15 | 16 | docker rmi 396299b75924 17 | 18 |   19 | 20 |   21 | 22 | 将jar 和dockerfile复制到当前目录, 23 | 24 | ---- start --- 25 | #定义基础环境,后续执行在此基础上进行的,即jdk环境 26 | FROM java:8 27 | #指定作者 28 | MAINTAINER chenye 29 | #复制本地jar到镜像中 30 | ADD pigtest.jar /app.jar 31 | #暴露给容器外的端口 32 | EXPOSE 9290 33 | #执行的命令 34 | ENTRYPOINT ["java","-Xms2g","-Xmx2g","-jar","app.jar","--spring.profiles.active=hk","--server.port=8280"] 35 | ----- end --- 36 | 37 | 38 | home/chenye 39 | 40 | 用jar生成镜像 41 | 42 | docker build -t art . 43 | 44 | 启动镜像 45 | docker run -d -p 8280:8280 art 46 | 47 | ———————————————— 48 | 版权声明:本文为CSDN博主「qq_34874784」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 49 | 原文链接:https://blog.csdn.net/qq_34874784/article/details/103480342 -------------------------------------------------------------------------------- /docker/docker国内镜像.md: -------------------------------------------------------------------------------- 1 | tee /etc/docker/daemon.json <<-'EOF' 2 | { 3 | "registry-mirrors": ["https://9rl160ta.mirror.aliyuncs.com"] 4 | } 5 | EOF 6 | 7 | systemctl restart docker 8 | 重启生效 -------------------------------------------------------------------------------- /docker/docker清理空间.md: -------------------------------------------------------------------------------- 1 | docker清理未使用空间 2 | 3 | 若要删除未使用的volume,可以使用内置程序 4 | #列出未使用的volume 5 | ``` 6 | docker volume ls -qf dangling=true 7 | ``` 8 | 9 | #删除未使用的volume 10 | ``` 11 | docker volume rm $(docker volume ls -qf dangling=true) 12 | ``` 13 | 14 | 删除所有未使用数据 15 | ``` 16 | docker system prune 17 | ``` 18 | 比如想删除未使用的image,container,volume,network查看官方文档https://docs.docker.com/config/pruning/#prune-networks -------------------------------------------------------------------------------- /docker/docker部署jar.md: -------------------------------------------------------------------------------- 1 | docker pull java:8 2 | docker pull java:8u191 3 | 4 | docker run -d -p 8280:8280 -v /root/label-service/art.jar:/root/label-service/art.jar --name art java:8 java -Xms2g -Xmx2g -jar /root/label-service/art.jar --spring.profiles.active=en --server.port=8280 5 | docker update --restart=always art 6 | docker run -d -p 8280:8280 --restart=always -v /root/label-service:/root/label-service --name art java:8 java -Xms2g -Xmx2g -jar /root/label-service/art.jar --spring.profiles.active=en --server.port=8280 7 | #官网服务docker部署命令 8 | ker run -d -p 9039:9039 --restart=always -v /root/www-service:/root/www-service --name futve java:8 java -Dlogging.file=/root/www-service/futve.log -jar /root/www-service/futve.jar --spring.profiles.active=43 --server.port=9039 9 | 10 | docker run -d -p 80:80 -v /root/label-frontend:/root/label-frontend --name front node:12 node /root/label-frontend/server.js --env=production 11 | 12 | docker run -d -p 80:80 --restart=always -v /root/label-frontend:/root/label-frontend --name front node:12 cd /root/label-frontend/ && node server.js --env=production 13 | 14 | docker run -d -p 80:80 -v /root/label-frontend:/root/label-frontend --name front node:12 node sh /root/label-frontend/start.sh 15 | 16 | node /root/label-frontend/server.js --env=production 17 | docker run -d -p 80:80 --restart=always front -v /root/label-frontend:/root/label-frontend --name front node:12 sh /root/label-frontend/start.sh 18 | docker update --restart=always front 19 | 20 | p 8380:8280 表示将容器的端口 映射成宿主主机的端口,否则8280端口访问不到 21 | 22 | -v /usr/springboot-1.jar:/usr/springboot-1.jar 表示将宿主主机的jar文件,映射到容器中(分号前为宿主主机的路径,分号后为容器中的路径) 23 | 24 | --name art 表示为该容器取一个全局唯一的名称,这里我取的名称为springboot 25 | 26 | java:8u191 表示镜像文件的名称和tag 27 | 28 | java -jar /root/label-service/art.jar 表示运行jar包,注意:这里的jar包为容器中的位置,是通过前面的-v属 -------------------------------------------------------------------------------- /docker/docker限制资源内存cpu.md: -------------------------------------------------------------------------------- 1 | docker如何限制已经在运行的容器cpu和内存 2 | 3 | docker container update gitlabseafilegit_gitlab_1_66166xxx --cpus="2" --memory="8g" --memory-swap="-1" 4 | 5 | docker container update rocketmq-console-ng --cpus="1" --memory="1g" --memory-swap="-1" 6 | 7 | 8 | -------------------------------------------------------------------------------- /docker/git/docker-gitea.md: -------------------------------------------------------------------------------- 1 | docker run -d --name gitea --restart=always -p 422:22 -p 10082:3000 gitea/gitea -------------------------------------------------------------------------------- /docker/jenkins重置密码.md: -------------------------------------------------------------------------------- 1 | 1、查看所有容器 2 | 1 3 | docker ps 4 | 2、进入gitlab容器中 5 | 1 6 | docker exec -it gitlab bash 7 | 回到顶部 8 | 二、修改密码 9 | 官网也有相关的说法:https://docs.gitlab.com/ce/security/reset_root_password.html 10 | 11 | 1、要重置您的root密码,请首先使用root特权登录到服务器。使用以下命令启动Ruby on Rails控制台 12 | gitlab-rails console -e production 13 | 2、等待控制台加载完毕,有多种找到用户的方法,您可以搜索电子邮件或用户名 14 | user = User.where(id: 1).first 15 | 或者 16 | user = User.find_by(email: 'admin@example.com') 17 | 3、现在,您可以更改密码 18 | user.password = 'secret_pass' 19 | user.password = 'root1234567890' 20 | user.password_confirmation = 'secret_pass' 21 | user.password_confirmation = 'root1234567890' 22 | 4、重要的是,您必须同时更改密码和password_confirmation才能使其正常工作,别忘了保存更改 23 | 1 24 | user.save! -------------------------------------------------------------------------------- /docker/mq/docker-rocketmq.md: -------------------------------------------------------------------------------- 1 | 在conf/broker.conf 中 加入 两行配置 2 | namesrvAddr = 你的公网IP:9876 3 | brokerIP1=你的公网IP 4 | 5 | docker run -d -p 9876:9876 --restart=always -v /root/java/rocketmq-all-4.7.1-bin-release-docker:/mq --name nameserver adoptopenjdk/openjdk8-openj9 sh /mq/bin/mqnamesrv 6 | docker logs -f nameserver 7 | docker run -d -p 10909:10909 -p 10910:10910 -p 10911:10911 --restart=always -v /root/java/rocketmq-all-4.7.1-bin-release-docker:/mq --name mqbroker adoptopenjdk/openjdk8-openj9 sh /mq/bin/mqbroker -n 39.97.250.105:9876 -c /mq/conf/broker.conf autoCreateTopicEnable=true 8 | docker logs -f mqbroker 9 | #####查看ip 10 | docker inspect nameserver -------------------------------------------------------------------------------- /docker/nexus私服/docker-nexus.md: -------------------------------------------------------------------------------- 1 | ##nexus2 安装 2 | docker run -p 8082:8081 --name nexus2 sonatype/nexus 3 | 4 | 首页 5 | http://39.97.250.105:8082/nexus/index.html 6 | ###默认用户名密码 7 | admin 8 | admin123 9 | 10 | 进入容器 11 | docker exec -it nexus2 bash 12 | 查看密码 13 | 14 | ## nexus3 安装 15 | ``` 16 | docker run -p 8083:8081 --name nexus3 sonatype/nexus3 17 | ``` 18 | 首页 19 | http://39.97.250.105:8083 20 | 21 | Your admin user password is located in 22 | /nexus-data/admin.password on the server. 23 | -------------------------------------------------------------------------------- /docker/注册中心/docker-nacos.md: -------------------------------------------------------------------------------- 1 | docker run --env MODE=standalone --name nacos -d -p 8848:8848 nacos/nacos-server -------------------------------------------------------------------------------- /docker/注册中心/docker-zookeeper.md: -------------------------------------------------------------------------------- 1 | docker run --privileged=true -d --name zookeeper --publish 2181:2181 -d zookeeper:latest 2 | 3 | docker run -d -p 2181:2181 --name some-zookeeper --restart always zookeeper -------------------------------------------------------------------------------- /ide/eclipse/eclipse 设置启动jdk版本.md: -------------------------------------------------------------------------------- 1 | 打开eclipse安装目录下的eclipse.ini文件,将内容加入开头 2 | 3 | -vm 4 | 5 | D:/software/jdk_1.8u91/bin(jdk版本) -------------------------------------------------------------------------------- /ide/idea/idea模板.md: -------------------------------------------------------------------------------- 1 | ##模板参数 2 | ``` 3 | * 4 | * @description //TODO $end$ 5 | * @author chenye 6 | * @date $time$ $date$ 7 | * @param $param$ 8 | * @return $return$ 9 | **/ 10 | 11 | ``` 12 | 13 | time 14 | ``` 15 | time() 16 | ``` 17 | 18 | date 19 | ``` 20 | date() 21 | ``` 22 | 23 | param 24 | ```$xslt 25 | groovyScript("def result=''; def stop=false; def params=\"${_1}\".replaceAll('[\\\\[|\\\\]|\\\\s]', '').split(',').toList(); if (params.size()==1 && (params[0]==null || params[0]=='null' || params[0]=='')) { stop=true; }; if(!stop) { for(i=0; i < params.size(); i++) {result +=((i==0) ? '\\r\\n' : '') + ((i < params.size() - 1) ? ' * @param: ' + params[i] + '\\r\\n' : ' * @param: ' + params[i] + '')}; }; return result;", methodParameters()) 26 | 27 | ``` 28 | 29 | ##其他 30 | 修改快捷键为回车(enter) -------------------------------------------------------------------------------- /images/basic/algorithm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stylesmile/javaRoad/500e28dd78804c915df06cef32a3e95d3b989465/images/basic/algorithm.png -------------------------------------------------------------------------------- /js/file/excel_deal.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | js如何解析Excel文件 6 | 7 | 8 | 9 | 10 | 11 | 35 | -------------------------------------------------------------------------------- /linux/linux编译安装nginx.md: -------------------------------------------------------------------------------- 1 | 1下载 2 | 3 | http://nginx.org/en/download.html 4 | 2.解压 5 | 6 | tar zxvf nginx-1.19.2.tar.gz 7 | 8 | 3.进入文件夹 9 | 10 | cd nginx-1.19.2 11 | 12 | 4.配置 13 | 14 | ./configure --prefix=/usr/local/nginx 15 | 16 | 正常的编译安装/卸载 17 | 源码的安装一般由3个步骤组成: 18 | 19 | 配置(configure) 20 | 编译(make) 21 | 安装(make install) 22 | 23 | configure文件是一个可执行的脚本文件,它有很多选项,在待安装的源码目录下使用命令./configure –help可以输出详细的选项列表。 24 | 其中--prefix选项是配置安装目录,如果不配置该选项,安装后可执行文件默认放在/usr /local/bin,库文件默认放在/usr/local/lib,配置文件默认放在/usr/local/etc,其它的资源文件放在/usr /local/share,比较凌乱。 25 | 如果配置了--prefix,如: 26 | $ ./configure --prefix=/usr/local/test 27 | 28 | 安装后的所有资源文件都会被放在/usr/local/test目录中,不会分散到其他目录。 29 | 使用--prefix选项的另一个好处是方便卸载软件或移植软件 30 | 当某个安装的软件不再需要时,只须简单的删除该安装目录,就可以把软件卸载干净; 31 | 移植软件只需拷贝整个目录到另外一个机器即可(相同的操作系统下) 32 | 当然要卸载程序,也可以在原来的make目录下用一次make uninstall,但前提是Makefile文件有uninstall命令。 33 | 34 | make install PREFIX=path 35 | 这里PREFIX必须大写,其实绝大部分情况下 make install 都不能再指定 PREFIX 了,因为大部分程序都会 configure 时得到的 prefix 写入 config.h,然后在编译时编译到可执行文件内部,以便在执行时读取资源文件等。 36 | 37 | 这样在编译完毕后,就不能再修改 prefix 了。只有运行时不需要资源文件的小工具,才可能在安装的时候随意选择 PREFIX,或者具有 loader 的大程序,在执行时通过 loader 传入路径…… 38 | 39 | 关于卸载 40 | 如果没有配置--prefix选项,源码包也没有提供make uninstall,则可以通过以下方式可以完整卸载: 41 | 42 | 一个临时目录重新安装一遍,如: 43 | $ ./configure --prefix=/tmp/to_remove && make install 44 | 然后遍历/tmp/to_remove的文件,删除对应安装位置的文件即可(因为/tmp/to_remove里的目录结构就是没有配置--prefix选项时的目录结构)。 45 | 5.编译安装 46 | 47 | make && make install 48 | 49 | 6.验证是否安装成功 50 | 51 | /usr/local/nginx/sbin/nginx -V 52 | 53 | nginx version: nginx/1.19.2 54 | built by gcc 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.12) 55 | configure arguments: --prefix=/usr/local/nginx 56 | 7.配置nginx 服务 57 | 58 | vi /usr/lib/systemd/system/nginx.service 59 | 添加如下: 60 | 61 | [Unit] 62 | 63 | Description=nginx - high performance web server 64 | 65 | Documentation=http://nginx.org/en/docs/ 66 | 67 | After=network.target remote-fs.target nss-lookup.target 68 | 69 | [Service] 70 | 71 | Type=forking 72 | 73 | PIDFile=/usr/local/nginx/logs/nginx.pid 74 | 75 | ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.confExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf 76 | 77 | ExecReload=/bin/kill -s HUP $MAINPID 78 | 79 | ExecStop=/bin/kill -s QUIT $MAINPID 80 | 81 | PrivateTmp=true [Install]WantedBy=multi-user.target 82 | 执行: 83 | 84 | /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf 85 | 86 | 启动nginx: 87 | 88 | systemctl start nginx 89 | 90 | 设置开机启动: 91 | 92 | systemctl enable nginx 93 | 94 | 95 | 96 | cd /usr/local/nginx 97 | pwd 98 | ls 99 | 100 | 101 | 启动Nginx 102 | 103 | /usr/local/nginx/sbin/nginx 104 | 查看Nginx进程是否启动 105 | 106 | ps aux | grep nginx 107 | 108 | 109 | 查看Nginx占用的端口号 110 | 111 | netstat -tlnp 112 | 113 | 114 | 使用本地主机访问虚拟机上的Nginx服务器 115 | 116 | 停止nginx 117 | 停止Nginx的三种方式 118 | 119 | # 1. 立即停止Nginx服务 120 | /usr/local/nginx/sbin/nginx -s stop 121 | 122 | # 2.完成当前任务后停止 123 | /usr/local/nginx/sbin/nginx -s quit 124 | 125 | # 3.杀死Nginx进程 126 | killall nginx 127 | 把nginx命令添加到环境变量 128 | 使用软连接将nginx链接到/usr/local/sbin 129 | 130 | ln -s /usr/local/nginx/sbin/nginx /usr/local/sbin 131 | ll /usr/local/sbin/ | grep "nginx" 132 | 133 | 134 | 显示当前环境变量PATH 135 | 136 | echo $PATH 137 | 编辑.bash_profile文件 138 | 139 | vim ~/.bash_profile 140 | 在.bash_profile文件末尾加入以下内容 141 | 142 | export PATH=$PATH:/usr/local/nginx/sbin 143 | 144 | 145 | 引用.bash_profile文件 146 | 147 | source ~/.bash_profile 148 | 使用nginx命令 149 | 150 | # 启动nginx 151 | nginx 152 | # 停止nginx 153 | nginx -s quit 154 | 把nginx命令添加到系统服务 155 | 创建并编辑文件/root/service-nginx.sh 156 | 157 | #!/bin/sh 158 | # 159 | # filename: service-nginx.sh 160 | # 161 | # nginx - this script starts and stops the nginx daemon 162 | # 163 | # chkconfig: - 85 15 164 | # description: NGINX is an HTTP(S) server, HTTP(S) reverse \ 165 | # proxy and IMAP/POP3 proxy server 166 | # processname: nginx 167 | # config: /etc/nginx/nginx.conf 168 | # config: /etc/sysconfig/nginx 169 | # pidfile: /var/run/nginx.pid 170 | 171 | # Source function library. 172 | . /etc/rc.d/init.d/functions 173 | 174 | # Source networking configuration. 175 | . /etc/sysconfig/network 176 | 177 | # Check that networking is up. 178 | [ "$NETWORKING" = "no" ] && exit 0 179 | 180 | #nginx="/usr/sbin/nginx" 181 | nginx="/usr/local/sbin/nginx" 182 | prog=$(basename $nginx) 183 | 184 | #NGINX_CONF_FILE="/etc/nginx/nginx.conf" 185 | NGINX_CONF_FILE="/usr/local/nginx/conf/nginx.conf" 186 | 187 | [ -f /etc/sysconfig/nginx ] && . /etc/sysconfig/nginx 188 | 189 | lockfile=/var/lock/subsys/nginx 190 | 191 | make_dirs() { 192 | # make required directories 193 | user=`$nginx -V 2>&1 | grep "configure arguments:.*--user=" | sed 's/[^*]*--user=\([^ ]*\).*/\1/g' -` 194 | if [ -n "$user" ]; then 195 | if [ -z "`grep $user /etc/passwd`" ]; then 196 | useradd -M -s /bin/nologin $user 197 | fi 198 | options=`$nginx -V 2>&1 | grep 'configure arguments:'` 199 | for opt in $options; do 200 | if [ `echo $opt | grep '.*-temp-path'` ]; then 201 | value=`echo $opt | cut -d "=" -f 2` 202 | if [ ! -d "$value" ]; then 203 | # echo "creating" $value 204 | mkdir -p $value && chown -R $user $value 205 | fi 206 | fi 207 | done 208 | fi 209 | } 210 | 211 | start() { 212 | [ -x $nginx ] || exit 5 213 | [ -f $NGINX_CONF_FILE ] || exit 6 214 | make_dirs 215 | echo -n $"Starting $prog: " 216 | daemon $nginx -c $NGINX_CONF_FILE 217 | retval=$? 218 | echo 219 | [ $retval -eq 0 ] && touch $lockfile 220 | return $retval 221 | } 222 | 223 | stop() { 224 | echo -n $"Stopping $prog: " 225 | killproc $prog -QUIT 226 | retval=$? 227 | echo 228 | [ $retval -eq 0 ] && rm -f $lockfile 229 | return $retval 230 | } 231 | 232 | restart() { 233 | configtest || return $? 234 | stop 235 | sleep 1 236 | start 237 | } 238 | 239 | reload() { 240 | configtest || return $? 241 | echo -n $"Reloading $prog: " 242 | killproc $nginx -HUP 243 | RETVAL=$? 244 | echo 245 | } 246 | 247 | force_reload() { 248 | restart 249 | } 250 | 251 | configtest() { 252 | $nginx -t -c $NGINX_CONF_FILE 253 | } 254 | 255 | rh_status() { 256 | status $prog 257 | } 258 | 259 | rh_status_q() { 260 | rh_status >/dev/null 2>&1 261 | } 262 | 263 | case "$1" in 264 | start) 265 | rh_status_q && exit 0 266 | $1 267 | ;; 268 | stop) 269 | rh_status_q || exit 0 270 | $1 271 | ;; 272 | restart|configtest) 273 | $1 274 | ;; 275 | reload) 276 | rh_status_q || exit 7 277 | $1 278 | ;; 279 | force-reload) 280 | force_reload 281 | ;; 282 | status) 283 | rh_status 284 | ;; 285 | condrestart|try-restart) 286 | rh_status_q || exit 0 287 | ;; 288 | *) 289 | echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}" 290 | exit 2 291 | esac 292 | # END 293 | 用/root/service-nginx.sh替换/etc/init.d/nginx 294 | 295 | mv /root/service-nginx.sh /etc/init.d/nginx 296 | 赋予可执行限权 297 | 298 | chmod 755 /etc/init.d/nginx 299 | 执行 300 | 301 | systemctl start nginx 302 | 源码方式安装nginx,自动化安装脚本 303 | #!/bin/bash 304 | 305 | # installation configuration 306 | NGINX_VERSION=1.12.2 307 | NGINX_SRC_PATH=/root 308 | NGINX_BIN_PATH=/usr/local/nginx 309 | 310 | # disable firewall 311 | systemctl stop firewalld 312 | setenforce 0 313 | 314 | # installation dependence 315 | yum install -y pcre-devel zlib-devel openssl-devel wget gcc 316 | 317 | # download nginx source package 318 | cd ${NGINX_SRC_PATH} 319 | wget http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz 320 | 321 | # unzip source package 322 | tar -xzvf nginx-${NGINX_VERSION}.tar.gz 323 | cd ./nginx-${NGINX_VERSION} 324 | 325 | # install nginx 326 | ./configure --prefix=${NGINX_BIN_PATH} --with-http_ssl_module 327 | make & make install 328 | 329 | # start nginx service 330 | cd ${NGINX_BIN_PATH}/sbin 331 | ./nginx 332 | 333 | # END 334 | -------------------------------------------------------------------------------- /linux/ubuntu/dpkg.md: -------------------------------------------------------------------------------- 1 | ## 2 | 常用 3 | 模糊查找文件 4 | dpkg -l | ps 文件 5 | 6 | 7 | dpkg是一个Debian的一个命令行工具,它可以用来安装、删除、构建和管理Debian的软件包。 8 | 下面是它的一些命令解释: 9 | 1)安装软件 10 | 命令行:dpkg -i <.deb file name> 11 | 示例:dpkg -i avg71flm_r28-1_i386.deb 12 | 2)安装一个目录下面所有的软件包 13 | 命令行:dpkg -R 14 | 示例:dpkg -R /usr/local/src 15 | 3)释放软件包,但是不进行配置 16 | 命令行:dpkg –unpack package_file 如果和-R一起使用,参数可以是一个目录 17 | 示例:dpkg –unpack avg71flm_r28-1_i386.deb 18 | 4)重新配置和释放软件包 19 | 命令行:dpkg –configure package_file 20 | 如果和-a一起使用,将配置所有没有配置的软件包 21 | 示例:dpkg –configure avg71flm_r28-1_i386.deb 22 | 5)删除软件包(保留其配置信息) 23 | 命令行:dpkg -r 24 | 示例:dpkg -r avg71flm 25 | 6)替代软件包的信息 26 | 命令行:dpkg –update-avail 27 | 7)合并软件包信息 28 | dpkg –merge-avail 29 | 8)从软件包里面读取软件的信息 30 | 命令行:dpkg -A package_file 31 | 9)删除一个包(包括配置信息) 32 | 命令行:dpkg -P 33 | 10)丢失所有的Uninstall的软件包信息 34 | 命令行:dpkg –forget-old-unavail 35 | 11)删除软件包的Avaliable信息 36 | 命令行:dpkg –clear-avail 37 | 12)查找只有部分安装的软件包信息 38 | 命令行:dpkg -C 39 | 13)比较同一个包的不同版本之间的差别 40 | 命令行:dpkg –compare-versions ver1 op ver2 41 | 14)显示帮助信息 42 | 命令行:dpkg –help 43 | 15)显示dpkg的Licence 44 | 命令行:dpkg –licence (or) dpkg –license 45 | 16)显示dpkg的版本号 46 | 命令行:dpkg –version 47 | 17)建立一个deb文件 48 | 命令行:dpkg -b direc×y [filename] 49 | 18)显示一个Deb文件的目录 50 | 命令行:dpkg -c filename 51 | 19)显示一个Deb的说明 52 | 命令行:dpkg -I filename [control-file] 53 | 20)搜索Deb包 54 | 命令行:dpkg -l package-name-pattern 55 | 示例:dpkg -I vim 56 | 21)显示所有已经安装的Deb包,同时显示版本号以及简短说明 57 | 命令行:dpkg -l 58 | 22)报告指定包的状态信息 59 | 命令行:dpkg -s package-name 60 | 示例:dpkg -s ssh 61 | 23)显示一个包安装到系统里面的文件目录信息 62 | 命令行:dpkg -L package-Name 63 | 示例:dpkg -L apache2 64 | 24)搜索指定包里面的文件(模糊查询) 65 | 命令行:dpkg -S filename-search-pattern 66 | 25)显示包的具体信息 67 | 命令行:dpkg -p package-name 68 | 示例:dpkg -p cacti 69 | 70 | 最后: 71 | 1、很多人抱怨用了Ubuntu或者Debian以后,不知道自己的软件给安装到什么地方了。其实可以用上面的dpkg -L命令来方便的查找。看来基础还是非常重要的,图形界面并不能够包办一切。 72 | 2、有的时候,用“新力得”下载完成以后,没有配置,系统会提示用“dpkg –configure -all”来配置,具体为什么也可以从上面看到。 73 | 3、现在Edgy里面可以看到Deb的信息。不过是在没有安装的时候(当然也可以重新打开那个包),可以看到Deb的文件路径。 74 | 4、如果想暂时删除程序以后再安装,第5项还是比较实用的,毕竟在Linux下面配置一个软件也并非容易。 -------------------------------------------------------------------------------- /linux/ubuntu/错误解决.md: -------------------------------------------------------------------------------- 1 | ##软件无法更新 2 | Err:11 https://pkg.jenkins.io/debian-stable binary/ Release.gpg 3 | 进入 4 | /etc/apt/sources.list.d/ 5 | 6 | 删除jenkins.list 7 | rm -rf jenkins.list 8 | rm -rf jenkins.list.save 9 | -------------------------------------------------------------------------------- /maven/Maven定制化打包后的包名(加入时间戳).md: -------------------------------------------------------------------------------- 1 | #Maven定制化打包后的包名 2 | 3 | ##默认Maven的包名为: 4 | 5 | 6 | ${project.artifactId}-${project.version} 7 | 8 | 9 | ##你可以定制为其它你想要的名字,如: 10 | 11 | 12 | ${project.artifactId}-${project.version}-company 13 | 14 | 15 | 16 | ${project.artifactId} 17 | 18 | 19 | ##加入时间戳: 20 | 21 | 22 | UTF-8 23 | yyyy-MM-dd_HH_mm 24 | 25 | 26 | 27 | ${project.artifactId}-${maven.build.timestamp} 28 | -------------------------------------------------------------------------------- /mq/RocketMQ 怎么保证的消息不丢失.md: -------------------------------------------------------------------------------- 1 | RocketMQ 怎么保证的消息不丢失? 2 | 3 | 面试官常常喜欢问:RocketMQ 怎么保证的消息不丢失? 4 | 5 | 再遇到这个问题,就可以把这篇文章甩给他了~ 6 | 7 | 一、消息发送过程 8 | 9 | 在这里插入图片描述 10 | 11 | 我们将消息流程分为如下三大部分,每一部分都有可能会丢失数据。 12 | 13 | 生产阶段:Producer通过网络将消息发送给Broker,这个发送可能会发生丢失,比如网络延迟不可达等。 14 | 15 | 存储阶段:Broker肯定是先把消息放到内存的,然后根据刷盘策略持久化到硬盘中,刚收到Producer的消息,再内存中了,但是异常宕机了,导致消息丢失。 16 | 17 | 消费阶段:消费失败了其实也是消息丢失的一种变体吧。 18 | 19 | 二、Producer生产阶段 20 | 21 | Producer通过网络将消息发送给Broker,这个发送可能会发生丢失,比如网络延迟不可达等。 22 | 23 | 1、解决方案一 24 | 25 | 1.1、说明 26 | 27 | 有三种send方法,同步发送、异步发送、单向发送。我们可以采取同步发送的方式进行发送消息,发消息的时候会同步阻塞等待broker返回的结果,如果没成功,则不会收到SendResult,这种是最可靠的。其次是异步发送,再回调方法里可以得知是否发送成功。单向发送(OneWay)是最不靠谱的一种发送方式,我们无法保证消息真正可达。 28 | 29 | 1.2、源码 30 | /** 31 | 32 | {@link org.apache.rocketmq.client.producer.DefaultMQProducer} 33 | */ 34 | // 同步发送 35 | public SendResult send(Message msg) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {} 36 | 37 | // 异步发送,sendCallback作为回调 38 | public void send(Message msg,SendCallback sendCallback) throws MQClientException, RemotingException, InterruptedException {} 39 | 40 | // 单向发送,不关心发送结果,最不靠谱 41 | public void sendOneway(Message msg) throws MQClientException, RemotingException, InterruptedException {} 42 | 43 | 2、解决方案二 44 | 45 | 2.1、说明 46 | 47 | 发送消息如果失败或者超时了,则会自动重试。默认是重试三次,可以根据api进行更改,比如改为10次: 48 | producer.setRetryTimesWhenSendFailed(10); 49 | 50 | 2.2、源码 51 | /** 52 | 53 | {@link org.apache.rocketmq.client.producer.DefaultMQProducer#sendDefaultImpl(Message, CommunicationMode, SendCallback, long)} 54 | */ 55 | // 自动重试次数,this.defaultMQProducer.getRetryTimesWhenSendFailed()默认为2,如果是同步发送,默认重试3次,否则重试1次 56 | int timesTotal = communicationMode == CommunicationMode.SYNC ? 1 + this.defaultMQProducer.getRetryTimesWhenSendFailed() : 1; 57 | int times = 0; 58 | for (; times < timesTotal; times++) { 59 | // 选择发送的消息queue 60 | MessageQueue mqSelected = this.selectOneMessageQueue(topicPublishInfo, lastBrokerName); 61 | if (mqSelected != null) { 62 | try { 63 | // 真正的发送逻辑,sendKernelImpl。 64 | sendResult = this.sendKernelImpl(msg, mq, communicationMode, sendCallback, topicPublishInfo, timeout - costTime); 65 | switch (communicationMode) { 66 | case ASYNC: 67 | return null; 68 | case ONEWAY: 69 | return null; 70 | case SYNC: 71 | // 如果发送失败了,则continue,意味着还会再次进入for,继续重试发送 72 | if (sendResult.getSendStatus() != SendStatus.SEND_OK) { 73 | if (this.defaultMQProducer.isRetryAnotherBrokerWhenNotStoreOK()) { 74 | continue; 75 | } 76 | } 77 | // 发送成功的话,将发送结果返回给调用者 78 | return sendResult; 79 | default: 80 | break; 81 | } 82 | } catch (RemotingException e) { 83 | continue; 84 | } catch (…) { 85 | continue; 86 | } 87 | } 88 | } 89 | 90 | 说明: 91 | 92 | 这里只是总结出核心的发送逻辑,并不是全代码。可以看出如下: 93 | 94 | 重试次数同步是1 + this.defaultMQProducer.getRetryTimesWhenSendFailed(),其他方式默认1次。 95 | 96 | this.defaultMQProducer.getRetryTimesWhenSendFailed()默认是2,我们可以手动设置producer.setRetryTimesWhenSendFailed(10); 97 | 98 | 调用sendKernelImpl真正的去发送消息 99 | 100 | 如果是sync同步发送,且发送失败了,则continue,意味着还会再次进入for,继续重试发送 101 | 102 | 发送成功的话,将发送结果返回给调用者 103 | 104 | 如果发送异常进入catch了,则continue继续下次重试。 105 | 106 | 3、解决方案三 107 | 108 | 3.1、说明 109 | 110 | 假设Broker宕机了,但是生产环境一般都是多M多S的,所以还会有其他master节点继续提供服务,这也不会影响到我们发送消息,我们消息依然可达。因为比如恰巧发送到broker的时候,broker宕机了,producer收到broker的响应发送失败了,这时候producer会自动重试,这时候宕机的broker就被踢下线了, 所以producer会换一台broker发送消息。 111 | 112 | 4、总结 113 | 114 | Producer怎么保证发送阶段消息可达? 115 | 116 | 失败会自动重试,即使重试N次也不行后,那客户端也会知道消息没成功,这也可以自己补偿等,不会盲目影响到主业务逻辑。再比如即使Broker挂了,那还有其他Broker再提供服务了,高可用,不影响。 117 | 118 | 总结为几个字就是:同步发送+自动重试机制+多个Master节点 119 | 120 | 三、Broker存储阶段 121 | 122 | Broker肯定是先把消息放到内存的,然后根据刷盘策略持久化到硬盘中,刚收到Producer的消息,再内存中了,但是异常宕机了,导致消息丢失。 123 | 124 | 1、解决方案一 125 | 126 | MQ持久化消息分为两种:同步刷盘和异步刷盘。默认情况是异步刷盘,Broker收到消息后会先存到cache里然后立马通知Producer说消息我收到且存储成功了,你可以继续你的业务逻辑了,然后Broker起个线程异步的去持久化到磁盘中,但是Broker还没持久化到磁盘就宕机的话,消息就丢失了。同步刷盘的话是收到消息存到cache后并不会通知Producer说消息已经ok了,而是会等到持久化到磁盘中后才会通知Producer说消息完事了。这也保障了消息不会丢失,但是性能不如异步高。看业务场景取舍。 127 | 128 | 修改刷盘策略为同步刷盘。默认情况下是异步刷盘的,如下配置 129 | 130 | 默认情况为 ASYNC_FLUSH,修改为同步刷盘:SYNC_FLUSH,实际场景看业务,同步刷盘效率肯定不如异步刷盘高。 131 | flushDiskType = SYNC_FLUSH 132 | 133 | 对应的Java配置类如下: 134 | package org.apache.rocketmq.store.config; 135 | 136 | public enum FlushDiskType { 137 | // 同步刷盘 138 | SYNC_FLUSH, 139 | // 异步刷盘(默认) 140 | ASYNC_FLUSH 141 | } 142 | 143 | 异步刷盘默认10s执行一次,源码如下: 144 | /* 145 | 146 | {@link org.apache.rocketmq.store.CommitLog#run()} 147 | */ 148 | while (!this.isStopped()) { 149 | try { 150 | // 等待10s 151 | this.waitForRunning(10); 152 | // 刷盘 153 | this.doCommit(); 154 | } catch (Exception e) { 155 | CommitLog.log.warn(this.getServiceName() + " service has exception. ", e); 156 | } 157 | } 158 | 159 | 2、解决方案二 160 | 161 | 集群部署,主从模式,高可用。 162 | 163 | 即使Broker设置了同步刷盘策略,但是Broker刷完盘后磁盘坏了,这会导致盘上的消息全TM丢了。但是如果即使是1主1从了,但是Master刷完盘后还没来得及同步给Slave就磁盘坏了,不也是GG吗?没错! 164 | 165 | 所以我们还可以配置不仅是等Master刷完盘就通知Producer,而是等Master和Slave都刷完盘后才去通知Producer说消息ok了。 166 | 167 | 默认为 ASYNC_MASTER 168 | brokerRole=SYNC_MASTER 169 | 170 | 3、总结 171 | 172 | 若想很严格的保证Broker存储消息阶段消息不丢失,则需要如下配置,但是性能肯定远差于默认配置。 173 | 174 | master 节点配置 175 | flushDiskType = SYNC_FLUSH 176 | brokerRole=SYNC_MASTER 177 | 178 | slave 节点配置 179 | brokerRole=slave 180 | flushDiskType = SYNC_FLUSH 181 | 182 | 上面这个配置含义是: 183 | 184 | Producer发消息到Broker后,Broker的Master节点先持久化到磁盘中,然后同步数据给Slave节点,Slave节点同步完且落盘完成后才会返回给Producer说消息ok了。 185 | 186 | 四、Consumer消费阶段 187 | 188 | 消费失败了其实也是消息丢失的一种变体。 189 | 190 | 1、解决方案一 191 | 192 | 消费者会先把消息拉取到本地,然后进行业务逻辑,业务逻辑完成后手动进行ack确认,这时候才会真正的代表消费完成。而不是说pull到本地后消息就算消费完了。举个例子 193 | consumer.registerMessageListener(new MessageListenerConcurrently() { 194 | @Override 195 | public ConsumeConcurrentlyStatus consumeMessage(List msgs, ConsumeConcurrentlyContext consumeConcurrentlyContext) { 196 | for (MessageExt msg : msgs) { 197 | String str = new String(msg.getBody()); 198 | System.out.println(str); 199 | } 200 | // ack,只有等上面一系列逻辑都处理完后,到这步CONSUME_SUCCESS才会通知broker说消息消费完成,如果上面发生异常没有走到这步ack,则消息还是未消费状态。而不是像比如redis的blpop,弹出一个数据后数据就从redis里消失了,并没有等我们业务逻辑执行完才弹出。 201 | return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; 202 | } 203 | }); 204 | 205 | 2、解决方案二 206 | 207 | 消息消费失败自动重试。如果消费消息失败了,没有进行ack确认,则会自动重试,重试策略和次数(默认15次)如下配置 208 | /** 209 | 210 | Broker可以配置的所有选项 211 | */ 212 | public class org.apache.rocketmq.store.config.MessageStoreConfig { 213 | private String messageDelayLevel = “1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h”; 214 | } 215 | 高质量编程视频:shangyepingtai.xin 216 | END -------------------------------------------------------------------------------- /mq/rocketmq-start-linux.md: -------------------------------------------------------------------------------- 1 | ##配置环境 2 | vim /etc/profile 3 | 增加 4 | export ROCKETMQ_HOME=/root/java/rocketmq-all-4.7.1-bin-release 5 | export NAMESRV_ADDR=localhost:9876 6 | 7 | ###使配置生效 8 | source /etc/profile 9 | 10 | 11 | ##启动 nameServer注册中心 12 | sh bin/mqnamesrv 13 | ###后台启动 14 | nohup sh bin/mqnamesrv & 15 | ###查看日志 16 | tail -f ~/logs/rocketmqlogs/namesrv.log 17 | 18 | 19 | 20 | ##启动 broker 21 | nohup sh bin/mqbroker -n localhost:9876 & 22 | ###查看日志 23 | tail -f ~/logs/rocketmqlogs/broker.log 24 | ###停止 25 | sh bin/mqshutdown namesrv 26 | sh bin/mqshutdown broker 27 | ###公网启动 28 | 在conf/broker.conf 中 加入 两行配置 29 | namesrvAddr = 你的公网IP:9876 30 | brokerIP1=你的公网IP 31 | nohup sh mqbroker -n localhost:9876 -c ../conf/broker.conf autoCreateTopicEnable=true & 32 | nohup sh bin/mqbroker -n localhost:9876 -c conf/broker.conf autoCreateTopicEnable=true & 33 | tail -f ~/logs/rocketmqlogs/broker.log 34 | 35 | ##创建topic 36 | bin/mqadmin updatetopic -n localhost:9876 -c DefaultCluster -t test_topic 37 | bin/mqadmin updatetopic -n localhost:9876 -c DefaultCluster -t app_topic 38 | 39 | ##查看topic 40 | bin/mqadmin topicList -n localhost:9876 -c DefaultCluster 41 | 42 | [docker安装rocketmq](../docker/mq/docker-rocketmq.md) 43 | 44 | 45 | -------------------------------------------------------------------------------- /tool/alibaba-tool.md: -------------------------------------------------------------------------------- 1 | 阿里程序员推荐的 15 款常用开发者工具 2 | 点击关注 👉 芋道源码 今天 3 | 点击上方“芋道源码”,选择“设为星标” 4 | 5 | 管她前浪,还是后浪? 6 | 7 | 能浪的浪,才是好浪! 8 | 9 | 每天 8:55 更新文章,每天掉亿点点头发... 10 | 11 | 源码精品专栏 12 | 13 | 14 | 原创 | Java 2020 超神之路,很肝~ 15 | 16 | 中文详细注释的开源项目 17 | 18 | RPC 框架 Dubbo 源码解析 19 | 20 | 网络应用框架 Netty 源码解析 21 | 22 | 消息中间件 RocketMQ 源码解析 23 | 24 | 数据库中间件 Sharding-JDBC 和 MyCAT 源码解析 25 | 26 | 作业调度中间件 Elastic-Job 源码解析 27 | 28 | 分布式事务中间件 TCC-Transaction 源码解析 29 | 30 | Eureka 和 Hystrix 源码解析 31 | 32 | Java 并发源码 33 | 34 | 来源:阿里巴巴中间件 35 | 36 | 一、Java 线上诊断工具 Arthas 37 | 二、IDE 插件 Cloud Toolkit 38 | 三、混沌实验注入工具 ChaosBlade 39 | 四、Java 代码规约扫描插件 40 | 五、应用实时监控工具 ARMS 41 | 六、静态开源站点搭建工具 Docsite 42 | 七、Android 平台上的秒级编译方案 Freeline 43 | 八、性能测试工具 PTS 44 | 九、云效开发者工具KT 45 | 十、架构可视化工具 AHAS 46 | 十一、数据处理工具 EasyExcel 47 | 十二、iOS 类工具 HandyJSON 48 | 十三、云上资源和应用部署工具 EDAS Serverless 49 | 十四、数据库连接池 Druid 50 | 十五、Java 工具集 Dragonwell 51 | 从人工到自动化,从重复到创新,技术演进的历程中,伴随着开发者工具类产品的发展。 52 | 53 | 阿里巴巴将自身在各类业务场景下的技术积淀,通过开源、云上实现或工具等形式对外开放,本文将精选了一些阿里巴巴的开发者工具,希望能帮助开发者们提高开发效率、更优雅的写代码。 54 | 55 | 由于开发者涉及的技术领域众多,笔者仅从自己熟悉的领域,以后端开发者的视角盘点平时可能用得到的工具。每个工具按照以下几点进行介绍: 56 | 57 | 1、工具名称和简介 2、使用场景 3、使用教程 4、获取方式 58 | 59 | 一、Java 线上诊断工具 Arthas 60 | Arthas 阿里巴巴2018年9月开源的一款Java线上诊断工具。 61 | 62 | 工具的使用场景: 63 | 64 | 1、这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception? 65 | 66 | 2、我改的代码为什么没有执行到?难道是我没 commit?分支搞错了? 67 | 68 | 3、遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗? 69 | 70 | 4、线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现! 71 | 72 | 5、是否有一个全局视角来查看系统的运行状况? 73 | 74 | 6、有什么办法可以监控到JVM的实时运行状态? 75 | 76 | Arthas支持JDK 6+,支持Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。 77 | 78 | 使用教程: 基础教程: 79 | 80 | https://alibaba.github.io/arthas/arthas-tutorials?language=cn&id=arthas-basics 81 | 82 | 进阶教程: 83 | 84 | https://alibaba.github.io/arthas/arthas-tutorials?language=cn&id=arthas-advanced 85 | 86 | 获取方式: (免费)开源地址: 87 | 88 | https://github.com/alibaba/arthas 89 | 90 | “推荐一个艿艿写的 6000+ Star 的 SpringBoot + SpringCloud + Dubbo 教程的仓库:https://github.com/YunaiV/SpringBoot-Labs 91 | 二、IDE 插件 Cloud Toolkit 92 | Cloud Toolkit 是一款 IDE 插件,可以帮助开发者更高效地开发、测试、诊断并部署应用。通过 Cloud Toolkit,开发者能够方便地将本地应用一键部署到任意机器(本地或云端),并内置 Arthas 诊断、高效执行终端命令和 SQL 等,提供 IntelliJ IDEA 版,Eclipse 版,PyCharm 版和 Maven 版。 93 | 94 | 工具的使用场景: 95 | 96 | 1、每次修改完代码后,是否正在经历反复地打包? 97 | 98 | 2、在 Maven 、Git 以及其他运维脚本和工具的之间频繁切换? 99 | 100 | 3、采用 SCP 工具上传?使用XShell或SecureCRT登录服务器?替换部署包?重启? 101 | 102 | 4、文件上传到服务器指定目录,在各种 FTP、SCP 工具之间频繁切换 ? 103 | 104 | 使用教程: 105 | 106 | IntelliJ IDEA版: 107 | 108 | https://help.aliyun.com/document_detail/98762.html 109 | 110 | Eclipse 版: 111 | 112 | https://help.aliyun.com/document_detail/29970.html 113 | 114 | PyCharm 版: 115 | 116 | https://help.aliyun.com/document_detail/112740.html 117 | 118 | Maven 版: 119 | 120 | https://help.aliyun.com/document_detail/108682.html 121 | 122 | 获取方式: (免费)工具地址: 123 | 124 | https://www.aliyun.com/product/cloudtoolkit 125 | 126 | “推荐一个艿艿写的 3000+ Star 的 SpringCloud Alibaba 电商开源项目的仓库:https://github.com/YunaiV/onemall 127 | 三、混沌实验注入工具 ChaosBlade 128 | ChaosBlade 是一款遵循混沌工程实验原理,提供丰富故障场景实现,帮助分布式系统提升容错性和可恢复性的混沌工程工具,可实现底层故障的注入,提供了延迟、异常、返回特定值、修改参数值、重复调用和try-catch 块异常等异常场景。 129 | 130 | 工具的使用场景: 131 | 132 | 1、微服务的容错能力不易衡量? 133 | 134 | 2、容器编排配置是否合理无法验证? 135 | 136 | 3、PaaS 层健壮性的测试工作无从入手? 137 | 138 | 使用教程: 139 | 140 | https://github.com/chaosblade-io/chaosblade/wiki/新手指南 141 | 142 | 获取方式: (免费)开源地址: 143 | 144 | https://github.com/chaosblade-io/chaosblade/wiki/新手指南 145 | 146 | 四、Java 代码规约扫描插件 147 | 该插件用于检测 Java 代码中存在的不规范的位置,并给予提示。规约插件是采用 Kotlin 语言开发。 148 | 149 | 使用教程: 150 | 151 | IDEA插件使用文档: 152 | 153 | https://github.com/alibaba/p3c/wiki/IDEA插件使用文档 154 | 155 | Eclipse插件使用文档: 156 | 157 | https://github.com/alibaba/p3c/wiki/Eclipse插件使用文档 158 | 159 | 获取方式: (免费)开源地址: 160 | 161 | https://github.com/alibaba/p3c 162 | 163 | 五、应用实时监控工具 ARMS 164 | ARMS 是一款 APM 类的监控工具,提供前端、应用、自定义监控 3 类监控选项,可快速构建实时的应用性能和业务监控能力。 165 | 166 | 工具的使用场景: 167 | 168 | 1、晚上10点收到37条报警信息,你却无从下手? 169 | 170 | 2、当我们发现问题的时候,客户/业务方已经发起投诉? 171 | 172 | 3、每个月花几十万买服务器,却无法保障用户体验? 173 | 174 | 使用教程: 175 | 176 | 前端监控接入: 177 | 178 | https://help.aliyun.com/documentdetail/106086.html 179 | 180 | 应用监控接入: 181 | 182 | https://help.aliyun.com/documentdetail/63796.html 183 | 184 | 自定义监控: 185 | 186 | https://help.aliyun.com/document_detail/47474.html 187 | 188 | 获取方式: (收费)工具地址: 189 | 190 | https://www.aliyun.com/product/arms 191 | 192 | 六、静态开源站点搭建工具 Docsite 193 | Docsite 一款集官网、文档、博客和社区为一体的静态开源站点的解决方案,具有简单易上手、上手不撒手的特质,同时支持 react 和静态渲染、PC端和移动端、支持中英文国际化、SEO、markdown文档、全局站点搜索、站点风格自定义、页面自定义等功能。 194 | 195 | 使用教程: 196 | 197 | https://docsite.js.org/zh-cn/docs/installation.html 198 | 199 | 获取方式: (免费)项目地址: 200 | 201 | https://github.com/txd-team/docsite 202 | 203 | 七、Android 平台上的秒级编译方案 Freeline 204 | Freeline 可以充分利用缓存文件,在几秒钟内迅速地对代码的改动进行编译并部署到设备上,有效地减少了日常开发中的大量重新编译与安装的耗时。Freeline 最快捷的使用方法就是直接安装 Android Studio 插件。 205 | 206 | 使用教程: 207 | 208 | https://github.com/alibaba/freeline/blob/master/README-zh.md 209 | 210 | 获取方式: (免费)项目地址: 211 | 212 | https://github.com/alibaba/freeline 213 | 214 | 八、性能测试工具 PTS 215 | PTS 可以模拟大量用户访问业务的场景,任务随时发起,免去搭建和维护成本,支持 JMeter 脚本转化为 PTS 压测,同样支持原生 JMeter 引擎进行压测。 216 | 217 | 使用教程: 218 | 219 | https://help.aliyun.com/document_detail/70290.html 220 | 221 | 获取方式: (收费)工具地址: 222 | 223 | https://www.aliyun.com/product/pts 224 | 225 | 九、云效开发者工具KT 226 | KT 可以简化在 Kubernetes 下进行联调测试的复杂度,提高基于Kubernetes的研发效率。 227 | 228 | 使用教程: 229 | 230 | https://yq.aliyun.com/articles/690519 231 | 232 | 获取方式: (免费)工具地址: 233 | 234 | https://yq.aliyun.com/download/3393 235 | 236 | 十、架构可视化工具 AHAS 237 | AHAS 为 K8s 等容器环境提供了架构可视化的功能,同时,具有故障注入式高可用能力评测和一键流控降级等功能,可以快速低成本的提升应用可用性。 238 | 239 | 工具的使用场景: 240 | 241 | 1、服务化改造过程中,想精确的了解资源实例的构成和交互情况,实现架构的可视化? 242 | 243 | 2、想引入真实的故障场景和演练模型? 244 | 245 | 3、低门槛获得流控、降级功能? 246 | 247 | 使用教程: 248 | 249 | https://help.aliyun.com/document_detail/90323.html 250 | 251 | 获取方式: (免费)工具地址: 252 | 253 | https://www.aliyun.com/product/ahas 254 | 255 | 十一、数据处理工具 EasyExcel 256 | EasyExcel 是一个用来对 Java 进行解析、生成Excel 的框架,它重写了 poi 对07版 Excel 的解析,原本一个3M的 Excel 用POI sax需要100M左右内存,EasyExcel可降低到 KB 级别,并且再大的excel也不会出现内存溢出的情况。03版依赖 POI 的 sax 模式。在上层做了模型转换的封装,让使用者更加简单方便。 257 | 258 | 使用教程: 259 | 260 | https://github.com/alibaba/easyexcel/blob/master/quickstart.md 261 | 262 | 获取方式: (开源) 263 | 264 | https://github.com/alibaba/easyexcel 265 | 266 | 十二、iOS 类工具 HandyJSON 267 | HandyJSON 是一个用于 Swift 语言中的JSON序列化/反序列化库。 268 | 269 | 与其他流行的Swift JSON库相比,HandyJSON 的特点是,它支持纯 Swift 类,使用也简单。它反序列化时(把 JSON 转换为Model)不要求 Model从 NSObject 继承(因为它不是基于 KVC 机制),也不要求你为 Model 定义一个 Mapping 函数。只要你定义好 Model 类,声明它服从 HandyJSON 协议,HandyJSON 就能自行以各个属性的属性名为Key,从JSON串中解析值。 270 | 271 | 使用教程: 272 | 273 | https://github.com/alibaba/HandyJSON/blob/master/README_cn.md 274 | 275 | 获取方式: (开源) 276 | 277 | https://github.com/alibaba/HandyJSON 278 | 279 | 十三、云上资源和应用部署工具 EDAS Serverless 280 | EDAS Serverless 一款基于 Kubernetes,面向应用和微服务的 Serverless 平台。用户无需管理和维护集群与服务器,即可通过镜像、WAR 包和JAR 包,快速创建原生支持 Kubernetes 的容器应用,同时支持 Spring Cloud 和 Dubbo 等主流微服务框架。 281 | 282 | 使用教程: 283 | 284 | https://help.aliyun.com/document_detail/102048.html 285 | 286 | 获取方式: (公测期间免费) 287 | 288 | https://help.aliyun.com/document_detail/97792.html 289 | 290 | 十四、数据库连接池 Druid 291 | Druid 是 Java 语言下的数据库连接池,它能够提供强大的监控和扩展功能。 292 | 293 | 使用教程: https://github.com/alibaba/druid/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98 294 | 295 | 获取方式: (开源) 296 | 297 | http://central.maven.org/maven2/com/alibaba/druid/ 298 | 299 | 十五、Java 工具集 Dragonwell 300 | Alibaba Dragonwell 是阿里巴巴内部OpenJDK定制版AJDK的开源版本, AJDK为在线电商,金融,物流做了结合业务场景的优化,运行在超大规模的,100,000+ 服务器的阿里巴巴数据中心。Alibaba Dragonwell与Java SE标准兼容,目前仅支持 Linux/x86_64平台。 301 | 302 | 使用教程: https://github.com/alibaba/dragonwell8/wiki/%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4Dragonwell8%E7%94%A8%E6%88%B7%E6%8C%87%E5%8D%97 303 | 304 | 获取方式: (开源) 305 | 306 | https://github.com/alibaba/dragonwell8 -------------------------------------------------------------------------------- /持续集成/git/Git 中 SSH key 生成步骤.md: -------------------------------------------------------------------------------- 1 | #Git 中 SSH key 生成步骤 2 | 由于本地Git仓库和GitHub仓库之间的传输是通过SSH加密的,所以必须要让github仓库认证你SSH key,在此之前,必须要生成SSH key。 3 | linux 4 | ssh-keygen -t rsa -C "your_email@example.com" 5 | ssh-keygen -t rsa -C "chenye@futve.com" 6 | 7 | 8 | 9 | 10 | window 11 | 第1步:创建SSH Key。在windows下查看[c盘->用户->自己的用户名->.ssh]下是否有id_rsa、id_rsa.pub文件,如果没有需要手动生成。 12 | 打开git bash,在控制台中输入以下命令。 13 | 14 | 1 15 | $ ssh-keygen -t rsa -C "youremail@example.com" 16 | 密钥类型可以用 -t 选项指定。如果没有指定则默认生成用于SSH-2的RSA密钥。这里使用的是rsa。 17 | 18 | 同时在密钥中有一个注释字段,用-C来指定所指定的注释,可以方便用户标识这个密钥,指出密钥的用途或其他有用的信息。所以在这里输入自己的邮箱或者其他都行。 19 | 20 | 输入完毕后程序同时要求输入一个密语字符串(passphrase),空表示没有密语。接着会让输入2次口令(password),空表示没有口令。3次回车即可完成当前步骤,此时[c盘>用户>自己的用户名>.ssh]目录下已经生成好了。 21 | 22 | 23 | 24 | 第2步:登录github。打开setting->SSH keys,点击右上角 New SSH key,把生成好的公钥id_rsa.pub放进 key输入框中,再为当前的key起一个title来区分每个key。 -------------------------------------------------------------------------------- /持续集成/git/gitlab令牌.md: -------------------------------------------------------------------------------- 1 | #gitlab个人令牌 2 | x-zysLJeYn-HSVG_q36q 3 | YsC4iDsYJ-FA2Qz-uZ5t 4 | https://www.cnblogs.com/cainiaotest/p/11790945.html -------------------------------------------------------------------------------- /持续集成/git/gitlab重置密码.md: -------------------------------------------------------------------------------- 1 | #进入控制台 2 | gitlab-rails console production 3 | #查找id为1的用户 4 | u= User.where(id: 1).first 5 | #重置密码 6 | u.password='123456789' 7 | #保存生效 8 | u.save! 9 | 10 | #查找用户 11 | u = User.where(email: 'admin@example.com').first -------------------------------------------------------------------------------- /持续集成/git/git分支命令.md: -------------------------------------------------------------------------------- 1 | git 分支查看与切换 2 | git 分支查看与切换 3 | 4 | 5 | # 1.查看所有分支 6 | > git branch -a 7 |    8 | 9 | # 2.查看当前使用分支(结果列表中前面标*号的表示当前使用分支) 10 | > git branch 11 | 12 | # 3.切换分支 13 | > git checkout 分支名 -------------------------------------------------------------------------------- /持续集成/git/git记住密码.md: -------------------------------------------------------------------------------- 1 | git config --global credential.helper store 2 | 之后再次执行git push 或者git pull这时候还需要输入用户名和密码 3 | 4 | 下次就不需要了 -------------------------------------------------------------------------------- /持续集成/gitea.md: -------------------------------------------------------------------------------- 1 | ##官网 2 | https://gitea.com/ 3 | 4 | [docker-gitea](../docker/git/docker-gitea.md) -------------------------------------------------------------------------------- /持续集成/jenkins/build-front.md: -------------------------------------------------------------------------------- 1 | date 2 | cd /root/label-front/mark 3 | git pull 4 | cnpm install 5 | npm run build -------------------------------------------------------------------------------- /持续集成/jenkins/jenkins-docker安装.md: -------------------------------------------------------------------------------- 1 | ##拉取镜像 2 | ``` 3 | docker pull adoptopenjdk/openjdk11-openj9 4 | ``` 5 | 6 | ##部署 7 | ``` 8 | docker run -d -p 7088:7088 --restart=always -v /root/java/jenkins:/chenye --name jenkins2 adoptopenjdk/openjdk11-openj9 java -jar /chenye/jenkins2.253.war --httpPort=7088 9 | ``` 10 | 11 | ##限制容器内存cpu 12 | ``` 13 | docker container update example --cpus="1" --memory="1g" --memory-swap="-1" 14 | ``` 15 | 限制最多使用一个cpu,最多用一g内存 16 | 17 | 18 | ##查看 密码 19 | cat /root/.jenkins/secrets/initialAdminPassword 20 | 21 | ##官网 22 | https://www.jenkins.io/ 23 | ##下载地址 24 | 25 | https://mirrors.aliyun.com/jenkins/ 26 | https://mirrors.aliyun.com/jenkins/war/ 27 | 28 | java -jar jenkins.war --httpPort=9090 29 | 30 | nohup java -jar jenkins.war --httpPort=9090 & 31 | -------------------------------------------------------------------------------- /持续集成/jenkins/jenkins安装.md: -------------------------------------------------------------------------------- 1 | ##官网 2 | https://www.jenkins.io/ 3 | 4 | ##下载地址 5 | https://mirrors.aliyun.com/jenkins/ 6 | https://mirrors.aliyun.com/jenkins/war/ 7 | 8 | java -jar jenkins.war --httpPort=9090 9 | 10 | nohup java -jar jenkins.war --httpPort=9090 & 11 | -------------------------------------------------------------------------------- /持续集成/jenkins/shell 到达一定数量文件自动删除最久时间文件.md: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | shell 到达一定数量文件自动删除最久时间文件.md 3 | 4 | #rm_file>14day 5 | 6 | ReservedNum=4 #保留文件数量 7 | rm_file_dir='/home/sean/sean/rmfile' #需要删除文件的路径 8 | 9 | cd $rm_file_dir #进入文件夹 10 | RootDir=$(cd $(dirname $0); pwd) #当前文件路径 11 | FileNum=$(ls -l | grep ^- | wc -l) #查找文件数量 12 | OldFile=$(ls -rt *.dmp|head -1) #找出dmp最早文件 13 | echo OldFile 14 | if [ $RootDir == $rm_file_dir ];then #判断所在目录是否正确 15 | echo $RootDir 16 | echo $rm_file_dir 17 | while (($FileNum>$ReservedNum)) #文件数超过设置变量才执行 18 | do 19 | echo "Delete File:"$RootDir'/'$OldFile #打印要删除的文件名称 20 | rm -f $RootDir'/'$OldFile #删除文件 21 | let "FileNum--" #变量自减操作 22 | OldFile=$(ls -rt *.dmp|head -1) #更新dmp最早文件 23 | done 24 | else 25 | echo "error file path " #所在目录不对打印出路径错误 26 | fi 27 | -------------------------------------------------------------------------------- /持续集成/jenkins/shell以日期重命名.md: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #shell以日期重命名.md 3 | find ./log -name "*.jar" | while read file 4 | do 5 | DATE=$(date +%Y%m%d_%H%M%S_%N) 6 | mv $file ./temp_log/${DATE}.log 7 | done 8 | 9 | #第一行语句:找出当前log目录下的所有以*.log为后缀的文件。 10 | #第三行语句:把当前时间变量导入DATE变量(产生一个随机数)。 11 | #第四行语句:移动并重命名查找到的文件。 -------------------------------------------------------------------------------- /持续集成/jenkins/ubuntu-install-jenkins.md: -------------------------------------------------------------------------------- 1 | #在Ubuntu上安装Jenkins 2 | #https://wiki.jenkins-ci.org/display/JENKINS/Installing+Jenkins+on+Ubuntu 3 | 先决条件 4 | 安装Java SDK 5 | 6 | sudo apt-get install openjdk-8-jdk 7 | 8 | #第1步 - 安装Jenkins 9 | 包含在默认Ubuntu软件包中的Jenkins版本往往落后于项目本身的最新版本。 为了利用最新的修复和功能,我们将使用项目维护的软件包来安装Jenkins。 10 | 11 | 首先,我们将存储库密钥添加到系统。 12 | 13 | wget -q -O - https://pkg.jenkins.io/debian/jenkins-ci.org.key | sudo apt-key add - 14 | 添加密钥后,系统将返回OK 。 接下来,我们将Debian包存储库地址附加到服务器的sources.list : 15 | 16 | echo deb http://pkg.jenkins.io/debian-stable binary/ | sudo tee /etc/apt/sources.list.d/jenkins.list 17 | 当这两个都到位时,我们将运行update ,以便apt-get将使用新的存储库: 18 | 19 | sudo apt-get update 20 | sudo apt-get install jenkins 21 | 指定早期版本可以安装 22 | 23 | sudo apt-get install jenkins=2.138.1 24 | 如果太慢的话 可以去官网下载后 再安装 25 | 26 | 27 | 28 | #第2步 - 开始Jenkins 29 | 使用systemctl我们将启动Jenkins: 30 | 31 | sudo systemctl start jenkins 32 | #我们将使用其status命令来验证它是否成功启动 33 | sudo systemctl status jenkins 34 | #第3步 - 开机启动 35 | sudo systemctl enable jenkins 36 | -------------------------------------------------------------------------------- /持续集成/jenkins/webhooks配置.md: -------------------------------------------------------------------------------- 1 | https://www.cnblogs.com/saysmy/p/8806975.html 2 | https://www.jianshu.com/p/9d7615e2ea50 3 | 4 | 5 | gitlab的webhooks url 是根据jenkins构建权限连接设置的,如果必须登录才能构建就必须获取jenkins的用户名及token,可以在jenkins用户-设置里面查看到 ,url格式 6 | http://:@/ 7 | 8 | 9 | 8880 10 | http://chenye:1130bd60108173d7d1945e2cb64582c5d1@39.97.250.105:8880/gitee-project/test-front-105 11 | f5238183b34355e66958e3cafbb8890a 12 | 13 | 14 | http://test:11fa046bfafaeafb15ccc26f8d7ab8a6fb@39.97.250.105:8880/project/test-service-105 15 | 9e26bf94f39075a7d191b96648965384 -------------------------------------------------------------------------------- /持续集成/jenkins/使用shell脚本删除30天以前的文件.md: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | location=/root/rm 3 | find $location -mtime +30 -print | xargs rm -rf //-mtime是距离上一次修改时间 -print是只显示文件 xargs是获取find查找的结果在通过rm命令删除 -------------------------------------------------------------------------------- /版本控制器/git/git同时提交到2个仓库gitee.github.md: -------------------------------------------------------------------------------- 1 | 使用git clone url导出项目后、 2 | 修改 .git/config文件 3 | 4 | 5 | [core] 6 | repositoryformatversion = 0 7 | filemode = false 8 | bare = false 9 | logallrefupdates = true 10 | symlinks = false 11 | ignorecase = true 12 | [submodule] 13 | active = . 14 | [remote "origin"] 15 | url = https://gitee.com/stylesmile/snow.git 16 | fetch = +refs/heads/*:refs/remotes/origin/* 17 | url = https://github.com/stylesmile/snow.git 18 | 19 | [branch "master"] 20 | remote = origin 21 | merge = refs/heads/master 22 | 23 | [remote "github"] 24 | url = https://github.com/stylesmile/snow.git 25 | fetch = +refs/heads/*:refs/remotes/gitee/* 26 | tagopt = --no-tags -------------------------------------------------------------------------------- /问题排查/JAVA 线上故障排查完整套路,从 CPU、磁盘、内存、网络、GC 一条龙.md: -------------------------------------------------------------------------------- 1 | CPU 2 | 磁盘 3 | 内存 4 | GC问题 5 | 网络 6 | 线上故障主要会包括cpu、磁盘、内存以及网络问题,而大多数故障可能会包含不止一个层面的问题,所以进行排查时候尽量四个方面依次排查一遍。 7 | 同时例如jstack、jmap等工具也是不囿于一个方面的问题的,基本上出问题就是df、free、top 三连,然后依次jstack、jmap伺候,具体问题具体分析即可。 8 | CPU 9 | 10 | 一般来讲我们首先会排查cpu方面的问题。cpu异常往往还是比较好定位的。原因包括业务逻辑问题(死循环)、频繁gc以及上下文切换过多。而最常见的往往是业务逻辑(或者框架逻辑)导致的,可以使用jstack来分析对应的堆栈情况。 11 | 使用jstack分析cpu问题 12 | 我们先用ps命令找到对应进程的pid(如果你有好几个目标进程,可以先用top看一下哪个占用比较高)。 13 | 接着用top -H -p pid来找到cpu使用率比较高的一些线程 14 | 15 | 然后将占用最高的pid转换为16进制printf '%x\n' pid得到nid 16 | 17 | 接着直接在jstack中找到相应的堆栈信息jstack pid |grep 'nid' -C5 –color 18 | 19 | 可以看到我们已经找到了nid为0x42的堆栈信息,接着只要仔细分析一番即可。 20 | 当然更常见的是我们对整个jstack文件进行分析,通常我们会比较关注WAITING和TIMED_WAITING的部分,BLOCKED就不用说了。我们可以使用命令cat jstack.log | grep "java.lang.Thread.State" | sort -nr | uniq -c来对jstack的状态有一个整体的把握,如果WAITING之类的特别多,那么多半是有问题啦。 21 | 22 | 频繁gc 23 | 当然我们还是会使用jstack来分析问题,但有时候我们可以先确定下gc是不是太频繁,使用jstat -gc pid 1000命令来对gc分代变化情况进行观察,1000表示采样间隔(ms),S0C/S1C、S0U/S1U、EC/EU、OC/OU、MC/MU分别代表两个Survivor区、Eden区、老年代、元数据区的容量和使用量。YGC/YGT、FGC/FGCT、GCT则代表YoungGc、FullGc的耗时和次数以及总耗时。如果看到gc比较频繁,再针对gc方面做进一步分析。 24 | 25 | 上下文切换 26 | 针对频繁上下文问题,我们可以使用vmstat命令来进行查看 27 | 28 | cs(context switch)一列则代表了上下文切换的次数。 29 | 如果我们希望对特定的pid进行监控那么可以使用 pidstat -w pid命令,cswch和nvcswch表示自愿及非自愿切换。 30 | 31 | 磁盘 32 | 33 | 磁盘问题和cpu一样是属于比较基础的。首先是磁盘空间方面,我们直接使用df -hl来查看文件系统状态 34 | 35 | 更多时候,磁盘问题还是性能上的问题。我们可以通过iostatiostat -d -k -x来进行分析 36 | 37 | 最后一列%util可以看到每块磁盘写入的程度,而rrqpm/s以及wrqm/s分别表示读写速度,一般就能帮助定位到具体哪块磁盘出现问题了。 38 | 另外我们还需要知道是哪个进程在进行读写,一般来说开发自己心里有数,或者用iotop命令来进行定位文件读写的来源。 39 | 40 | 不过这边拿到的是tid,我们要转换成pid,可以通过readlink来找到pidreadlink -f /proc/*/task/tid/../..。 41 | 42 | 找到pid之后就可以看这个进程具体的读写情况cat /proc/pid/io 43 | 44 | 我们还可以通过lsof命令来确定具体的文件读写情况lsof -p pid 45 | 46 | 内存 47 | 48 | 内存问题排查起来相对比CPU麻烦一些,场景也比较多。主要包括OOM、GC问题和堆外内存。一般来讲,我们会先用free命令先来检查一发内存的各种情况。 49 | 50 | 堆内内存 51 | 内存问题大多还都是堆内内存问题。表象上主要分为OOM和StackOverflow。 52 | OOM 53 | JMV中的内存不足,OOM大致可以分为以下几种: 54 | Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread 55 | 这个意思是没有足够的内存空间给线程分配java栈,基本上还是线程池代码写的有问题,比如说忘记shutdown,所以说应该首先从代码层面来寻找问题,使用jstack或者jmap。如果一切都正常,JVM方面可以通过指定Xss来减少单个thread stack的大小。 56 | 另外也可以在系统层面,可以通过修改/etc/security/limits.confnofile和nproc来增大os对线程的限制 57 | 58 | Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 59 | 这个意思是堆的内存占用已经达到-Xmx设置的最大值,应该是最常见的OOM错误了。解决思路仍然是先应该在代码中找,怀疑存在内存泄漏,通过jstack和jmap去定位问题。如果说一切都正常,才需要通过调整Xmx的值来扩大内存。 60 | Caused by: java.lang.OutOfMemoryError: Meta space 61 | 这个意思是元数据区的内存占用已经达到XX:MaxMetaspaceSize设置的最大值,排查思路和上面的一致,参数方面可以通过XX:MaxPermSize来进行调整(这里就不说1.8以前的永久代了)。 62 | Stack Overflow 63 | 栈内存溢出,这个大家见到也比较多。 64 | Exception in thread "main" java.lang.StackOverflowError 65 | 表示线程栈需要的内存大于Xss值,同样也是先进行排查,参数方面通过Xss来调整,但调整的太大可能又会引起OOM。 66 | 使用JMAP定位代码内存泄漏 67 | 上述关于OOM和StackOverflow的代码排查方面,我们一般使用JMAPjmap -dump:format=b,file=filename pid来导出dump文件 68 | 69 | 通过mat(Eclipse Memory Analysis Tools)导入dump文件进行分析,内存泄漏问题一般我们直接选Leak Suspects即可,mat给出了内存泄漏的建议。另外也可以选择Top Consumers来查看最大对象报告。和线程相关的问题可以选择thread overview进行分析。除此之外就是选择Histogram类概览来自己慢慢分析,大家可以搜搜mat的相关教程。 70 | 71 | 日常开发中,代码产生内存泄漏是比较常见的事,并且比较隐蔽,需要开发者更加关注细节。比如说每次请求都new对象,导致大量重复创建对象;进行文件流操作但未正确关闭;手动不当触发gc;ByteBuffer缓存分配不合理等都会造成代码OOM。 72 | 另一方面,我们可以在启动参数中指定-XX:+HeapDumpOnOutOfMemoryError来保存OOM时的dump文件。 73 | 搜索Java知音,回复“后端面试”,送你一份面试宝典.pdf 74 | gc问题和线程 75 | gc问题除了影响cpu也会影响内存,排查思路也是一致的。一般先使用jstat来查看分代变化情况,比如youngGC或者fullGC次数是不是太多呀;EU、OU等指标增长是不是异常呀等。 76 | 线程的话太多而且不被及时gc也会引发oom,大部分就是之前说的unable to create new native thread。除了jstack细细分析dump文件外,我们一般先会看下总体线程,通过pstreee -p pid |wc -l。 77 | 78 | 或者直接通过查看/proc/pid/task的数量即为线程数量。 79 | 80 | 堆外内存 81 | 如果碰到堆外内存溢出,那可真是太不幸了。首先堆外内存溢出表现就是物理常驻内存增长快,报错的话视使用方式都不确定,如果由于使用Netty导致的,那错误日志里可能会出现OutOfDirectMemoryError错误,如果直接是DirectByteBuffer,那会报OutOfMemoryError: Direct buffer memory。 82 | 堆外内存溢出往往是和NIO的使用相关,一般我们先通过pmap来查看下进程占用的内存情况pmap -x pid | sort -rn -k3 | head -30,这段意思是查看对应pid倒序前30大的内存段。这边可以再一段时间后再跑一次命令看看内存增长情况,或者和正常机器比较可疑的内存段在哪里。 83 | 84 | 我们如果确定有可疑的内存端,需要通过gdb来分析gdb --batch --pid {pid} -ex "dump memory filename.dump {内存起始地址} {内存起始地址+内存块大小}" 85 | 86 | 获取dump文件后可用heaxdump进行查看hexdump -C filename | less,不过大多数看到的都是二进制乱码。 87 | NMT是Java7U40引入的HotSpot新特性,配合jcmd命令我们就可以看到具体内存组成了。需要在启动参数中加入 -XX:NativeMemoryTracking=summary 或者 -XX:NativeMemoryTracking=detail,会有略微性能损耗。 88 | 一般对于堆外内存缓慢增长直到爆炸的情况来说,可以先设一个基线jcmd pid VM.native_memory baseline。 89 | 90 | 然后等放一段时间后再去看看内存增长的情况,通过jcmd pid VM.native_memory detail.diff(summary.diff)做一下summary或者detail级别的diff。 91 | 92 | 93 | 可以看到jcmd分析出来的内存十分详细,包括堆内、线程以及gc(所以上述其他内存异常其实都可以用nmt来分析),这边堆外内存我们重点关注Internal的内存增长,如果增长十分明显的话那就是有问题了。 94 | detail级别的话还会有具体内存段的增长情况,如下图。 95 | 96 | 此外在系统层面,我们还可以使用strace命令来监控内存分配 strace -f -e "brk,mmap,munmap" -p pid 97 | 这边内存分配信息主要包括了pid和内存地址。 98 | 99 | 不过其实上面那些操作也很难定位到具体的问题点,关键还是要看错误日志栈,找到可疑的对象,搞清楚它的回收机制,然后去分析对应的对象。比如DirectByteBuffer分配内存的话,是需要full GC或者手动system.gc来进行回收的(所以最好不要使用-XX:+DisableExplicitGC)。 100 | 那么其实我们可以跟踪一下DirectByteBuffer对象的内存情况,通过jmap -histo:live pid手动触发fullGC来看看堆外内存有没有被回收。如果被回收了,那么大概率是堆外内存本身分配的太小了,通过-XX:MaxDirectMemorySize进行调整。如果没有什么变化,那就要使用jmap去分析那些不能被gc的对象,以及和DirectByteBuffer之间的引用关系了。 101 | 搜索Java知音,回复“后端面试”,送你一份面试宝典.pdf 102 | GC问题 103 | 104 | 堆内内存泄漏总是和GC异常相伴。不过GC问题不只是和内存问题相关,还有可能引起CPU负载、网络问题等系列并发症,只是相对来说和内存联系紧密些,所以我们在此单独总结一下GC相关问题。 105 | 我们在cpu章介绍了使用jstat来获取当前GC分代变化信息。而更多时候,我们是通过GC日志来排查问题的,在启动参数中加上-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps来开启GC日志。 106 | 常见的Young GC、Full GC日志含义在此就不做赘述了。 107 | 针对gc日志,我们就能大致推断出youngGC与fullGC是否过于频繁或者耗时过长,从而对症下药。我们下面将对G1垃圾收集器来做分析,这边也建议大家使用G1-XX:+UseG1GC。 108 | youngGC过频繁 109 | youngGC频繁一般是短周期小对象较多,先考虑是不是Eden区/新生代设置的太小了,看能否通过调整-Xmn、-XX:SurvivorRatio等参数设置来解决问题。如果参数正常,但是young gc频率还是太高,就需要使用Jmap和MAT对dump文件进行进一步排查了。 110 | youngGC耗时过长 111 | 耗时过长问题就要看GC日志里耗时耗在哪一块了。以G1日志为例,可以关注Root Scanning、Object Copy、Ref Proc等阶段。Ref Proc耗时长,就要注意引用相关的对象。 112 | Root Scanning耗时长,就要注意线程数、跨代引用。Object Copy则需要关注对象生存周期。而且耗时分析它需要横向比较,就是和其他项目或者正常时间段的耗时比较。比如说图中的Root Scanning和正常时间段比增长较多,那就是起的线程太多了。 113 | 114 | 触发fullGC 115 | G1中更多的还是mixedGC,但mixedGC可以和youngGC思路一样去排查。触发fullGC了一般都会有问题,G1会退化使用Serial收集器来完成垃圾的清理工作,暂停时长达到秒级别,可以说是半跪了。 116 | fullGC的原因可能包括以下这些,以及参数调整方面的一些思路: 117 | 并发阶段失败:在并发标记阶段,MixGC之前老年代就被填满了,那么这时候G1就会放弃标记周期。这种情况,可能就需要增加堆大小,或者调整并发标记线程数-XX:ConcGCThreads。 118 | 晋升失败:在GC的时候没有足够的内存供存活/晋升对象使用,所以触发了Full GC。这时候可以通过-XX:G1ReservePercent来增加预留内存百分比,减少-XX:InitiatingHeapOccupancyPercent来提前启动标记,-XX:ConcGCThreads来增加标记线程数也是可以的。 119 | 大对象分配失败:大对象找不到合适的region空间进行分配,就会进行fullGC,这种情况下可以增大内存或者增大-XX:G1HeapRegionSize。 120 | 程序主动执行System.gc():不要随便写就对了。 121 | 另外,我们可以在启动参数中配置-XX:HeapDumpPath=/xxx/dump.hprof来dump fullGC相关的文件,并通过jinfo来进行gc前后的dump 122 | jinfo -flag +HeapDumpBeforeFullGC pid 123 | jinfo -flag +HeapDumpAfterFullGC pid 124 | 这样得到2份dump文件,对比后主要关注被gc掉的问题对象来定位问题。 125 | 搜索Java知音,回复“后端面试”,送你一份面试宝典.pdf 126 | 网络 127 | 128 | 涉及到网络层面的问题一般都比较复杂,场景多,定位难,成为了大多数开发的噩梦,应该是最复杂的了。这里会举一些例子,并从tcp层、应用层以及工具的使用等方面进行阐述。 129 | 超时 130 | 超时错误大部分处在应用层面,所以这块着重理解概念。超时大体可以分为连接超时和读写超时,某些使用连接池的客户端框架还会存在获取连接超时和空闲连接清理超时。 131 | 读写超时。readTimeout/writeTimeout,有些框架叫做so_timeout或者socketTimeout,均指的是数据读写超时。注意这边的超时大部分是指逻辑上的超时。soa的超时指的也是读超时。读写超时一般都只针对客户端设置。 132 | 连接超时。connectionTimeout,客户端通常指与服务端建立连接的最大时间。服务端这边connectionTimeout就有些五花八门了,jetty中表示空闲连接清理时间,tomcat则表示连接维持的最大时间。 133 | 其他。包括连接获取超时connectionAcquireTimeout和空闲连接清理超时idleConnectionTimeout。多用于使用连接池或队列的客户端或服务端框架。 134 | 我们在设置各种超时时间中,需要确认的是尽量保持客户端的超时小于服务端的超时,以保证连接正常结束。 135 | 在实际开发中,我们关心最多的应该是接口的读写超时了。 136 | 如何设置合理的接口超时是一个问题。如果接口超时设置的过长,那么有可能会过多地占用服务端的tcp连接。而如果接口设置的过短,那么接口超时就会非常频繁。 137 | 服务端接口明明rt降低,但客户端仍然一直超时又是另一个问题。这个问题其实很简单,客户端到服务端的链路包括网络传输、排队以及服务处理等,每一个环节都可能是耗时的原因。 138 | TCP队列溢出 139 | tcp队列溢出是个相对底层的错误,它可能会造成超时、rst等更表层的错误。因此错误也更隐蔽,所以我们单独说一说。 140 | 141 | 如上图所示,这里有两个队列:syns queue(半连接队列)、accept queue(全连接队列)。三次握手,在server收到client的syn后,把消息放到syns queue,回复syn+ack给client,server收到client的ack,如果这时accept queue没满,那就从syns queue拿出暂存的信息放入accept queue中,否则按tcp_abort_on_overflow指示的执行。 142 | tcp_abort_on_overflow 0表示如果三次握手第三步的时候accept queue满了那么server扔掉client发过来的ack。tcp_abort_on_overflow 1则表示第三步的时候如果全连接队列满了,server发送一个rst包给client,表示废掉这个握手过程和这个连接,意味着日志里可能会有很多connection reset / connection reset by peer。 143 | 那么在实际开发中,我们怎么能快速定位到tcp队列溢出呢? 144 | netstat命令,执行netstat -s | egrep "listen|LISTEN" 145 | 146 | 如上图所示,overflowed表示全连接队列溢出的次数,sockets dropped表示半连接队列溢出的次数。 147 | ss命令,执行ss -lnt 148 | 149 | 上面看到Send-Q 表示第三列的listen端口上的全连接队列最大为5,第一列Recv-Q为全连接队列当前使用了多少。 150 | 接着我们看看怎么设置全连接、半连接队列大小吧: 151 | 全连接队列的大小取决于min(backlog, somaxconn)。backlog是在socket创建的时候传入的,somaxconn是一个os级别的系统参数。而半连接队列的大小取决于max(64, /proc/sys/net/ipv4/tcp_max_syn_backlog)。 152 | 在日常开发中,我们往往使用servlet容器作为服务端,所以我们有时候也需要关注容器的连接队列大小。在tomcat中backlog叫做acceptCount,在jetty里面则是acceptQueueSize。 153 | RST异常 154 | RST包表示连接重置,用于关闭一些无用的连接,通常表示异常关闭,区别于四次挥手。 155 | 在实际开发中,我们往往会看到connection reset / connection reset by peer错误,这种情况就是RST包导致的。 156 | 端口不存在 157 | 如果像不存在的端口发出建立连接SYN请求,那么服务端发现自己并没有这个端口则会直接返回一个RST报文,用于中断连接。 158 | 主动代替FIN终止连接 159 | 一般来说,正常的连接关闭都是需要通过FIN报文实现,然而我们也可以用RST报文来代替FIN,表示直接终止连接。实际开发中,可设置SO_LINGER数值来控制,这种往往是故意的,来跳过TIMED_WAIT,提供交互效率,不闲就慎用。 160 | 客户端或服务端有一边发生了异常,该方向对端发送RST以告知关闭连接 161 | 我们上面讲的tcp队列溢出发送RST包其实也是属于这一种。这种往往是由于某些原因,一方无法再能正常处理请求连接了(比如程序崩了,队列满了),从而告知另一方关闭连接。 162 | 接收到的TCP报文不在已知的TCP连接内 163 | 比如,一方机器由于网络实在太差TCP报文失踪了,另一方关闭了该连接,然后过了许久收到了之前失踪的TCP报文,但由于对应的TCP连接已不存在,那么会直接发一个RST包以便开启新的连接。 164 | 一方长期未收到另一方的确认报文,在一定时间或重传次数后发出RST报文 165 | 这种大多也和网络环境相关了,网络环境差可能会导致更多的RST报文。 166 | 之前说过RST报文多会导致程序报错,在一个已关闭的连接上读操作会报connection reset,而在一个已关闭的连接上写操作则会报connection reset by peer。通常我们可能还会看到broken pipe错误,这是管道层面的错误,表示对已关闭的管道进行读写,往往是在收到RST,报出connection reset错后继续读写数据报的错,这个在glibc源码注释中也有介绍。 167 | 我们在排查故障时候怎么确定有RST包的存在呢?当然是使用tcpdump命令进行抓包,并使用wireshark进行简单分析了。tcpdump -i en0 tcp -w xxx.cap,en0表示监听的网卡。 168 | 169 | 接下来我们通过wireshark打开抓到的包,可能就能看到如下图所示,红色的就表示RST包了。 170 | 171 | TIME_WAIT和CLOSE_WAIT 172 | TIME_WAIT和CLOSE_WAIT是啥意思相信大家都知道。 173 | 在线上时,我们可以直接用命令netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'来查看time-wait和close_wait的数量 174 | 用ss命令会更快ss -ant | awk '{++S[$1]} END {for(a in S) print a, S[a]}' 175 | 176 | 177 | TIME_WAIT 178 | time_wait的存在一是为了丢失的数据包被后面连接复用,二是为了在2MSL的时间范围内正常关闭连接。它的存在其实会大大减少RST包的出现。 179 | 过多的time_wait在短连接频繁的场景比较容易出现。这种情况可以在服务端做一些内核参数调优: 180 | #表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭 181 | net.ipv4.tcp_tw_reuse = 1 182 | #表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭 183 | net.ipv4.tcp_tw_recycle = 1 184 | 当然我们不要忘记在NAT环境下因为时间戳错乱导致数据包被拒绝的坑了,另外的办法就是改小tcp_max_tw_buckets,超过这个数的time_wait都会被干掉,不过这也会导致报time wait bucket table overflow的错。 185 | CLOSE_WAIT 186 | close_wait往往都是因为应用程序写的有问题,没有在ACK后再次发起FIN报文。close_wait出现的概率甚至比time_wait要更高,后果也更严重。往往是由于某个地方阻塞住了,没有正常关闭连接,从而渐渐地消耗完所有的线程。 187 | 想要定位这类问题,最好是通过jstack来分析线程堆栈来排查问题,具体可参考上述章节。这里仅举一个例子。 188 | 开发同学说应用上线后CLOSE_WAIT就一直增多,直到挂掉为止,jstack后找到比较可疑的堆栈是大部分线程都卡在了countdownlatch.await方法,找开发同学了解后得知使用了多线程但是确没有catch异常,修改后发现异常仅仅是最简单的升级sdk后常出现的class not found。 -------------------------------------------------------------------------------- /高效工作/时间管理.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stylesmile/javaRoad/500e28dd78804c915df06cef32a3e95d3b989465/高效工作/时间管理.png -------------------------------------------------------------------------------- /高效工作/时间管理.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stylesmile/javaRoad/500e28dd78804c915df06cef32a3e95d3b989465/高效工作/时间管理.xmind --------------------------------------------------------------------------------