十一月札记
认识获取(了解概念) -> 知识学习(建立模型) -> 技能训练(实践)
git 常用命令
git tag -a v1.3.1 -m "version v1.3.1 2019-6-20 ok" #创建了本地一个版本 V20180817 ,并且添加了附注信息 version 20180817 但是目前这个标签仅仅是提交到了本地git仓库.
git push origin --tags # 同步到远程代码库,tag 远程推送
git show v20180107 #查看对应的版本号
git reset --hard XXXXXXXX # 回到当时版本
git tag -a v1.3.2 -m "version v1.3.2 2019-7-12 ok"
git pull origin master 如果是多人开发的话 需要把远程master上的代码pull下来
把dev分支的代码合并到master上
git merge dev
然后查看状态
git status
上面的意思就是你有12个commit,需要push到远程master上
执行下面命令即可
git push origin master
git强制覆盖:
git fetch --all
git reset --hard origin/master
git pull
git push origin --delete dev # 删除远程dev分支
git branch -d dev # 删除本地分支dev
apt-get 常用命令
apt-cache search XXXXX :查询包
apt-get update:更新安装列表
apt-get upgrade:升级软件
apt-get install software_name :安装软件
apt-get --purge remove software_name :卸载软件及其配置
apt-get autoremove software_name:卸载软件及其依赖的安装包
dpkg --list:罗列已安装软件
安装python3.7
wget https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tar.xz
xz -d Python-3.7.0.tar.xz
tar -xvf Python-3.7.0.tar
cd Python-3.7.0
./configure
make
sudo make install
curl
## 需要注意的是在window中单引号要改成双引号,json格式数据中双引号要加\转义
curl -v -X POST "127.0.0.1:3000/v1/image" -d "{\"group_id\":1,\"name\":\"aaa\",\"url\":\"bbb\",\"status\":1}" -H "Content-Type: application/json"
mysql
# 以管理员身份运行,在命令行输入cd+mySQL的bin目录的安装路径
C:\Windows\system32>cd C:\Program Files\MySQL\MySQL Server5.6\bin
C:\Program Files\MySQL\MySQL Server5.6\bin>mysqld --remove
Service successfully removed.
C:\Program Files\MySQL\MySQL Server5.6\bin>mysqld --install
Service successfully installed.
C:\Program Files\MySQL\MySQL Server5.6\bin>net start mysql
grant replication slave on *.* to 'toto1'@'%' identified by 'toto123';
GRANT ALL PRIVILEGES ON `camel_test`.* TO 'toto'@'%' WITH GRANT OPTION;
GRANT REPLICATION SLAVE ON *.* TO 'toto1'@'%' IDENTIFIED BY 'toto123';
GRANT REPLICATION SUPER ON `camel_test`.* TO 'toto1'@'%';
grant replication slave, reload, super on *.* to 'toto1'@'%' identified by 'toto123';
flush privileges;
show variables like '%binlog_format%'; # 查看bin-log模式:statment(SBR)格式. Row(RBR)格式. MIXED(MBR)综合格式。
show status like 'table_locks_%';# 数据库锁统计
show variables like '%expire_logs_days%'; # 查看默认的日志保存天数
show variables like '%log_error%'; #查看错误日志路径:
show variables like '%slow_query_log%'; # MySQL慢查询日志
SHOW BINARY LOGS; # 获取当前二进制日志列表
MySQL彻底清除slave信息
在我们的MySQL,Master和Slave进行主从切换的时候,Slave成功升级为主库,那么这个时候就需要彻底清理从库的信息,不然监控系统会认为这台服务器是Slave,而且会报主从同步失败。
其实非常的简单,只需要以下两步:
mysql> stop slave;
mysql> reset slave all;
reset slave all;是清除从库的同步复制信息. 包括连接信息和二进制文件名. 位置。
从库上执行这个命令后,使用show slave status将不会有输出。
select id from user where id in (select user_id from shippers inner join commits on shippers.id=commits.shipper_id where commits.type=4);
update truck tk,
(select t.fk_truck_plate,t.fk_carrier_id,t.shipper_name,s.com_no,c.type from carrier_truck_commit t inner join commits c on t.id=c.shipper_id inner join shippers s on s.id=t.fk_carrier_id) obj
set tk.fk_carrier_id=obj.fk_carrier_id, tk.carrier_name=obj.shipper_name,tk.carrier_code=obj.com_no,tk.carrier_type=obj.type,tk.team_carrier_id=obj.fk_carrier_id, tk.team_carrier_name=obj.shipper_name,tk.team_carrier_code=obj.com_no,tk.own_carrier_id=obj.fk_carrier_id, tk.own_carrier_name=obj.shipper_name,tk.own_carrier_code=obj.com_no
where tk.plate=obj.fk_truck_plate;
SELECT
[ALL | DISTINCT | DISTINCTROW ]
[HIGH_PRIORITY]
[STRAIGHT_JOIN]
[SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
[SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
select_expr [, select_expr ...]
[FROM table_references
[PARTITION partition_list]
[WHERE where_condition]
[GROUP BY {col_name | expr | position}
[ASC | DESC], ... [WITH ROLLUP]]
[HAVING where_condition]
[ORDER BY {col_name | expr | position}
[ASC | DESC], ...]
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
[PROCEDURE procedure_name(argument_list)]
[INTO OUTFILE 'file_name'
[CHARACTER SET charset_name]
export_options
| INTO DUMPFILE 'file_name'
| INTO var_name [, var_name]]
[FOR UPDATE | LOCK IN SHARE MODE]]
# 不同版本默认的SQL_MODE
MySQL 5.5:空
MySQL 5.6:NO_ENGINE_SUBSTITUTION
MySQL 5.7:ONLY_FULL_GROUP_BY, STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER, NO_ENGINE_SUBSTITUTION
MySQL 8.0:ONLY_FULL_GROUP_BY, STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_ENGINE_SUBSTITUTION
# 如何修改SQL_MODE
SQL_MODE既可在全局级别修改,又可在会话级别修改。可指定多个MODE,MODE之间用逗号隔开。
# 全局级别
set global sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES';
# 会话级别
set session sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES';
# 总结
1. SQL_MODE在非严格模式下,会出现很多意料不到的结果。建议线上开启严格模式。但对于线上老的环境,如果一开始就运行在非严格模式下,切忌直接调整,毕竟两者的差异性还是相当巨大。
2. 官方默认的SQL_MODE一直在发生变化,MySQL 5.5, 5.6, 5.7就不尽相同,但总体是趋严的,在对数据库进行升级时,其必须考虑默认的SQL_MODE是否需要调整。
3. 在进行数据库迁移时,可通过调整SQL_MODE来兼容其它数据库的语法。
go杂记
#可被寻址
值的修改从表面意义上叫可寻址,换一种说法就是值必须“可被设置”。那么,想修改变量值,一般的步骤是:
取这个变量的地址或者这个变量所在的结构体已经是指针类型。
使用 reflect.ValueOf 进行值包装。
通过 Value.Elem() 获得指针值指向的元素值对象(Value),因为值对象(Value)内部对象为指针时,使用 set 设置时会报出宕机错误。
使用 Value.Set 设置值。
# GO111MODULE
set GO111MODULE=off
set GOPROXY=https://goproxy.io
set GO111MODULE=auto # 在gopath中就默认on,其他地方默认off
# go get 参数
-u 用于下载指定的路径包及其依赖包,默认情况下,不会下载本地已经存在的,只会下载本地不存在的代码包。就是口中常说的跟新包 比如:go get -u github.com/jinzhu/gorm。会把最新的 gorm 包下载到你本地
-d 此命令仅仅是下载路径包,而不会进行安装。即不会执行 go install 命令
-t 让命令程序同时下载并安装指定的代码包中的测试源码文件中依赖的代码包。
-fix 让命令程序在下载代码包后先执行修正动作,而后再进行编译和安装。。
-insecure 允许命令程序使用非安全的scheme(如HTTP)去下载指定的代码包。如果你用的代码仓库(如公司内部的Gitlab)没有HTTPS支持,可以添加此标记。请在确定安全的情况下使用它。(记得 使用工具 git 时,有个版本就是 http 升级为了https)
-v 打印出那些下载的代码包的名字。
-f 仅在使用-u标记时才有效。该标记会让命令程序忽略掉对已下载代码包的导入路径的检查。如果下载并安装的代码包所属的项目是你从别人那里Fork过来的,那么这样做就尤为重要了 。
-x 打印出整个过程使用了哪些命令。
# GO111MODULE=auto(auto是指如果在gopath下不启用mod)
go mod init XXX //创建了一个名字为XXX的新模块,自动分析项目里的依赖关系同步到go.mod文件中,同时创建go.sum文件(XXX必须和模块名一致)
go build, go test //和其它构建代码包的命令,会在需要的时候在 go.mod 文件中添加新的依赖项
go list -m all //列出了当前模块所有的依赖项
go get //修改指定依赖项的版本(或者添加一个新的依赖项)
go mod tidy -v //移除模块中没有用到的依赖项,并打印详情
go mod vendor -v //生成vendor文件夹,该文件夹下将会放置你go.mod文件描述的依赖包
go mod help查看帮助
go mod init<项目模块名称>初始化模块,会在项目根目录下生成 go.mod文件。
go mod tidy 根据go.mod文件来处理依赖关系。
go mod vendor将依赖包复制到项目下的 vendor目录。建议一些使用了被墙包的话可以这么处理,方便用户快速使用命令go build -mod=vendor编译
go list -m all显示依赖关系。go list -m -json all显示详细依赖关系。
go mod download <path@version>下载依赖。参数<path@version>是非必写的,path是包的路径,version是包的版本。
# 如果你使用的 Go 版本>=1.13, 你可以通过设置 GOPRIVATE 环境变量来控制哪些私有仓库和依赖(公司内部仓库)不通过 proxy 来拉取,直接走本地,设置如下:
set GOPROXY=https://proxy.golang.org
set GOPROXY=https://goproxy.io
Go version >= 1.13
go env -w GOPROXY=https://goproxy.io
go env -w GOPRIVATE=*.corp.example.com //设置不走 proxy 的私有仓库,多个用逗号相隔
引入本地包的方法(在go.mod中)
require (
test v0.0.0
)
replace (
test => ../test
)
注意:
1.引入的包必须也是gomod的(有.mod文件)
2.replace时必须使用相对路径比如../ ./
3.require 的包后必须带版本号,replace中可带可不带
require go-crud/conf v0.0.0
replace go-crud/conf => ./conf
# Golang 解决 golang.org/x/ 下包下载不下来的问题
由于众所周知的原因,golang在下载golang.org的包时会出现访问不了的情况。尤其是x包,很多库都依赖于它。由于x包在github上都有镜像,我们可以使用从github.com上先clone下来,再做软链接的方式曲线救国。
mkdir -p $GOPATH/src/github.com/golang/
git clone https://github.com/golang/sys.git $GOPATH/src/github.com/golang/sys
git clone https://github.com/golang/net.git $GOPATH/src/github.com/golang/net
git clone https://github.com/golang/text.git $GOPATH/src/github.com/golang/text
git clone https://github.com/golang/lint.git $GOPATH/src/github.com/golang/lint
git clone https://github.com/golang/tools.git $GOPATH/src/github.com/golang/tools
git clone https://github.com/golang/crypto.git $GOPATH/src/github.com/golang/crypto
ln -s $GOPATH/src/github.com/golang/ $GOPATH/src/golang.org/x
git clone https://github.com/golang/context.git $GOPATH/src/github.com/golang/context
ln -s /usr/bin/go $GOPATH/src/golang.org/x
ln -s /usr/bin/go /usr/local/go/bin/go
ln -s /usr/bin/X11/go /usr/local/go/bin/go
supervisorctl 后台任务进程管理
supervisor能把一个普通进程变为后台daemon进程,并监控进程状态,在进程异常退出时能够自动重启(或者告警),同时还提供一些相关的管理功能
1.查询所有进程状态:
supervisorctl status
2.启. 停. 重启业务进程,tomcat为进程名,即[program:tomcat]里配置的值:
supervisorctl start tomcat
supervisorctl stop tomcat
supervisorctl restart tomcat
3.管理全部进程:
supervisorctl start all
supervisorctl stop all
supervisorctl restart all
4.重新加载配置文件,停止原有进程并按新的配置启动所有进程(注意:所有进程会停止并重启,线上操作慎重)
supervisorctl reload
5.根据最新的配置文件,启动新配置或有改动的进程,配置没有改动的进程不会受影响而被重启(注意:这才是线上可以操作的命令,不会重启原有进程)
supervisorctl update
#把stderr重定向到stdout,默认false;
stdout_logfile=/data/log/tomcat/out-memcache.log
#标准日志输出;
stderr_logfile=/data/log/tomcat/err-memcache.log
systemctl 服务管理
systemctl enable servicename 开机启动服务
systemctl disable servicename 停止开机启动服务
systemctl start/stop/restart servicename 启动/停止/重启服务
systemctl reload servicename 重新加载配置文件
systemctl status servicename 查看服务状态
systemctl -a 列出所有服务的状态
systemctl list-units 列出当前系统服务状态
systemctl list-unit-files 列出服务的状态
systemctl list-dependencies servicename 列出服务的依赖关系
systemctl list-sockets 显示套接字文件
systemctl list-timers 列出定时器
systemctl cat servicename 查看服务的配置文件
systemctl show-environment 查看环境变量
systemd-analyze blame 显示每个进程消耗时间
systemd-analyze plot 生成网页
架构
好的架构不是设计出来的,而是进化而来的:
(1)流量小的时候,我们要提高开发效率,可以在早期要引入ORM,DAO;
(2)流量变大,可以使用动静分离. 读写分离. 主从同步. 垂直拆分. CDN. MVC等方式不断提升网站的性能和研发效率;
(3)面对更大的流量时,通过垂直拆分. 服务化. 反向代理. 开发框架(站点/服务)等等手段,可以不断提升高可用(研发效率);
(4)在面对上亿级的流量时,通过配置中心. 柔性服务. 消息总线. 自动化(回归,测试,运维,监控)来迎接新的挑战;
1.所有的网络调用没有抛出最原始error信息。(经过加工之后的日志会严重误导人。)
2.超时时间的设置未能起到作用,未经过完整的压测和故障演练,所以超时时间很容易无效。
3.内外网域名没有隔离,需要区分内外网调用,做好环境隔离。
4.http服务器本身的超时没有设置,如果程序内部出现问题导致处理超时,并发会把服务器拖垮。
5.系统一旦上云之后整个网络架构变得复杂,干扰因素太多,排查也会面临比较大的依赖,对云上的调用链路和网络架构需要非常熟悉,这样才能快速定位问题。
系统架构的目标是解决利益相关者的关注点
架构是这样定义的:
1.每个系统都有一个架构
2.架构由架构元素以及相互之间的关系构成
3.系统是为了满足利益相关者(stakeholder)的需求而构建的
4.利益相关者都有自己的关注点(concerns)
5.架构由架构文档描述
6.架构文档描述了一系列的架构视角
7.每个视角都解决并且对应到利益相关者的关注点。
1.soft skills are always hard than hard skills,软技能比硬技能难
2.choosing relationship over correctness ,注重关系重于谁对谁错
3.架构的政治性,在中大型公司里工作的架构师尤其要学习
政治指的是和他人协作将事情搞定的艺术,架构是一种社交活动,在技术的世界里,个人主义很容易被打败,即使你的目的是好的技术是最优的,技术决策是政治决策(technical decisions are political decisions),一个技术产品,一波人可以做,另一波人也可以做,到底谁做的好,真不好说,不管谁做,都给业务套上了一副手铐。
架构系统前,架构师的首要任务是尽最大可能找出所有利益相关者,业务方,产品经理,客户 / 用户,开发经理,工程师,项目经理,测试人员,运维人员,产品运营人员等等都有可能是利益相关者,架构师要充分和利益相关者沟通,深入理解他们的关注点和痛点,并出架构解决这些关注点。
最小可用产品(Minimum Viable Product, MVP)理念
收集 -> 测量 -> 调整 -> 闭环重复,在有测量数据和反馈的基础上,系统. 应用. 流程和客户体验才有可能获得持续的提升和改善,否则没有数据的所谓改进只能靠拍脑袋或者说猜测。
微服务更多是关于组织和团队,而不是技术
反向面试
#职责
On-call (电话值班)的计划或者规定是什么?值班或者遇到问题加班时候有加班费吗?
我的日常工作是什么?
团队里面初级和高级工程师的比例是多少?(有计划改变吗)
入职培训会是什么样的?
自己单独的开发活动和按部就班工作的比例大概是怎样的?
每天预期/核心工作时间是多少小时?
在你看来,这个工作做到什么程度算成功?
我入职的岗位是新增还是接替之前离职的同事?(是否有技术债需要还)?(zh)
入职之后在哪个项目组,项目是新成立还是已有的?(zh)
#技术
公司常用的技术栈是什么?
你们怎么使用源码控制系统?
你们怎么测试代码?
你们怎么追踪 bug?
你们怎么集成和部署代码改动?是使用持续集成和持续部署吗?
你们的基础设施搭建方法在版本管理系统里吗?或者是代码化的吗?
从计划到完成一项任务的工作流是什么样的?
你们如何准备故障恢复?
有标准的开发环境吗?是强制的吗?
你们需要花费多长时间来给产品搭建一个本地测试环境?(分钟/小时/天)
你们需要花费多长时间来响应代码或者依赖中的安全问题?
所有的开发者都可以使用他们电脑的本地管理员权限吗?
公司是否有技术分享交流活动?有的话,多久一次呢?(zh)
#团队
工作是怎么组织的?
团队内/团队间的交流通常是怎样的?
如果遇到不同的意见怎样处理?
谁来设定优先级 / 计划?
如果被退回了会怎样?(“这个在预计的时间内做不完”)
每周都会开什么类型的会议?
产品/服务的规划是什么样的?(n周一发布 / 持续部署 / 多个发布流 / ...)
生产环境发生事故了怎么办?是否有不批评人而分析问题的文化?
有没有一些团队正在经历还尚待解决的挑战?
公司技术团队的架构和人员组成?(zh)
#公司
有没有会议/旅行预算?使用的规定是什么?
晋升流程是怎样的?要求/预期是怎样沟通的?
技术和管理两条职业路径是分开的吗?
对于多元化招聘的现状或者观点是什么?
有公司级别的学习资源吗?比如电子书订阅或者在线课程?
有获取证书的预算吗?
公司的成熟度如何?(早期寻找方向 / 有内容的工作 / 维护中 / ...)
我可以为开源项目做贡献吗?是否需要审批?
有竞业限制或者保密协议需要签吗?
你们认为公司文化中的空白是什么?
能够跟我说一公司处于不良情况,以及如何处理的故事吗?
#商业
你们现在盈利吗?
如果没有的话,还需要多久?
公司的资金来源是什么?谁影响或者指定高层计划或方向?
你们如何挣钱?
什么阻止了你们挣更多的钱?
你们认为什么是你们的竞争优势?
#远程工作
远程工作和办公室工作的比例是多少?
公司提供硬件吗?更新计划如何?
额外的附件和家居可以通过公司购买吗?这方面是否有预算?
有共享办公或者上网的预算吗?
多久需要去一次办公室?
公司的会议室是否一直为视频会议准备着?
办公室工作
办公室的布局如何?(开放的 / 小隔间 / 独立办公室)
有没有支持/市场/或者其他需要大量打电话的团队在我的团队旁边办公?
#待遇
如果有奖金计划的话,奖金如何分配?
如果有奖金计划的话,过去的几年里通常会发百分之多少的奖金?
有五险一金或者其他退休养老金等福利吗?如果有的话,公司有配套的商业保险吗?
带薪休假
带薪休假时间有多久?
病假和事假是分开的还是一起算?
我可以提前使用假期时间吗?也就是说应休假期是负的?
假期的更新策略是什么样的?也就是说未休的假期能否滚入下一周期
照顾小孩的政策如何?
无薪休假政策是什么样的?
shell的艺术
https://github.com/jlevy/the-art-of-command-line/blob/master/README-zh.md
在 Bash 中,可以通过按 Tab 键实现自动补全参数,使用 ctrl-r 搜索命令行历史记录(按下按键之后,输入关键字便可以搜索,重复按下 ctrl-r 会向后查找匹配项,按下 Enter 键会执行当前匹配的命令,而按下右方向键会将匹配项放入当前行中,不会直接执行,以便做出修改)。
在 Bash 中,可以按下 ctrl-w 删除你键入的最后一个单词,ctrl-u 可以删除行内光标所在位置之前的内容,alt-b 和 alt-f 可以以单词为单位移动光标,ctrl-a 可以将光标移至行首,ctrl-e 可以将光标移至行尾,ctrl-k 可以删除光标至行尾的所有内容,ctrl-l 可以清屏。键入 man readline 可以查看 Bash 中的默认快捷键。内容有很多,例如 alt-. 循环地移向前一个参数,而 alt-* 可以展开通配符。
pstree -p 以一种优雅的方式展示进程树
使用 netstat -lntp 或 ss -plat 检查哪些进程在监听端口(默认是检查 TCP 端口; 添加参数 -u 则检查 UDP 端口)或者 lsof -iTCP -sTCP:LISTEN -P -n (这也可以在 OS X 上运行)。
lsof 来查看开启的套接字和文件。
strace 跟踪一个进程的系统调用或信号产生的情况
ltrace 跟踪进程调用库函数的情况
lsblk 列出块设备信息:以树形展示你的磁盘以及磁盘分区信息
lshw,lscpu,lspci,lsusb 和 dmidecode:查看硬件信息,包括 CPU. BIOS. RAID. 显卡. USB设备等
lsmod 和 modinfo 列出内核模块,并显示其细节
pmap -d $pid
ps aux|grep $pid
top -p $pid
cat /proc/$pid/status
ps aux | sort -k4nr | head -n 10
htop -p $pid # top 的加强版
# 查看CPU信息(型号)
cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c
# 查看物理CPU个数
cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l
# 查看每个物理CPU中core的个数(即核数)
cat /proc/cpuinfo| grep "cpu cores"| uniq
# 查看逻辑CPU的个数
cat /proc/cpuinfo| grep "processor"| wc -l
expr:计算表达式或正则匹配
m4:简单的宏处理器
yes:多次打印字符串
cal:漂亮的日历
env:执行一个命令(脚本文件中很有用)
printenv:打印环境变量(调试时或在写脚本文件时很有用)
look:查找以特定字符串开头的单词或行
cut,paste 和 join:数据修改
fmt:格式化文本段落
pr:将文本格式化成页/列形式
fold:包裹文本中的几行
column:将文本格式化成多个对齐. 定宽的列或表格
expand 和 unexpand:制表符与空格之间转换
nl:添加行号
seq:打印数字
bc:计算器
factor:分解因数
gpg:加密并签名文件
toe:terminfo 入口列表
nc:网络调试及数据传输
socat:套接字代理,与 netcat 类似
slurm:网络流量可视化
dd:文件或设备间传输数据
file:确定文件类型
tree:以树的形式显示路径和文件,类似于递归的 ls
stat:文件信息
time:执行命令,并计算执行时间
timeout:在指定时长范围内执行命令,并在规定时间结束后停止进程
lockfile:使文件只能通过 rm -f 移除
logrotate: 切换. 压缩以及发送日志文件
watch:重复运行同一个命令,展示结果并/或高亮有更改的部分
when-changed:当检测到文件更改时执行指定命令。参阅 inotifywait 和 entr。
tac:反向输出文件
shuf:文件中随机选取几行
comm:一行一行的比较排序过的文件
strings:从二进制文件中抽取文本
tr:转换字母
iconv 或 uconv:文本编码转换
split 和 csplit:分割文件
sponge:在写入前读取所有输入,在读取文件后再向同一文件写入时比较有用,例如 grep -v something some-file | sponge some-file
units:将一种计量单位转换为另一种等效的计量单位(参阅 /usr/share/units/definitions.units)
apg:随机生成密码
xz:高比例的文件压缩
ldd:动态库信息
nm:提取 obj 文件中的符号
ab 或 wrk:web 服务器性能分析
strace:调试系统调用
mtr:更好的网络调试跟踪工具
cssh:可视化的并发 shell
rsync:通过 ssh 或本地文件系统同步文件和文件夹
wireshark 和 tshark:抓包和网络调试工具
ngrep:网络层的 grep
host 和 dig:DNS 查找
lsof:列出当前系统打开文件的工具以及查看端口信息
dstat:系统状态查看
glances:高层次的多子系统总览
iostat:硬盘使用状态
mpstat: CPU 使用状态
vmstat: 内存使用状态
htop:top 的加强版
last:登入记录
w:查看处于登录状态的用户
id:用户/组 ID 信息
sar:系统历史数据
iftop 或 nethogs:套接字及进程的网络利用情况
ss:套接字数据
dmesg:引导及系统错误信息
sysctl: 在内核运行时动态地查看和修改内核的运行参数
hdparm:SATA/ATA 磁盘更改及性能分析
lsblk:列出块设备信息:以树形展示你的磁盘以及磁盘分区信息
lshw,lscpu,lspci,lsusb 和 dmidecode:查看硬件信息,包括 CPU. BIOS. RAID. 显卡. USB设备等
lsmod 和 modinfo:列出内核模块,并显示其细节
fortune,ddate 和 sl:额,这主要取决于你是否认为蒸汽火车和莫名其妙的名人名言是否“有用”
网络调试
# tracepath 122.235.81.5
1?: [LOCALHOST] pmtu 1500
1: no reply
2: no reply
3: 11.208.177.13 11.165ms asymm 1
4: 11.208.176.178 30.852ms asymm 2
5: 116.251.117.174 0.690ms asymm 3
6: 116.251.113.33 1.123ms asymm 4
7: 150.138.130.117 0.978ms asymm 5
8: 150.138.128.185 6.510ms asymm 6
9: 202.97.13.49 17.593ms asymm 7
10: 61.164.23.254 19.454ms asymm 9
11: 61.164.4.103 32.944ms asymm 10
12: 122.235.81.5 23.153ms reached
# mtr 122.235.81.5
Host Loss% Snt Last Avg Best Wrst StDev
1. ???
2. ???
3. 11.208.176.157 0.0% 12 0.8 1.9 0.7 13.3 3.5
4. 11.208.177.254 0.0% 12 58.5 37.4 0.9 75.4 33.0
5. 116.251.117.170 0.0% 12 1.2 2.0 1.1 6.7 1.4
6. 103.41.143.114 0.0% 12 2.5 1.4 1.2 2.5 0.3
7. 150.138.130.113 0.0% 12 0.9 1.0 0.9 1.3 0.0
8. 150.138.128.113 0.0% 12 11.1 11.2 9.0 21.3 3.5
9. 202.97.39.25 16.7% 12 24.7 25.7 24.7 32.3 2.2
10. 220.191.143.177 54.5% 12 22.3 22.3 22.2 22.5 0.0
11. 61.164.4.101 0.0% 12 27.5 51.7 27.4 245.8 64.3
12. 122.235.81.5 0.0% 11 22.4 22.7 22.3 24.4 0.4
神器 strace
strace能做什么:
它可以基于特定的系统调用或系统调用组进行过滤
它可以通过统计特定系统调用的使用次数,所花费的时间,以及成功和错误的数量来分析系统调用的使用。
它跟踪发送到进程的信号。
可以通过pid附加到任何正在运行的进程。
调试性能问题,查看系统调用的频率,找出耗时的程序段
查看程序读取的是哪些文件从而定位比如配置文件加载错误问题
查看某个php脚本长时间运行“假死”情况
当程序出现“Out of memory”时被系统发出的SIGKILL信息所kill
另外因为strace拿到的是系统调用相关信息,一般也即是IO操作信息,这个对于排查比如cpu占用100%问题是无能为力的。这个时候就可以使用GDB工具了。
strace参数:
-c 统计每一系统调用的所执行的时间,次数和出错的次数等.
-d 输出strace关于标准错误的调试信息.
-f 跟踪由fork调用所产生的子进程.
-ff 如果提供-o filename,则所有进程的跟踪结果输出到相应的filename.pid中,pid是各进程的进程号.
-F 尝试跟踪vfork调用.在-f时,vfork不被跟踪.
-h 输出简要的帮助信息.
-i 输出系统调用的入口指针.
-q 禁止输出关于脱离的消息.
-r 打印出相对时间关于,,每一个系统调用.
-t 在输出中的每一行前加上时间信息.
-tt 在输出中的每一行前加上时间信息,微秒级.
-ttt 微秒级输出,以秒了表示时间.
-T 显示每一调用所耗的时间.
-v 输出所有的系统调用.一些调用关于环境变量,状态,输入输出等调用由于使用频繁,默认不输出.
-V 输出strace的版本信息.
-x 以十六进制形式输出非标准字符串
-xx 所有字符串以十六进制形式输出.
-a column
设置返回值的输出位置.默认 为40.
-e expr
指定一个表达式,用来控制如何跟踪.格式如下:
[qualifier=][!]value1[,value2]...
qualifier只能是 trace,abbrev,verbose,raw,signal,read,write其中之一.value是用来限定的符号或数字.默认的 qualifier是 trace.感叹号是否定符号.例如:
-eopen等价于 -e trace=open,表示只跟踪open调用.而-etrace!=open表示跟踪除了open以外的其他调用.有两个特殊的符号 all 和 none.
注意有些shell使用!来执行历史记录里的命令,所以要使用\\.
-e trace=
只跟踪指定的系统 调用.例如:-e trace=open,close,rean,write表示只跟踪这四个系统调用.默认的为set=all.
-e trace=file
只跟踪有关文件操作的系统调用.
-e trace=process
只跟踪有关进程控制的系统调用.
-e trace=network
跟踪与网络有关的所有系统调用.
-e strace=signal
跟踪所有与系统信号有关的 系统调用
-e trace=ipc
跟踪所有与进程通讯有关的系统调用
-e abbrev=
设定 strace输出的系统调用的结果集.-v 等与 abbrev=none.默认为abbrev=all.
-e raw=
将指 定的系统调用的参数以十六进制显示.
-e signal=
指定跟踪的系统信号.默认为all.如 signal=!SIGIO(或者signal=!io),表示不跟踪SIGIO信号.
-e read=
输出从指定文件中读出 的数据.例如:
-e read=,
-e write=
输出写入到指定文件中的数据.
-o filename
将strace的输出写入文件filename
-p pid
跟踪指定的进程pid.
-s strsize
指定输出的字符串的最大长度.默认为32.文件名一直全部输出.
-u username
以username 的UID和GID执行被跟踪的命令
window shell
netstat -ano 查看所有的端口占用
netstat -ano|findstr "3306"
tasklist|findstr "pid" 找到进程名称,
taskkill /f /t /im 进程名称 结束进程
strace -p 也可以再window上用
wmic 神器....
hdparm:SATA/ATA 磁盘更改及性能分析,
hdparm -t /dev/sda 测试硬盘的读取速度
hdparm -T /dev/xvda 测试硬盘缓存的读取速度
{
hdparm [-CfghiIqtTvyYZ][-a <快取分区>][-A <0或1>][-c <I/O模式>][-d <0或1>][-k <0或1>][-K <0或1>][-m <分区数>][-n <0或1>][-p <PIO模式>][-P <分区数>][-r <0或1>][-S <时间>][-u <0或1>][-W <0或1>][-X <传输模式>][设备]
-a<快取分区> 设定读取文件时,预先存入块区的分区数,若不加上<快取分区>选项,则显示目前的设定。
-A<0或1> 启动或关闭读取文件时的快取功能。
-c<I/O模式> 设定IDE32位I/O模式。
-C 检测IDE硬盘的电源管理模式。
-d<0或1> 设定磁盘的DMA模式。
-f 将内存缓冲区的数据写入硬盘,并清楚缓冲区。
-g 显示硬盘的磁轨,磁头,磁区等参数。
-h 显示帮助。
-i 显示硬盘的硬件规格信息,这些信息是在开机时由硬盘本身所提供。
-I 直接读取硬盘所提供的硬件规格信息。
-k<0或1> 重设硬盘时,保留-dmu参数的设定。
-K<0或1> 重设硬盘时,保留-APSWXZ参数的设定。
-m<磁区数> 设定硬盘多重分区存取的分区数。
-n<0或1> 忽略硬盘写入时所发生的错误。
-p<PIO模式> 设定硬盘的PIO模式。
-P<磁区数> 设定硬盘内部快取的分区数。
-q 在执行后续的参数时,不在屏幕上显示任何信息。
-r<0或1> 设定硬盘的读写模式。
-S<时间> 设定硬盘进入省电模式前的等待时间。
-t 评估硬盘的读取效率。
-T 评估硬盘快取的读取效率。
-u<0或1> 在硬盘存取时,允许其他中断要求同时执行。
-v 显示硬盘的相关设定。
-W<0或1> 设定硬盘的写入快取。
-X<传输模式> 设定硬盘的传输模式。
-y 使IDE硬盘进入省电模式。
-Y 使IDE硬盘进入睡眠模式。
-Z 关闭某些Seagate硬盘的自动省电功能。
查看CPU信息
# 总核数 = 物理CPU个数 X 每颗物理CPU的核数
# 总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数
# 查看物理CPU个数
cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l
# 查看每个物理CPU中core的个数(即核数)
cat /proc/cpuinfo| grep "cpu cores"| uniq
# 查看逻辑CPU的个数
cat /proc/cpuinfo| grep "processor"| wc -l
# 查看CPU信息(型号)
cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c
}
python杂记
# pycharm sphinx-quickstart 生成API文档
https://www.cnblogs.com/combfish/p/10297987.html
pip install line_profiler
安装之后kernprof.py会加到环境变量中。
line_profiler可以统计每行代码的执行次数和执行时间等,时间单位为微妙。
1.在需要测试的函数加上@profile装饰,这里我们把测试代码写在C:\Python34\test.py文件上.
2.运行命令行:kernprof -l -v C:\Python34\test.py
pip install psutil # 需要先安装 psutil 模块
pip install memory_profiler
memory_profiler 模块能够逐行测量内存的占用情况
python -m memory_profiler cp02/demo01.py
# 这些路径都是错误的,会被应用logger的文件影响
log_path = os.path.realpath(os.getcwd()) + '/logs/'
print "log_path:", log_path
log_path = os.path.abspath(os.getcwd()) + '/logs/'
print "log_path:", log_path
log_path = '../logs/'
print "log_path:", log_path
# 以下为正确的
log_path = os.path.split(os.path.realpath(__file__))[0] + '/../logs/' # 固定文件路径
print "log_path:", log_path
log_path = os.path.dirname(os.path.realpath(__file__)) + '/../logs/' # 固定文件路径
print "log_path:", log_path
pip show sphinx # 查看包信息
# 动态导入库
mp = sys.modules.get('multiprocessing')
if mp is not None:
# Errors may occur if multiprocessing has not finished loading
# yet - e.g. if a custom import hook causes third-party code
# to run when multiprocessing calls import. See issue 8200
# for an example
try:
self.processName = mp.current_process().name
except StandardError:
pass
fi
# Python 中如何实现自动导入缺失的库
https://my.oschina.net/u/4051725/blog/3123190
# python logging日志模块以及多进程日志 的几种处理方式
https://blog.csdn.net/ll641058431/article/details/86446366
# uwsgi日志按天切割
https://www.jianshu.com/p/6609fc915139
# 监听事件
import time
from sqlalchemy import event
from sqlalchemy.engine import Engine
@event.listens_for(Engine, "before_cursor_execute")
def before_cursor_execute(conn, cursor, statement,
parameters, context, executemany):
conn.info.setdefault('query_start_time', []).append(time.time())
statement = "/*node1*/ " + statement
print("Start Query: ", statement)
@event.listens_for(Engine, "after_cursor_execute")
def after_cursor_execute(conn, cursor, statement,
parameters, context, executemany):
total = time.time() - conn.info['query_start_time'].pop(-1)
print("Query Complete!")
print("Total Time:", total)
# 优化器提示,使用 Select.prefix_with() 和 Query.prefix_with() ::
select(...).prefix_with("/*+ NO_RANGE_OPTIMIZATION(t4 PRIMARY) */")
用flask时遇到了返回字符串支持中文显示的问题,在web端显示的是utf-8的编码,而不是中文
虽然不影响接口的读取,但是可读性太差,于是研究了一下怎么直接显示成中文。最后找到了解决方案如下,
在配置中加入下面一行代码就OK了。
app.config['JSON_AS_ASCII'] = False
json.dumps()解决同样的问题可以加入ensure_ascii=False
查询服务链接状态
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
CLOSED:无连接是活动的或正在进行
LISTEN:服务器在等待进入呼叫
SYN_RECV:一个连接请求已经到达,等待确认
SYN_SENT:应用已经开始,打开一个连接
ESTABLISHED:正常数据传输状态
FIN_WAIT1:应用说它已经完成
FIN_WAIT2:另一边已同意释放
ITMED_WAIT:等待所有分组死掉
CLOSING:两边同时尝试关闭
TIME_WAIT:另一边已初始化一个释放
LAST_ACK:等待所有分组死掉
通过修改内核参数使服务端的连接尽快释放
vi /etc/sysctl.conf
net.ipv4.tcp_syncookies = 1 # 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭
net.ipv4.tcp_tw_reuse=1 #让TIME_WAIT状态可以重用,这样即使TIME_WAIT占满了所有端口,也不会拒绝新的请求造成障碍 默认是0
net.ipv4.tcp_tw_recycle=1 #表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
net.ipv4.tcp_fin_timeout=30
/sbin/sysctl -p 让修改生效
别名IP
ifconfig eth0:1 192.168.209.22 broadcast 192.168.209.255 netmask 255.255.255.0 up
route add -host 192.168.209.22 dev eth0:1
ifconfig eth0:1 down
# 辅助IP
ip addr add 192.168.40.20/24 dev eth0
ip addr del 192.168.40.20/24 dev eth0
ifconfig eth1:0 115.28.27.232 netmask 255.255.252.0 up
route add -host 115.28.27.232 dev eth1:0
ip addr show
ip addr
远程转发,本地代理10.30.108.193:6379,通过118.190.87.8转发
ssh -L 6379:10.30.108.193:6379 lgj@118.190.87.8 -p 8100
ssh -L <local port>:<remote host>:<remote port> <SSH server host> # 本地转发
ssh -R <local port>:<remote host>:<remote port> <SSH server host> # 远程转发
先把数据结构搞清楚,程序的其余部分自现。—— David Jones
sar 诊断系统瓶颈
sar(System Activity Reporter系统活动情况报告)是目前 Linux 上最为全面的系统性能分析工具之一,可以从多方面对系统的活动进行报告,包括:文件的读写情况、 系统调用的使用情况、磁盘I/O、CPU效率、内存使用状况、进程活动及IPC有关的活动等
# sar命令常用格式
sar [options] [-A] [-o file] t [n]
其中:
t为采样间隔,n为采样次数,默认值是1;
-o file表示将命令结果以二进制格式存放在文件中,file 是文件名。
options 为命令行选项,sar命令常用选项如下:
-A:所有报告的总和
-u:输出CPU使用情况的统计信息
-v:输出inode、文件和其他内核表的统计信息
-d:输出每一个块设备的活动信息
-r:输出内存和交换空间的统计信息
-b:显示I/O和传送速率的统计信息
-a:文件读写情况
-c:输出进程统计信息,每秒创建的进程数
-R:输出内存页面的统计信息
-y:终端设备活动情况
-w:输出系统交换活动信息
要判断系统瓶颈问题,有时需几个 sar 命令选项结合起来
怀疑CPU存在瓶颈,可用 sar -u 和 sar -q 等来查看
怀疑内存存在瓶颈,可用 sar -B、sar -r 和 sar -W 等来查看
怀疑I/O存在瓶颈,可用 sar -b、sar -u 和 sar -d 等来查看
#常用命令汇总,因版本和平台不同,有部分命令可能没有或显示结果不一致:
默认监控: sar 5 5 # CPU和IOWAIT统计状态
sar -b 5 5 # IO传送速率
sar -B 5 5 # 页交换速率
sar -c 5 5 # 进程创建的速率
sar -d 5 5 # 块设备的活跃信息
sar -n DEV 5 5 # 网路设备的状态信息
sar -n SOCK 5 5 # SOCK的使用情况
sar -n ALL 5 5 # 所有的网络状态信息
sar -P ALL 5 5 # 每颗CPU的使用状态信息和IOWAIT统计状态
sar -q 5 5 # 队列的长度(等待运行的进程数)和负载的状态
sar -r 5 5 # 内存和swap空间使用情况
sar -R 5 5 # 内存的统计信息(内存页的分配和释放、系统每秒作为BUFFER使用内存页、每秒被cache到的内存页)
sar -u 5 5 # CPU的使用情况和IOWAIT信息(同默认监控)
sar -v 5 5 # inode, file and other kernel tablesd的状态信息
sar -w 5 5 # 每秒上下文交换的数目
sar -W 5 5 # SWAP交换的统计信息(监控状态同iostat 的si so)
sar -x 2906 5 5 # 显示指定进程(2906)的统计信息,信息包括:进程造成的错误、用户级和系统级用户CPU的占用情况、运行在哪颗CPU上
sar -y 5 5 # TTY设备的活动状态
将输出到文件(-o)和读取记录信息(-f)
sar也可以监控非实时数据,通过cron周期的运行到指定目录下
例如:我们想查看本月27日,从0点到23点的内存资源.
sa27就是本月27日,指定具体的时间可以通过-s(start)和-e(end)来指定.
sar -f /var/log/sa/sa27 -s 00:00:00 -e 23:00:00 -r
go 编译
# go help build
讲到go build编译,不能不提跨平台编译,Go提供了编译链工具,可以让我们在任何一个开发平台上,编译出其他平台的可执行文件。
默认情况下,都是根据我们当前的机器生成的可执行文件,比如你的是Linux 64位,就会生成Linux 64位下的可执行文件,比如我的Mac;可以使用go env查看编译环境
# go env
GOARCH="amd64"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOROOT="/usr/local/go"
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GOOS=linux GOARCH=386 go tool compile -S main.go >> main.S 就可以获取了main.go的汇编版本。
注意里面两个重要的环境变量GOOS和GOARCH,其中GOOS指的是目标操作系统,它的可用值为:
darwin
freebsd
linux
windows
android
dragonfly
netbsd
openbsd
plan9
solaris
一共支持10种操作系统。GOARCH指的是目标处理器的架构,目前支持的有:
arm
arm64
386
amd64
ppc64
ppc64le
mips64
mips64le
s390x
# 具体组合参考:
https://golang.org/doc/install/source#environment
# 如果我们要生成不同平台架构的可执行程序,只要改变这两个环境变量就可以了,比如要生成Linux 64位的程序,命令如下:
GOOS=linux GOARCH=amd64 go build flysnow.org/hello
前面两个赋值,是更改环境变量,这样的好处是只针对本次运行有效,不会更改我们默认的配置。
更多关于go build的用户可以通过以下命令查看:go help build
nil 是go语言中预先定义的标识符, 没有默认类型,但它有许多可能的类型,对于编译器来说,必须从上下文中获取充足的信息才能推断出nil的类型。
nil可以代表很多类型的零值,在go语言中,nil可以代表下面这些类型的零值:
指针类型(包括unsafe中的)
map类型
slice类型
function类型
channel类型
interface类型
true和false的默认类型是bool
iota的预先定义类型是int
不同类型的nil值占用的内存大小可能是不一样的
两个不同类型的nil值可能无法进行比较
在go语言中map,slice和function不能比较。比较两个无法比较类型的值(包含nil)是非法的。
对nil channel,map,slice和array 指针进行range操作也是合法的。
nil只能赋值给指针、channel、func、interface、map或slice类型的变量 (非基础类型) 否则会引发 panic
# 链接:https://www.jianshu.com/p/174aa63b2cc5 Go语言中的Nil
碎碎念
先把数据结构搞清楚,程序的其余部分自现。—— David Jones
清晰的数据结构,清晰的概念
学习的过程是:例子(问题+答案)-> 知识 –> 新问题检验 –> 反馈
模拟情景
心理表征
模型类比
刻意练习
小幅迭代
对比反馈
<软技能-代码之外的生存指南>
1)了解全局
2)确定范围
3)定义目标
4)寻找资源
5)创建学习计划
6)筛选资源
7)开始学习,浅尝辄止
8)动手操作,边学边玩
9)全面掌握,学以致用
10)乐为人师,融会贯通
在斗争中,有这么四个原则是我要向大家推荐的:
第一原则,绝对不要随意扩大斗争对象,斗争对象要尽可能指向单个人或少部分人。这是一条基本原则,一定要注意
第二原则,斗争诉求一定要非常明确。诉求点要有先后顺序,抓紧把优先级高的诉求先实现了,不能实现的可以往后放。解决问题是个时间过程而不是一个时间点
第三原则,斗争的奥义是不要试图去说服或者压服你的斗争对象,他不可能被你说服。你斗争过程中的全部表演都是为了争取第三方和旁观者
第四原则,不要轻易威胁你的斗争对象,但是只要威胁了就一定要保证自己有能力做到
自带的redis性能测试工具
redis-benchmark -h 127.0.0.1 -p 6379 -c 100 -n 100000
goland 远程调试
# window上的goland参考此处配置
https://www.520mwx.com/view/53702
本地进入IDE,在要调试的地方打上断点,然后run--debug--eidit configurations-->添加remote主机信息和调试用的端口8200。
# 将代码sync到服务器的对应目录下
export GOPROXY=https://goproxy.io
# 构建主程序可执行文件
go build -o demo.exe
# 构建dlv工具
git clone https://github.com/go-delve/delve.git
go build -o dlv
# 开启远程调试程序
dlv --listen=:8200 --headless=true --api-version=2 --accept-multiclient exec ./demo
# ps
go build -gcflags=all="-N -l" ## 必须这样编译,才能用dlv打印出变量,第二个是小写的L,不是大写的i
阿里云机器上的github比较快,可以代理下使用
docker常用知识
# 常用命令
docker ps # 查看正在运行的容器
docker ps -a # 查看所有容器
docker ps -l # 查看最近一次运行的容器
docker search busybox # 搜索Busybox镜像(集成了100多个最常用Linux命令的软件工具箱,精简的UNIX工具集)
docker pull busybox # 下载Busybox镜像
docker images # 查看镜像
docker rmi 镜像名 # 删除镜像
docker build -t 镜像名:镜像版本 -f Dockerfile . # 依据Dockerfile构建镜像
docker create 容器名或者容器ID # 创建容器
docker start [-i] 容器名 # 启动容器
docker run 容器名或者容器ID # 运行容器,相当于docker create + docker start
docker run -it -v /var/data:/abc myos # 主机卷的映射--docker容器不保持任何数据,重要数据请使用外部卷存储(数据持久化)容器可以挂载真实机目录或共享存储为卷.
docker run -it -v /mnt/nfs/:/zhuhaiyan 192.168.6.153:5000/myos # 使用共享存储的映射
docker run -idt --name busybox1 busybox cal # 运行busybox容器,并运行 cal 命令
docker run -p 8300:8300 -itd -v /home/lgj/gopath/gf-demos:/* webserver2 # 冒号":"前面的目录是宿主机目录,后面的目录是容器内目录。端口映射
docker run -d --name nginx1.1 -p 8080:80 hub.c.163.com/library/nginx # 主机的8080端口映射到容器中的80端口
docker run -a stdin -a stdout -i -t ubuntu /bin/bash
docker run -t -i 镜像名:v2 /bin/bash
docker attach 容器名或者容器ID bash # 进入容器的命令行(退出容器后容器会停止)
docker exec -it 容器名或者容器ID bash # 进入容器的命令行
docker stop 容器名 # 停止容器
docker rm 容器名 # 删除容器
docker top 容器名 # 查看WEB应用程序容器的进程
docker inspect 容器名 # 查看Docker的底层信息
docker logs -tf 容器名 #查看容器应用的实时日志
docker logs --tail="10" 容器名 # 打印容器mytest应用后10行的内容
# dockerfile1
```
FROM scratch
ADD rootfs.tar.xz /
COPY main main
EXPOSE 8080
CMD ["./main"]
```
# dockerfile2
```
FROM docker.io/alpine
RUN echo "#aliyun" > /etc/apk/repositories
RUN echo "https://mirrors.aliyun.com/alpine/v3.6/main/" >> /etc/apk/repositories
RUN echo "https://mirrors.aliyun.com/alpine/v3.6/community/" >> /etc/apk/repositories
RUN apk update
RUN apk add bash vim
```
# 参考
https://my.oschina.net/zhizhisoft/blog/2966531 # 重点来了! CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main . 必须通过此命令构建的二进制文件才能不依赖bash.sh等等啥啊执行.
https://www.cnblogs.com/sap-jerry/p/10029824.html
https://www.runoob.com/docker/docker-image-usage.html
https://segmentfault.com/a/1190000021051021#articleHeader16
https://www.runoob.com/docker/docker-run-command.html # docker命令大全
docker 打包go程序步骤
1. 创件dockerfile文件命名为Dockerfile.scratch
```
# 使用scratch开启
FROM scratch
# 将内部程序输出映射到外界
RUN ln -sf /dev/stdout /xx/xx.log \ # info
&& ln -sf /dev/stderr /xx/xx.log # error
# 拷贝编译程序
COPY main main
# 拷贝依赖的配置文件
ADD config/config.toml config.toml
# 打开8080端口
EXPOSE 8080
# 运行!
CMD ["./main"]
```
2. 使用go程序编写一个web服务
```
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "hello world!")
}
func main() {
http.HandleFunc("/", handler)
fmt.Println("服务端口: 8080")
http.ListenAndServe(":8080", nil)
}
```
3. 编译程序. 创建镜像. 运行服务
$ go build main.go
$ sudo docker build -t webserver -f Dockerfile.scratch .
$ sudo docker run webserver
standard_init_linux.go:190: exec user process caused "no such file or directory"
运行程序会报以上错误,原因是cgo需要libc库,使用以下命令重新编译运行:
$ CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .
$ sudo docker build -t webserver -f Dockerfile.scratch .
$ sudo docker run -p 8080:8080 webserver
服务端口: 8080
成功开启docker容器的 go web服务
4. 因为使用了最简单的镜像,没安装各种依赖,就是把go程序当做一个可执行文件直接执行的,
所以要是go程序中有依赖其他什么东西如路径,配置,文件,系统命令啥的都可能报错.
docker 容器里的进程为什么要前台运行?
《第一本Docker书》讲到Docker容器启动web服务时,都指定了前台运行的参数,例如apache:
ENTRYPOINT [ "/usr/sbin/apache2" ]
CMD ["-D", "FOREGROUND"]
又例如nginx:
ENTRYPOINT [ "/usr/sbin/nginx", "-g", "daemon off;" ]
为什么要这么做呢?因为Docker容器仅在它的1号进程(PID为1)运行时,会保持运行。如果1号进程退出了,Docker容器也就退出了。
(1)容器中运行多个守护进程时,前面的进程要用后台方式运行(或添加 &),否则后面的服务无法启动
(2)容器中最后一个守护进程一定要用前台方式运行,否则start.sh退出,容器退出,所有的服务就白启动了
大多数情况下,我们启动一个Docker容器,只让它运行一个前台程序,并且保证它不会退出,当容器检查到内部没有运行的前台进程之后,自己就会自动退出。
docker run .... --restart=always
在Linux系统启动之后,第一个启动的用户态进程是/sbin/init ,它的PID是1,其余用户态的进程都是init进程的子进程。Supervisor在Docker容器里面充当的就类似init进程的角色,其它的应用进程都是Supervisor进程的子进程。通过这种方法就可以实现在一个容器中启动运行多个应用。
https://blog.csdn.net/u010039418/article/details/83749762
秒杀系统基本架构
# 层级 产品 解决方案
应用层 浏览器、APP 浏览器缓存、本地缓存(sqllite,localstorage)、按钮控制(过滤垃圾流量)、图形验证码(防止接口刷)
网络层 网络路由 CDN (超大并发秒杀很有必要、静态资源,节省服务器带宽)
负载层 Nginx 负载均衡、动静分离、反向代理缓存、限流
服务层 java应用 动态页面静态化(让浏览器可以缓存)、应用缓存、分布式缓存、异步、队列、限流、分布式锁
数据库 oracle、mysql 原子操作保障(乐观锁、悲观锁)
# 限流算法
1. 令牌桶:(处理突发流量)
以一定速率填充令牌(填满了则丢弃),另外一边去拿令牌,拿到令牌的可以进行下一步操作,没拿到令牌的直接拒绝
2. 漏桶:(处理速率恒定)
流入水滴的速率任意,桶底按常量速率流出水滴如果流入速率过快、超过了桶的容量、则直接丢弃水滴
# 方案
1. 客户端过滤垃圾流量
2. nginx 动静分离(反向代理图片)、负载均衡、限流
{
https://blog.csdn.net/hellow__world/article/details/78658041
https://blog.csdn.net/dongl890426/article/details/83863763
# 样例
imit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server {
location /search/ {
limit_req zone=one burst=5 nodelay;
}
}
$binary_remote_addr :表示通过remote_addr这个标识来做限制,“binary_”的目的是缩写内存占用量,是限制同一客户端ip地址
zone=one:10m:表示生成一个大小为10M,名字为one的内存区域,用来存储访问的频次信息
rate=1r/s:表示允许相同标识的客户端的访问频次,这里限制的是每秒1次,即每秒只处理一个请求,还可以有比如30r/m的,即限制每2秒访问一次,即每2秒才处理一个请求。
zone=one :设置使用哪个配置区域来做限制,与上面limit_req_zone 里的name对应
burst=5:重点说明一下这个配置,burst爆发的意思,这个配置的意思是设置一个大小为5的缓冲区当有大量请求(爆发)过来时,超过了访问频次限制的请求可以先放到这个缓冲区内等待,但是这个等待区里的位置只有5个,超过的请求会直接报503的错误然后返回。
nodelay:
如果设置,会在瞬时提供处理(burst + rate)个请求的能力,请求超过(burst + rate)的时候就会直接返回503,永远不存在请求需要等待的情况。(这里的rate的单位是:r/s)
如果没有设置,则所有请求会依次等待排队
limit_req zone=req_zone;
严格依照在limti_req_zone中配置的rate来处理请求
超过rate处理能力范围的,直接drop
表现为对收到的请求无延时
limit_req zone=req_zone burst=5;
依照在limti_req_zone中配置的rate来处理请求
同时设置了一个大小为5的缓冲队列,在缓冲队列中的请求会等待慢慢处理
超过了burst缓冲队列长度和rate处理能力的请求被直接丢弃
表现为对收到的请求有延时
limit_req zone=req_zone burst=5 nodelay;
依照在limti_req_zone中配置的rate来处理请求
同时设置了一个大小为5的缓冲队列,当请求到来时,会爆发出一个峰值处理能力,对于峰值处理数量之外的请求,直接丢弃
在完成峰值请求之后,缓冲队列不能再放入请求。如果rate=10r/m,且这段时间内没有请求再到来,则每6 s 缓冲队列就能回复一个缓冲请求的能力,直到回复到能缓冲5个请求位置。
}
3. 分布式限流(redis + lua , nginx + lua)
4. 服务层再次限流
5. 原子减库存
6. 队列、异步
7. 数据库锁 (select version from table from table where id = 1,update table set count = count -1 ,version = version + 1 where id = 1 and version = version)带重试乐观锁、不带重试的乐观锁(并发情况下成功率太低)