解决Ubuntu 16.04更新系统内核出错后的问题

大伟哥的工作电脑使用Ubuntu 16.04系统,已经很久没有更新了,今天正好有空,就运行了sudo apt update, sudo apt upgrade让它在后台自已更新去了。

因为要更新的软件比较多,需要花费挺长时间,大伟哥也没怎么在意,只是在运行结束后看了一下报错,上面显示因为boot分区空间不够,升级linux内核的时候出错了:

在处理时有错误发生:

linux-image-extra-4.4.0-97-generic
linux-image-generic
linux-generic
E: Sub-process /usr/bin/dpkg returned an error code (1)

之前也发生了同样的问题,系统提示可以运行sudo apt-get autoremove清除不需要的依赖的,而多次升级后/boot分区里已经有了多个之前版本的Linux内核,因此大伟哥决定先运行一下这个命令,看能不能自动给/boot分区清理出一部分空间来,这样也省得我再查文档手动清除旧的内核文件了。实验证明这个命令真的有效果,/boot分区清理出了100多M的空间,应该也够安装新的内核了。

再次执行sudo apt update/sudo apt upgrade, 系统并没有接着安装上次没有完成安装的内核,而是报错如下:

davidbro@Workstation:~$ sudo apt upgrade

正在读取软件包列表... 完成
正在分析软件包的依赖关系树       
正在读取状态信息... 完成       
正在计算更新... 完成
有一些软件包无法被安装。如果您用的是 unstable 发行版,这也许是
因为系统无法达到您要求的状态造成的。该版本中可能会有一些您需要的软件
包尚未被创建或是它们已被从新到(Incoming)目录移出。
下列信息可能会对解决问题有所帮助:

下列软件包有未满足的依赖关系:
 linux-image-extra-4.4.0-96-generic : 依赖: linux-image-4.4.0-96-generic 但是它将不会被安装
E: 破损的软件包

试一下sudo apt install命令看看不能能安装:

david@KingChef-Workstation:~$ sudo apt-get install

正在读取软件包列表... 完成
正在分析软件包的依赖关系树       
正在读取状态信息... 完成       
下列软件包将被【卸载】:
  linux-image-extra-4.4.0-96-generic
升级了 0 个软件包,新安装了 0 个软件包,要卸载 1 个软件包,有 0 个软件包未被升级。
有 5 个软件包没有被完全安装或卸载。
解压缩后将会空出 153 MB 的空间。
您希望继续执行吗? [Y/n] Y
(正在读取数据库 ... 系统当前共安装有 356556 个文件和目录。)
正在卸载 linux-image-extra-4.4.0-96-generic (4.4.0-96.119) ...
depmod: FATAL: could not load /boot/System.map-4.4.0-96-generic: No such file or directory
run-parts: executing /etc/kernel/postinst.d/apt-auto-removal 4.4.0-96-generic /boot/vmlinuz-4.4.0-96-generic
run-parts: executing /etc/kernel/postinst.d/dkms 4.4.0-96-generic /boot/vmlinuz-4.4.0-96-generic
Error! Your kernel headers for kernel 4.4.0-96-generic cannot be found.
Please install the linux-headers-4.4.0-96-generic package,
or use the --kernelsourcedir option to tell DKMS where it's located
Error! Your kernel headers for kernel 4.4.0-96-generic cannot be found.
Please install the linux-headers-4.4.0-96-generic package,
or use the --kernelsourcedir option to tell DKMS where it's located
run-parts: executing /etc/kernel/postinst.d/initramfs-tools 4.4.0-96-generic /boot/vmlinuz-4.4.0-96-generic
update-initramfs: Generating /boot/initrd.img-4.4.0-96-generic
WARNING: missing /lib/modules/4.4.0-96-generic
Ensure all necessary drivers are built into the linux image!
depmod: ERROR: could not open directory /lib/modules/4.4.0-96-generic: No such file or directory
depmod: FATAL: could not search modules: No such file or directory
depmod: WARNING: could not open /var/tmp/mkinitramfs_pkdOqR/lib/modules/4.4.0-96-generic/modules.order: No such file or directory
depmod: WARNING: could not open /var/tmp/mkinitramfs_pkdOqR/lib/modules/4.4.0-96-generic/modules.builtin: No such file or directory
run-parts: executing /etc/kernel/postinst.d/pm-utils 4.4.0-96-generic /boot/vmlinuz-4.4.0-96-generic
run-parts: executing /etc/kernel/postinst.d/unattended-upgrades 4.4.0-96-generic /boot/vmlinuz-4.4.0-96-generic
run-parts: executing /etc/kernel/postinst.d/update-notifier 4.4.0-96-generic /boot/vmlinuz-4.4.0-96-generic
run-parts: executing /etc/kernel/postinst.d/zz-update-grub 4.4.0-96-generic /boot/vmlinuz-4.4.0-96-generic
Generating grub configuration file ...
Warning: Setting GRUB_TIMEOUT to a non-zero value when GRUB_HIDDEN_TIMEOUT is set is no longer supported.
Found linux image: /boot/vmlinuz-4.4.0-130-generic
Found initrd image: /boot/initrd.img-4.4.0-130-generic
Found linux image: /boot/vmlinuz-4.4.0-98-generic
Found initrd image: /boot/initrd.img-4.4.0-98-generic
Found linux image: /boot/vmlinuz-3.5.0-54-generic
Found initrd image: /boot/initrd.img-3.5.0-54-generic
Found linux image: /boot/vmlinuz-3.5.0-23-generic
Found initrd image: /boot/initrd.img-3.5.0-23-generic
done
正在设置 initramfs-tools (0.122ubuntu8.11) ...
update-initramfs: deferring update (trigger activated)
正在设置 linux-image-extra-4.4.0-130-generic (4.4.0-130.156) ...
run-parts: executing /etc/kernel/postinst.d/apt-auto-removal 4.4.0-130-generic /boot/vmlinuz-4.4.0-130-generic
run-parts: executing /etc/kernel/postinst.d/dkms 4.4.0-130-generic /boot/vmlinuz-4.4.0-130-generic
ERROR: Cannot create report: [Errno 17] File exists: '/var/crash/i915-4.6.3-4.4.0-dkms.0.crash'
Error! Bad return status for module build on kernel: 4.4.0-130-generic (x86_64)
Consult /var/lib/dkms/i915-4.6.3-4.4.0/1/build/make.log for more information.
run-parts: executing /etc/kernel/postinst.d/initramfs-tools 4.4.0-130-generic /boot/vmlinuz-4.4.0-130-generic
update-initramfs: Generating /boot/initrd.img-4.4.0-130-generic
run-parts: executing /etc/kernel/postinst.d/pm-utils 4.4.0-130-generic /boot/vmlinuz-4.4.0-130-generic
run-parts: executing /etc/kernel/postinst.d/unattended-upgrades 4.4.0-130-generic /boot/vmlinuz-4.4.0-130-generic
run-parts: executing /etc/kernel/postinst.d/update-notifier 4.4.0-130-generic /boot/vmlinuz-4.4.0-130-generic
run-parts: executing /etc/kernel/postinst.d/zz-update-grub 4.4.0-130-generic /boot/vmlinuz-4.4.0-130-generic
Generating grub configuration file ...
Warning: Setting GRUB_TIMEOUT to a non-zero value when GRUB_HIDDEN_TIMEOUT is set is no longer supported.
Found linux image: /boot/vmlinuz-4.4.0-130-generic
Found initrd image: /boot/initrd.img-4.4.0-130-generic
Found linux image: /boot/vmlinuz-4.4.0-98-generic
Found initrd image: /boot/initrd.img-4.4.0-98-generic
Found linux image: /boot/vmlinuz-3.5.0-54-generic
Found initrd image: /boot/initrd.img-3.5.0-54-generic
Found linux image: /boot/vmlinuz-3.5.0-23-generic
Found initrd image: /boot/initrd.img-3.5.0-23-generic
done
正在设置 linux-image-generic (4.4.0.130.136) ...
正在设置 linux-generic (4.4.0.130.136) ...
正在处理用于 initramfs-tools (0.122ubuntu8.11) 的触发器 ...
update-initramfs: Generating /boot/initrd.img-4.4.0-130-generic

这样最新的内核版本4.4.0.130.136就安装好了。其实我觉得这样用autoremove腾出分区空间还是有点风险的,有可能会误删掉其他有用的软件。

git命令-远程仓库拉取、本地仓库更新、工作空间提交等等

未分类

一,新建代码库

1,在当前目录下新建一个git代码库

$ git init 

2,新建一个目录将其初始化为git代码库

$ git init [project-name]

3,git clone 远程代码库

$ git clone [url]

二,配置

1,Git的设置文件为.gitconfig,它可以在用户主目录下(全局配置),也可以在项目目,录(项目配置)。
2, 显示当前的Git配置

$ git config--list

3,编辑git配置文件

$ git config -e[--global]

4,设置提交代码时的用户信息

$ git config[--global] user.name "[name]" 
$ git config[--global] user.email "[email address]"

三、增加/删除文件

1,添加指定文件到暂存区

$ git add [file1][file2] ...

2, 添加指定目录到暂存区,包括子目录,

$ git add [dir]

3, 添加当前目录的所有文件到暂存区

$ git add .

4 添加每个变化前,都会要求确认, 对于同一个文件的多处变化,可以实现分次提交

$ git add -p

5,删除工作区文件,并且将这次删除放入暂存区

$ git rm [file1][file2] ...

6, 停止追踪指定文件,但该文件会保留在工作区

$ git rm --cached[file] 

7, 改名文件,并且将这个改名放入暂存区

$ git mv[file-original] [file-renamed]

四、代码提交

1, 提交暂存区到仓库区,

$ git commit -m[message],

2, 提交暂存区的指定文件到仓库区

$ git commit[file1] [file2] ... -m [message],

3,提交工作区自上次commit之后的变化,直接到仓库区

$ git commit -a,

4, 提交时显示所有diff信息

$ git commit -v

5,使用一次新的commit,替代上一次提交,如果代码没有任何新变化,则用来改写上一次commit的提交信息

$ git commit--amend -m [message]

6, 重做上一次commit,并包括指定文件的新变化

$ git commit--amend [file1] [file2] ...

五、分支

1, 列出所有本地分支

$ git branch

2, 列出所有远程分支

$ git branch -r

3, 列出所有本地分支和远程分支

$ git branch -a

4, 新建一个分支,但依然停留在当前分支

$ git branch[branch-name]

5, 新建一个分支,并切换到该分支

$ git checkout -b[branch]

6, 新建一个分支,指向指定commit

$ git branch[branch] [commit]

7, 新建一个分支,与指定的远程分支建立追踪关系

$ git branch--track [branch] [remote-branch]

8, 切换到指定分支,并更新工作区

$ git checkout[branch-name],

9, 切换到上一个分支

$ git checkout -,

10, 建立追踪关系,在现有分支与指定的远程分支之间

$ git branch--set-upstream [branch] [remote-branch]

11, 合并指定分支到当前分支,

$ git merge[branch]

12, 选择一个commit,合并进当前分支,

$ git cherry-pick[commit]

13, 删除分支,

$ git branch -d[branch-name]

14, 删除远程分支,

$ git push origin--delete [branch-name]
$ git branch -dr[remote/branch]

六、标签,

1, 列出所有tag

$ git tag

2, 新建一个tag在当前commit,

$ git tag [tag]

3, 新建一个tag在指定commit,

$ git tag [tag][commit]

4, 删除本地tag,

$ git tag -d[tag]

5, 删除远程tag,

$ git push origin:refs/tags/[tagName]

6, 查看tag信息,

$ git show [tag]

7, 提交指定tag,

$ git push[remote] [tag]

8, 提交所有tag,

$ git push[remote] --tags

9, 新建一个分支,指向某个tag

$ git checkout -b[branch] [tag]

七、查看信息

1, 显示有变更的文件

$ git status

2, 显示当前分支的版本历史

$ git log

3, 显示commit历史,以及每次commit发生变更的文件

$ git log --stat

4, 搜索提交历史,根据关键词

$ git log -S[keyword]

5, 显示某个commit之后的所有变动,每个commit占据一行

$ git log [tag]HEAD --pretty=format:%s

6, 显示某个commit之后的所有变动,其”提交说明”必须符合搜索条件,

$ git log [tag]HEAD --grep feature

7, 显示某个文件的版本历史,包括文件改名

$ git log --follow[file]
$ git whatchanged[file]

8, 显示指定文件相关的每一次diff

$ git log -p[file]

9, 显示过去5次提交,

$ git log -5--pretty --oneline

10, 显示所有提交过的用户,按提交次数排序

$ git shortlog-sn

11, 显示指定文件是什么人在什么时间修改过,

$ git blame[file]

12, 显示暂存区和工作区的差异

$ git diff

13,显示暂存区和上一个commit的差异

$ git diff--cached [file]

14, 显示工作区与当前分支最新commit之间的差异

$ git diff HEAD

14, 显示两次提交之间的差异,

$ git diff[first-branch]...[second-branch]

15,显示今天你写了多少行代码,

$ git diff--shortstat "@{0 day ago}"

16, 显示某次提交的元数据和内容变化

$ git show[commit]

17, 显示某次提交发生变化的文件,

$ git show--name-only [commit]

18,显示某次提交时,某个文件的内容

$ git show[commit]:[filename]

19, 显示当前分支的最近几次提交

$ git reflog

八、远程同步

1, 下载远程仓库的所有变动

$ git fetch[remote]

2,显示所有远程仓库,

$ git remote -v

3, 显示某个远程仓库的信息,

$ git remote show[remote]

4, 增加一个新的远程仓库,并命名

$ git remote add[shortname] [url]

5,取回远程仓库的变化,并与本地分支合并

$ git pull[remote] [branch]

6, 上传本地指定分支到远程仓库

$ git push[remote] [branch]

7, 强行推送当前分支到远程仓库,即使有冲突

$ git push[remote] --force

8, 推送所有分支到远程仓库

$ git push[remote] --all

九、撤销

1, 恢复暂存区的指定文件到工作区,

$ git checkout[file]

2, 恢复某个commit的指定文件到暂存区和工作区,

$ git checkout[commit] [file]

3,恢复暂存区的所有文件到工作区,

$ git checkout .

4, 重置暂存区的指定文件,与上一次commit保持一致,但工作区不变

$ git reset[file]

5, 重置暂存区与工作区,与上一次commit保持一致

$ git reset--hard

6, 重置当前分支的指针为指定commit,同时重置暂存区,但工作区不变

$ git reset[commit]

7, 重置当前分支的HEAD为指定commit,同时重置暂存区和工作区,与指定commit一致

$ git reset--hard [commit]

8, 重置当前HEAD为指定commit,但保持暂存区和工作区不变

$ git reset--keep [commit]

9, 新建一个commit,用来撤销指定commit, 后者的所有变化都将被前者抵消,并且应用到当前分支

$ git revert[commit]

10, 暂时将未提交的变化移除,稍后再移入

$ git stash
$ git stash pop

十、其他

1, 生成一个可供发布的压缩包

$ git archive

git命令-切换分支

git一般有很多分支,我们clone到本地的时候一般都是master分支,那么如何切换到其他分支呢?主要命令如下:

1. 查看远程分支

$ git branch -a
我在mxnet根目录下运行以上命令:

~/mxnet$ git branch -a
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/master
  remotes/origin/nnvm
  remotes/origin/piiswrong-patch-1
  remotes/origin/v0.9rc1

可以看到,我们现在在master分支下

2. 查看本地分支

~/mxnet$ git branch
* master

3. 切换分支

$ git checkout -b v0.9rc1 origin/v0.9rc1
Branch v0.9rc1 set up to track remote branch v0.9rc1 from origin.
Switched to a new branch 'v0.9rc1'

#已经切换到v0.9rc1分支了
$ git branch
  master
* v0.9rc1

#切换回master分支
$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.

用Zabbix和Docker搭建监控平台

Zabbix 是由 Alexei Vladishev 开发的一种网络监视、管理系统,基于 Server-Client 架构。可用于监视各种网络服务、服务器和网络机器等状态。

1. 架构

Zabbix 作为企业级分布式监控系统,具有很多优点,如:分布式监控,支持 node 和 proxy 分布式模式;自动化注册,根据规则,自动注册主机到监控平台,自动添加监控模板;支持 agentd、snmp、ipmi 和 jmx 等很多通信方式。

同时,Zabbix 官方还发布了 Zabbix Docker 镜像。此次我们以 Zabbix 的官方 Docker 镜像为基础,搭建一个监控平台。 总体架构图如下所示:
未分类
其中,使用 Zabbix 官方的提供的镜像 Zabbix-3.0:3.0.0 作为 Zabbix Web GUI 和 Zabbix Server;Zabbix Server 用来接收来自 Zabbix agent 的数据,并将数据存储到 Zabbix Database,根据配置的监控项和获取到的数据,判断是否达到报警条件,来对主机进行监控;Zabbix Web GUI 提供了 Zabbix Server 的配置和数据展示的可视化界面;

使用 MySQL 作为 Zabbix Database,官方有相应的 MariaDB 的镜像,但是与非容器化的 MySQL 并没有什么区别,因此便于数据的集中管理,我们并不再单独启动一个 MySQL 容器,而是使用已经存在的 MySQL;

使用由 million12 提供的 zabbix-agent:2.4.7 镜像作为 Zabbix agent 部署在各个需要监控的主机上,用来采集 CPU 、内存和进程等监控项的的数据,并发送到 Zabbix Server;

2. 数据库配置

对于数据库无需过多配置,仅需为 Zabbix Server 配置一个用户名密码让其能够访问数据库zabbix 即可。此处配置用户名:zabbix, 密码:zabbix,配置命令如下:

mysql> grant all privileges on zabbix.* to zabbix@'%' identified by 'zabbix';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

3. 启动 Zabbix Server

采用 docker-compose 的方式启动 Zabbix Server,docker-compose.yml 文件内容如下:

version: '2'
services:
  zabbix-server:
    image: zabbix/zabbix-3.0:3.0.0
    container_name: zabbix-server
    network_mode: "bridge"
    restart: always
    ports:
      - "8888:80"
      - "10051:10051"
    volumes:
      - /etc/localtime:/etc/localtime:ro
    environment:
      - ZS_DBHost=192.168.1.100
      - ZS_DBUser=zabbix
      - ZS_DBPassword=zabbix

其中环境变量 ZS_DBHost 是 Zabbix Server 的 IP,我的主机是 192.168.1.100; ZS_DBUser 和ZS_DBPassword 是数据库的用户名和密码,即我们上一步设置的 zabbix;

暴露端口 8888 用于访问页面,10051 用于和 Zabbix-agent 通信;

用 docker-compose up -d 即可启动 Zabbix Server, 启动过程大约需要 1~3 min。用docker logs -f zabbix-server 命令查看容器的日志,日志大致内容如下:

[[email protected] zabbix-server]$ docker logs -f zabbix-server
Creating zabbix-server
Attaching to zabbix-server
zabbix-server | Nginx status page: allowed address set to 127.0.0.1.
zabbix-server | PHP-FPM status page: allowed address set to 127.0.0.1.
zabbix-server | [LOG 13:39:08] Preparing server configuration
zabbix-server | [LOG 13:39:16] Config updated.
zabbix-server | [LOG 13:39:16] Enabling logging and pid management
zabbix-server | [LOG 13:39:17] Done
zabbix-server | [LOG 13:39:17] Waiting for database server
zabbix-server | [LOG 13:39:17] Database server is available
zabbix-server | [LOG 13:39:17] Checking if database exists or SQL import is required
zabbix-server | [WARNING 13:39:17] Zabbix database doesn't exist. Installing and importing default settings
zabbix-server | ERROR 1044 (42000) at line 1: Access denied for user 'zabbix'@'%' to database 'zabbix'
zabbix-server | ERROR 1227 (42000) at line 1: Access denied; you need (at least one of) the RELOAD privilege(s) for this operation
zabbix-server |
zabbix-server | [LOG 13:39:17] Database and user created, importing default SQL
zabbix-server |
zabbix-server | [LOG 13:42:37] Import finished, starting
zabbix-server | [LOG 13:42:37] Starting Zabbix version 3.0.0
zabbix-server | 2016
zabbix-server | 2016-04-07 13:42:37,691 CRIT Supervisor running as root (no user in config file)
zabbix-server | 2016-04-07 13:42:37,691 WARN Included extra file "/etc/supervisor.d/nginx.conf" during parsing
zabbix-server | 2016-04-07 13:42:37,691 WARN Included extra file "/etc/supervisor.d/php-fpm.conf" during parsing

通过日志可以看出,Zabbix Server 启动过程中使用了我们配置的用户名和密码初始化了名为zabbix 的数据库,并导入相应的数据结构及相应的基础数据,所以该容器启动耗时长达 3 min 左右。容器启动后,我们访问 http://192.168.1.100:8888, 出现如下界面,证明 Zabbix Server 启动成功。
未分类
默认账号的用户名、密码是:Admin 和 zabbix, 输入用户名密码登录,即可看到主界面。
未分类
进入到 Configuration 》Hosts 下,点击 disable 按钮,启用 Zabbix Server。
未分类
启用成功后,AVAILABILITY 项中 ZBX 变为绿色,如下图:
未分类

4. 启动 Zabbix agent

同样,Zabbix agent 的启动仍然以 docker-compose 的方式,不同的是 Zabbix agent 添加了一个配置文件,zabbix-agent 目录结构如下:

zabbix-agent
|-- conf
|   -- zabbix-agentd.conf
 -- docker-compose.yml

conf/zabbix-agentd.conf 的内容如下:

LogFile=/tmp/zabbix_agentd.log
EnableRemoteCommands=1
Server=192.168.1.100
ListenPort=10050
ServerActive=192.168.1.100

其中 ListenPort 为容器 zabbix-agent 暴露的端口,用于接收 Zabbix Server 的指令与其交互;Server 和 ServerActive 都指向 Zabbix Server 的 IP;

docker-compose.yml 内容如下:

version: '2'
services:
  zabbix-agent:
    image: million12/zabbix-agent:2.4.7
    container_name: zabbix-agent
    restart: always
    network_mode: "bridge"
    ports:
      - "10050:10050"
    volumes:
      - ./conf/zabbix-agentd.conf:/etc/zabbix_agentd.conf
      - /proc:/data/proc
      - /sys:/data/sys
      - /dev:/data/dev
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - ZABBIX_SERVER=192.168.1.100

其中,ports 暴露了配置文件中需要暴露的接口;挂载 ./conf/zabbix-agentd.conf 自定义配置文件到容器中 /etc/zabbix_agentd.conf 取代默认的配置文件;挂载 /proc、 /sys 和 /dev到容器中 /data 相应文件夹下,用于 zabbix-agent 收集系统进程等监控信息;环境变量中ZABBIX_SERVER 指向 Zabbix Server 的 IP;

运行 docker-compose up -d 即可启动;

5. 结束

数据库已经配置成功,Zabbix Server 正常启动,Zabbix agent 也正常启动,至于如何在 Zabbix Server 中添加需要监控的主机,有很多方式,如主动添加和跟 IP 范围自动发现,但是不在本文讨论范围之内。至此,用Zabbix 和 Docker 搭建监控平台已经完全实现。

(1)报警媒介 Email 配置注意项

未分类
SMTP helo 配置项中,一般是 SMTP server 根域名。如对于腾讯企业邮箱,SMTP server 是smtp.exmail.qq.com,则此处的 SMTP helo 应填写 qq.com。

(2)修改 Zabbix Server 系统语言为简体中文

对于 3.0 版本的 Zabbix Server 系统语言选择下拉框中默认是没有简体中文的,需要改动其源码,改动方式如下:

docker exec -it zabbix-server /bin/bash 进入容器;
vi /usr/local/src/zabbix/frontends/php/include/locales.inc.php,修改文件中的'zh_CN' => ['name' => _('Chinese (zh_CN)'), 'display' => false] 的 false 为 true 即可。

git-bash设置ssh心跳包防超时断开

Windows中使用git-bash作为日常终端工具,在使用ssh命令连接到服务器后,如果较长时间没进行交互时,ssh会断开,导致的现象就是终端卡住,你只能等待它退出,或直接关闭窗口重建连接,很麻烦。

使用ssh命令时,可以增加ServerAliveInterval参数设置心跳时间,比如设置60秒发送一次心跳包

ssh -o ServerAliveInterval=60 [email protected]

想一劳永逸,可以在ssh-config中配置全局参数
在git安装目录下的etc/ssh/ssh_config文件中,增加一行

ServerAliveInterval 60

现在再使用ssh时,就可以一直保存ssh连接在线了。

redis缓存同步小伎俩

redis做缓存分为被动和主动两种,今天要说的是被动+主动结合的一个小伎俩。

主动+被动结合,有2种常见做法:

  • set流派
    • 查询时,先查redis,不命中再查mysql,将结果set到redis里缓存TTL时间
    • 更新时,先更新mysql,再set到redis里缓存TTL时间
  • delete流派
    • 查询流程同上
    • 更新时,先更新mysql,再去redis里做delete删除掉缓存

set流派适合应付读热点的场景,不希望因为delete造成缓存穿透,影响到性能。

delete流派比较平庸,没有太密集的热点读压力,偏向于海量冷数据的被动缓存,删除的性价比更高。

小伎俩

今天的小伎俩与set流派有关,主要指出一个并发竞争的case。

考虑如下的时序:

  • 查询:redis miss,于是查询了mysql得到数据A。
  • 更新:mysql数据修改为B,同时set到Redis中。
  • 查询:通过set 命令将A更新到redis中。

结局:缓存里cache了一份老数据A。

对于缓存一致性要求高的业务是无法接受这种竞争的,即便没有很高的缓存一致性要求,一般业务也不希望这种事情出现。

解决方法,查询时使用setnx命令(set if not exist)取代set,同理可以用hsetnx取代hset,不同数据结构均有对应方法。

zabbix通过企业微信应用发送告警消息

本文参考大佬们的方法整理记录

首先注册申请(http://work.weixin.qq.com/?spm=5176.11156381.0.0.43bb71b2a3RojM)微信企业号
登录企业微信web后台,在【我的企业】选择【企业信息】,查看CorpID
在【企业应用】选择【创建应用】,完成后记录AgentId和Secret

未分类

TIPS

可以通过接口调试工具(http://work.weixin.qq.com/api/devtools/devtool.php?spm=5176.11156381.0.0.43bb71b2a3RojM)测试是否可以成功返回access_token

参考官方API说明发送应用(https://work.weixin.qq.com/api/doc?spm=5176.11156381.0.0.43bb71b2MZpcTD#10167)

配置自定义脚本

这里引用Zhang Sir’s (https://www.zhsir.org/article/134.html?spm=5176.11156381.0.0.43bb71b2MZpcTD)脚本,下载到zabbix_server.conf中设置的自定义告警脚本存放目录下,也可以参考GitHub上微信报警项目(https://github.com/X-Mars/Zabbix-Alert-WeChat?spm=5176.11156381.0.0.43bb71b29DyTuu)

# grep alertscripts /etc/zabbix/zabbix_server.conf 
AlertScriptsPath=/usr/lib/zabbix/alertscripts
# wget http://download.zhsir.org/Zabbix/weixin_linux_amd64
# mv weixin_linux_amd64 wechat
# chmod 755 wechat 
# chown  zabbix:zabbix wechat
# ./wechat -h
Usage of ./wechat:
  -agentid string
        agentid
  -author string
        http://www.oneoaas.com
  -corpid string
        corpid
  -corpsecret string
        corpsecret
  -msg string
        Send Message
  -user string
        which user to send msg
# ./wechat --corpid=CorpID --agentid=企业应用ID --corpsecret=企业应用Secret --msg="告警消息" --user=消息接收者的企业微信账号  
{"errcode":0,"errmsg":"ok","invaliduser":""}  #命令行测试是否可以发信

zabbix server端脚本定义完成后,可以应用到已经接入的主机,直接更新告警媒介即可

【管理/Adminastration】—>【媒介类型/Media Types】—>【创建媒体类型/Create Media Types】

未分类

添加用户告警的媒介并更新
【管理/Adminastration】—>【用户/Users】—>【媒介/Media】

未分类

添加主机后将主机加入用户和组,并创建监控项和触发器及动作
【配置/Configuration】—>【主机/host】—>【监控项】—>【触发器】
注意触发器的严重性需设置和action中定义的触发条件一致

未分类

【配置/Configuration】—>【动作/Actions】—>【创建动作/Create action】
定义告警的触发条件,以及告警默认信息,持续时间

未分类

未分类

Zabbix agent安装(源码包)

1、创建zabbix用户和组

# groupadd zabbix
# useradd -g zabbix zabbix -s /sbin/nologin

2、安装支持的类库

# yum -y install pcre*    //它是一个用C语言编写的正则表达式函数库

3、解压zabbix源码包并编译安装

# tar -xf zabbix-3.4.8.tar.gz
# cd /opt/zabbix-3.4.8
# ./configure --prefix=/usr/local/zabbix-agent --enable-agent
# make 
# make install

4、拷贝zabbix客户端启动脚本到/etc/init.d目录下

# cp misc/init.d/tru64/zabbix_agentd /etc/init.d/
# chmod +x /etc/init.d/zabbix_agentd

5、修改zabbix_agentd启动脚本

# vim /etc/init.d/zabbix_agentd

1)#!/bin/sh下面添加两行 #使其支持chkconfig配置服务

#chkconfig: 345 95 95
#description: Zabbix_Server

2)将DAEMON启动命令路径修改为安装时指定的路径。

DAEMON=/usr/local/sbin/zabbix_agentd      # 默认脚本启动服务的路径                

修改为:

DAEMON=/usr/local/zabbix-agent/sbin/zabbix_agentd     #安装时指定的路径

# 脚本启动服务的这个路径根据安装时指定的路径来设定;

6、设置zabbix_agentd服务开机启动

# chkconfig --add zabbix_agentd

# systemctl start zabbix_agentd       //启动zabbix
# systemctl status zabbix_agentd

# systemctl enable zabbix_agentd        //设置开机自启

7、编辑zabbix_agent配置文件

# egrep -v "^#|^$" /usr/local/zabbix-agent/etc/zabbix_agentd.conf
LogFile=/var/log/zabbix/zabbix_agentd.log
Server=10.103.1.191
ListenIP=10.103.1.170
ServerActive=10.103.1.191:10051
Hostname=Oracle-10-103-1-170

8、创建日志目录,并设置权限

# mkdir -p /var/log/zabbix

# chmod -R 755 /var/log/zabbix/
# chown -R zabbix. /var/log/zabbix/

# chmod -R 755 /usr/local/zabbix-agent/
# chown -R zabbix. /usr/local/zabbix-agent/

9、启动zabbix_agentd服务

# systemctl restart zabbix_agentd

10、查看zabbix_agentd服务是否启动成功

# netstat -nltp | grep zabbix
tcp        0      0 0.0.0.0:10050           0.0.0.0:*               LISTEN      65870/zabbix_agentd 
tcp        0      0 0.0.0.0:10051           0.0.0.0:*               LISTEN      53020/zabbix_server

到此,zabbix_agend端已安装完成!

Zabbix agent批量自动部署

废话:系统大批量上线时,我们一个个去装agent,有点枯燥,这里分享个expect结合上一篇《zabbix自动发现》,可以省不少工时。

准备工作:

1、下载客户端去吧https://www.zabbix.com/download_agents

2、跑脚本的主机192.168.2.100

1)下载的客户端放在了/opt下面
2)需要安装agent的(ip)和(passwd)信息,放在了ip_list.sh文件中

# vim /opt/ip_list.sh
192.168.2.1:123456
192.168.2.2:123456
192.168.2.3:123456
192.168.2.4:123456
192.168.2.5:123456

3)脚本agent_install.sh也放在了/opt下面

3、注意修改Zabbix Server IP、跑脚本的IP(我标红了)

环境信息:

  • 跑脚本的IP:192.168.2.100
  • Zabbix Server IP:192.168.2.201
  • agent安装路径:/usr/local/zabbix
  • agent日志:/tmp下面
  • 设置了开启启动
#!/bin/bash

# User:zgd
# https://www.zabbix.com/download_agents
# Install_URL:/usr/local/zabbix
# DATE:20180622
# Version:V2.3

rm -rf /root/.ssh/known_hosts
for i in {1..5}
do
 host=`sed -n "${i}p" /opt/ip_list.txt |awk -F ":" '{print $1}'`
 passwd=`sed -n "${i}p" /opt/ip_list.txt |awk -F ":" '{print $2}'`
  expect << EOF
  set timeout 300
  spawn ssh root@$host
  expect "yes/no" { send "yesr" }
  expect "password" { send "${passwd}r" }
  expect "#" { send "groupadd zabbixr" }
  expect "#" { send "useradd -g zabbix zabbix -s /sbin/nologinr" }
  expect "#" { send "mkdir /usr/local/zabbixr" }
  expect "#" { send "scp 192.168.2.100:/opt/zabbix_agents_3.2.0.linux2_6.amd64.tar.gz /usr/local/zabbixr" }
  expect "yes/no" { send "yesr" }
  expect "password" { send "123456r" }
  expect "#" { send  "cd /usr/local/zabbixr" }
  expect "#" { send "tar xf zabbix_agents_3.2.0.linux2_6.amd64.tar.gzr" }
  expect "#" { send "sed -i '91c Server=192.168.2.201' /usr/local/zabbix/conf/zabbix_agentd.confr" }
  expect "#" { send "sed -ri "/^Hostname/s/.*/Hostname=\${HOSTNAME%%.*}/" /usr/local/zabbix/conf/zabbix_agentd.confr" }
  expect "#" { send "/usr/local/zabbix/sbin/zabbix_agentd -c /usr/local/zabbix/conf/zabbix_agentd.confr" }
  expect "#" { send "chmod -R 755 /usr/local/zabbixr" }
  expect "#" { send "chown -R zabbix. /usr/local/zabbixr" }
  expect "#" { send "rm -rf /usr/local/zabbix/zabbix_agents_3.2.0.linux2_6.amd64.tar.gzr" }
  expect "#" { send "echo "/usr/local/zabbix/sbin/zabbix_agentd -c /usr/local/zabbix/conf/zabbix_agentd.conf" >> /etc/rc.localr" }
  expect "#" { send "exitr" }
EOF
done

配置多个ssh密钥对并且永久多ssh管理

这两天捣腾SSH,一直对其使用一知半解,由于要把博客迁移,弄来弄去发现还是部署到国内的coding吧
之前也弄过,但是由于重新安装了git-for-windows客户端,所以一开始用hexo d命令部署的时候报错了
趁着这次迁移也好好弄了一下本地的ssh管理,虽然还有些问题,但是至少比之前清晰一些了,这里也记录一下过程中遇到的问题

我的目的,将hexo生成的静态文件同时部署到github与coding上

安装git-for-windows客户端

下载地址 https://git-scm.com/download/win
无论是github还是coding都需要上传你的公钥,这两个地方可以上传相同的公钥,但也可以像我这样闲的蛋疼上传不同的公钥。

创建密钥对

使用ssh-keygen 来创建密钥对,命令为 ssh-keygen -t rsa -C “[email protected]”,其实这里-C 后面的email地址无所谓,可以随便写,只是为了你方便而已。
输入完该命令以后,首先会让你给密钥文件起个名字,这个是文件名,叫什么随心情

未分类

接下来让你输入密码,我这里直接回车,不用密码
然后它就会生成一个密钥对,像我这个设置就会生成yyxtest和yyxtest_pub两个文件,yyxtest.pub是公钥,谁都可以给,但是你私钥要自已保存好,谁拿到了你私钥就呵呵了。

上传公钥到github与coding中

根据github上的提示将公钥上传到github上你的个人账户中的ssh中

未分类

同样的操作再生成一对密钥,将公钥上传到coding中,注意我这里是为了测试,你完全没有必要重新生成,你当然可以上传刚才生成的yyxtest.pub这个公钥,当然后面会有一些问题,之后再详细说明。

上传文件到github上

赶紧上传个文件到github上试试吧(使用hexo d 来部署),其实你可以先不用上传文件,可以用ssh -vT [email protected] 来查看一下信息
这里你不用试了,肯定是不行的…… 抗都被我踩了

未分类

提示Permission denied,原因是你现在用的私钥还是id_rsa,并不是刚才生成的yyxtest,
ssh默认使用id_rsa,如果连id_rsa都没有,那你还不赶紧生成一个默认的。

添加yyxtest私钥到git bash中

根据github上的提示generate SSH keys 先将yyxtest添加到git bash中,
使用ssh-add ~/.ssh/yyxtest ,然后顺利提交代码成功,但是在提交文件到coding时又不行了,提示

Error: [email protected]: Permission denied (publickey).
fatal: Could not read from remote repository.

没办法,再用刚才的ssh-add 命令将用于coding的私钥也添加到git bash中,这次coding也可以提交了

配置ssh本地的config文件

试试关掉这个git bash,然后再试着用hexo d 提交一些文件,这次又不行了,还是提示Permission denied,这怎么能行,总不能每次提交更新都输入ssh-add 添加各种私钥吧,这时就要用到config这个文件了。
如果git安装是默认的话,将会把生成的公钥保存在C:Usersusername.ssh目录中(我用的是windows,不丢人),里面如果没有config文件,自已生成一个,里面写一些配置信息,各种字段说明如下

Host:代码托管平台的别名,但是这个别名和后面要用到的ssh链接 [email protected]:xxx/xxx.git 中的 @ 符号后面的内容要一致,而一般来说github默认提供的就是[email protected],因此为了方便,github的Host写github.com即可,别取别名了
HostName:代码托管平台真正的IP地址或域名,写域名就行,
IdentityFile:对应的密钥文件路径。必须写绝对路径,windows下可以写 C:Usersxxx.sshyyxtest
PreferredAuthentications:配置登录时用什么权限认证。可设为publickey,password publickey,keyboard-interactive等
User:对应的用户名。

我这里有两个私钥,所以我的配置文件如下

Host git.coding.net
    HostName git.coding.net
    IdentityFile C:Userskevin.sshrsa_coding
    PreferredAuthentications publickey
    User yangyanxing
Host github.com
    HostName github.com
    IdentityFile C:Userskevin.sshyyx
    PreferredAuthentications publickey
    User kevinkelin

之前说过,你没有必要为不同的网站生成不同的密钥,用同一份也可以,如果用同一份,这里IdentityFile也要写一样的
保存之后先不用着急提交,使用ssh -vT 查看一下连接是否有问题
github 提示 Hi kevinkelin! You’ve successfully authenticated, but GitHub does not provide shell access.
coding提示 yangyanxing,你好,你已经通过 SSH 协议认证 Coding.net 服务,这是一个个人公钥
这样就可以直接使用hexo d来提交文件更新了!

注意的问题

  • config文件中的host 配置是区分大小写的,github.com 和github.COM是不同的,一定要写对
  • coding的host是git.coding.net 而不是coding.net

遗留问题

git bash客户端,如果在非C盘上右键的方式启动,那么还是不行,它会寻找当前盘的中的.ssh目录,根本不存在的目录,所有找私钥肯定也找不到,只能先启动git bash,然后cd 到操作的目录中,这个我再研究研究怎么回事。