-
Notifications
You must be signed in to change notification settings - Fork 0
/
content.json
1 lines (1 loc) · 132 KB
/
content.json
1
{"meta":{"title":"Renqiang","subtitle":"码码工","description":"积土而为山,积水而为海。","author":"Renqiang","url":"https://renqiangme.github.io"},"pages":[{"title":"404 Not Found:该页无法显示","date":"2018-11-08T07:10:53.777Z","updated":"2018-11-06T13:28:44.000Z","comments":false,"path":"/404.html","permalink":"https://renqiangme.github.io//404.html","excerpt":"","text":""},{"title":"About","date":"2019-03-18T05:56:38.778Z","updated":"2019-03-18T05:56:38.777Z","comments":true,"path":"about/index.html","permalink":"https://renqiangme.github.io/about/index.html","excerpt":"","text":"Hi,我是一个做后端开发的程序猿,此博客是基于Hexo构建和Git pages部署,希望通过此博客记录:工作中的遇到的问题、学习笔记,生活感悟,博客中的内容可能有不对或者粗糙之处,欢迎指出。 123456789101112131415161718192021{ name: 'Renqiang' gender: '男', profession: 'JAVA后端开发工程师', experience: '4年', address: '广东省深圳市', education: '本科', github: 'https://github.com/Renqiangme', blog: 'https://renqiangme.github.io', email: 'renqiangme@qq.com', skills: [ ['Html', 'Javascript', 'jQuery', 'CSS', 'ES6', 'Node','Bootstrap','React'], ['Git', 'SVN'], ['PHP','ThinkPHP','Yii','Yaf','Swoole'], ['Java', 'SSM', 'SpringBoot','SpringCloud'], ['Redis','MySQL','MongoDB','Kafka', 'Storm'], ['Linux','Shell','Docker'] ]}"},{"title":"categories","date":"2019-03-18T04:28:53.051Z","updated":"2019-03-18T04:28:53.050Z","comments":true,"path":"categories/index.html","permalink":"https://renqiangme.github.io/categories/index.html","excerpt":"","text":""},{"title":"tags","date":"2019-03-18T04:29:12.452Z","updated":"2019-03-18T04:29:12.451Z","comments":true,"path":"tags/index.html","permalink":"https://renqiangme.github.io/tags/index.html","excerpt":"","text":""}],"posts":[{"title":"Mac下IDEA部分快捷键","slug":"Mac下IDEA部分快捷键","date":"2019-04-27T02:17:05.000Z","updated":"2019-04-27T02:25:09.841Z","comments":true,"path":"2019/04/27/Mac下IDEA部分快捷键/","link":"","permalink":"https://renqiangme.github.io/2019/04/27/Mac下IDEA部分快捷键/","excerpt":"","text":"编辑 ⌥↩︎ ,option键+Enter键,自动导入类,每按一次自动导入一个类,需要结合F2来自动跳动到没有导入该类的那一行,如何有多个类会弹出框供选择。 ⌘P ,command键+P,显示方法的参数信息 ⌃J ,control键+J,快速查看当前所选类、方法的文档 ⌘N, command键+N,弹出生成代码(getter、setter、构造函数、hashCode/equals,toString) ⌃O ,control键+O,覆盖方法(重写父类方法) ⌃I ,control键+I,实现方法(实现接口中的方法) ⌘⌥T ,command键+option键+T,包围代码(使用if..else, try..catch, for, synchronized等包围选中的代码) ⌘/ ,command键+/,注释/取消注释与行注释 ⌘⌥/ ,command键+option键+/,注释/取消注释与块注释 ⌥↑ ,option键+上箭头键,连续选中代码块 ⌥↓ ,option键+下箭头键,减少当前选中的代码块 ⇥ / ⇧⇥ ,按右制表符缩进代码 / shift+右制表符反缩进代码 ⌘⌥L ,command键+option键+L,格式化代码 ⌃⌥O ,control键+option键+O,优化import,比如属于同一个包的引入进来的类不是挨着的,使用这个优化之后会让他们挨着一起。 ⌘X ,command键+X,剪切当前行或选定的块到剪贴板 ⌘C ,command键+C,复制当前行或选定的块到剪贴板 ⌘V ,command键+V,从剪贴板粘贴 ⌘⇧V ,command键+shift键+V,从最近的缓冲区粘贴 ⌘D ,command键+D,复制当前行或选定的块 ⌘⌫ ,command键+删除键,删除当前行或选定的块的行 ⇧↩ ,shift键+回车键,开始新的一行 ⌘+ / ⌘- ,command键 + +键,展开 / ,command键 + -键,折叠代码块 ⌘⇧+ ,command键 + shift + +键,展开所以代码块 ⌘⇧- ,command键 + shift + -键,折叠所有代码块 查询/替换 ⌘F ,command键 + F,在文件内查找,比如搜索hello,在当前文件中找到了五个hello,可以通过上下方向箭头来向上或向下。 ⌘R ,command键 + R,在文件内替换。 ⌘⇧F ,command键 + shift + F,全局查找 ⌘⇧R ,command键 + shift + R,全局替换 编译和运行 ⌃⌥R ,control键 + option键+ R,弹出 Run 的可选择菜单 ⌃⌥D ,control键 + option键+ D,弹出 Debug 的可选择菜单 ⌃R ,control键 + R,运行 ⌃D ,control键 + D,运行调试 Debug调试 F8 进入下一步,如果当前行断点是一个方法,则不进入当前方法体内。 F7 进入下一步,如果当前行断点是一个方法,则进入当前方法体内,如果该方法体还有方法,则不会进入该内嵌的方法中。 ⇧F7 ,shift键 + F7,智能步入,断点所在行上有多个方法调用,会弹出进入哪个方法。 ⇧F8 ,shift键 + F8,跳出 ⌥F9 ,option键 + F9,运行到光标处,如果光标前有其他断点会进入到该断点 ⌥F8 ,option键 + F8,计算表达式(可以更改变量值使其生效) ⌘⌥R ,command键+option键 + R,恢复程序运行,如果该断点下面代码还有断点则停在下一个断点上 ⌘F8 ,command键+ F8,切换断点(若光标当前行有断点则取消断点,没有则加上断点) ⌘⇧F8 ,command键 + shift键 + F8,查看断点信息 Navigation(导航) ⌘O ,command键 + 字母o,查找类文件 ⌘⇧O ,command键 +shift键+ 字母o,查找所有类型文件、打开文件、打开目录,打开目录需要在输入的内容前面或后面加一个反斜杠/ ⌘⌥O ,command键 + option键+ 字母o,前往指定的变量或方法 ⌘L 在当前文件跳转到某一行的指定处,会弹出一个框来输入行号,跟vim里面的:xxline作用一样。 ⌘F12 ,command键 + F12,弹出当前文件结构层,可以在弹出的层上直接输入进行筛选(可用于搜索类中的方法) ⌃H ,command键 + H,显示当前类的层次结构 ⌘⇧H ,command键 +shift+ H,显示方法层次结构 ⌃⌥H ,command键 +option+ H,显示调用层次结构 Refactor重构 F5 复制文件到指定目录 F6 移动文件到指定目录 ⇧F6 ,shift键+ F6,选择当前文件类名,会弹出重命名文件 General通用 ⌘1…⌘9 ,command键+ 1…9,打开相应编号的工具窗口 ⌃⌘F ,control键+command键+F,切换全屏模式 ⌘, ,command键+, 打开IDEA系统设置 ⌘; ,command键+; 打开项目结构对话框","categories":[{"name":"开发工具","slug":"开发工具","permalink":"https://renqiangme.github.io/categories/开发工具/"}],"tags":[{"name":"IDEA","slug":"IDEA","permalink":"https://renqiangme.github.io/tags/IDEA/"}]},{"title":"kubernetes的kubeconfig配置文件及contexts切换","slug":"kubernetes的kubeconfig配置文件及contexts切换","date":"2019-04-24T04:18:19.000Z","updated":"2019-04-24T04:20:34.712Z","comments":true,"path":"2019/04/24/kubernetes的kubeconfig配置文件及contexts切换/","link":"","permalink":"https://renqiangme.github.io/2019/04/24/kubernetes的kubeconfig配置文件及contexts切换/","excerpt":"","text":"KubeconfigKubernetes的kubeconfig配置文件用于使用kubectl CLI,并允许您通过kubeconfig配置文件远程连接,控制群集。kubeconfig配置文件是存储在每个群集的kubectl-configs中。 基本用法要将kubectl与没有任何配置的集群一起使用,只需使用--kubeconfig选项。 1kubectl --kubeconfig kubectl-configs/<config-file> get pods 高级用法为每个命令手动指定配置文件可能会有的麻烦。 可以将KUBECONFIG环境变量设置为以下格式的配置文件列表:config-1:config-2:config-3 现在,所有文件都已合并,您可以通过上下文在它们之间切换。 例如:12345678# 显示当前使用的contextkubectl config current-context# 比如切换到使用aliyun-k8s,就会本地kubectl cli连接到aliyun-k8s集群kubectl config use-context aliyun-k8s# 显示aliyun-k8s集群的podskubectl get pods 更多命令可以通过kubectl config --help 查看。 通常情况下,我们本地开发机器会搭建kubernets,同时本地的测试机器环境也会搭建kubernets,线上也会搭建很多个kubernets集群环境。 因为kubernets去读取context的时候,如果设置了全局环境变量KUBECONFIG,他就会优先使用这个全局环境变量对应的配置文件,如果没有设置就会去找$HOME/.kube/config 这个配置文件。 如果需要在本地管理连接这些kubernets,那么可以把对应的kubernets的配置文件:$HOME/.kube/config 导出来,下载导本地,再跟本地的配置文件合并。 以本地测试机器为例子:12345678910111213141516171819202122232425#登录到测试机器,导出配置文件kubectl config view --raw > office-test.conf# 下载office-test.conf到本地电脑,然后修改环境变量配置文件,比如:vim ~/.bash_profileexport KUBECONFIG=/Users/xx/.kube/office-test.conf:/Users/xx/.kube/config# 更新环境变量文件source ~/.bash_profile# 新开一个命令行终端,执行导入合并文件kubectl config view --raw > combined.conf# 注释掉KUBECONFIG这个环境变量并source更新,然后再把combined.conf复制到$HOME/.kube/config`#可以看到最新的合并了的contextskubectl config get-contexts#切换context为 office-testkubectl config set-context office-test#获取对应的pods,校验是否切换连接成功kubectl get pods","categories":[{"name":"Linux","slug":"Linux","permalink":"https://renqiangme.github.io/categories/Linux/"}],"tags":[{"name":"Kubernetes","slug":"Kubernetes","permalink":"https://renqiangme.github.io/tags/Kubernetes/"},{"name":"k8s","slug":"k8s","permalink":"https://renqiangme.github.io/tags/k8s/"}]},{"title":"安装kubernetes-dashboard","slug":"安装kubernetes-dashboard","date":"2019-04-24T04:15:23.000Z","updated":"2019-04-24T04:20:54.133Z","comments":true,"path":"2019/04/24/安装kubernetes-dashboard/","link":"","permalink":"https://renqiangme.github.io/2019/04/24/安装kubernetes-dashboard/","excerpt":"","text":"kubernetes Dashboard作为Kubernetes的Web用户界面,用户可以通过Dashboard在Kubernetes集群中部署容器化的应用,对应用进行问题处理和管理,并对集群本身进行管理。通过Dashboard,用户可以查看集群中应用的运行情况,同时也能够基于Dashboard创建或修改部署、任务、服务等Kubernetes的资源。通过部署向导,用户能够对部署进行扩缩容,进行滚动更新、重启Pod和部署新应用。当然,通过Dashboard也能够查看Kubernetes资源的状态。 Kubernetes Dashboard Github地址 安装1kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v1.10.1/src/deploy/recommended/kubernetes-dashboard.yaml 安装部署成功之后执行: 1kubectl proxy 打开:http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/#!/login就可以通过UI来管理了。 kubernetes Dashboard访问权限问题现在新版的kubernetes Dashboard似乎都没有了跳过这个button. 点击跳过进入dashboard 使用的是默认的 kubernetes-dashboard 角色,比如Azure的AKS就是直接没有登录界面,直接进入主页。可能有很多黄色警告:12345678configmaps is forbidden: User "system:serviceaccount:kube-system:kubernetes-dashboard" cannot list configmaps in the namespace "default"persistentvolumeclaims is forbidden: User "system:serviceaccount:kube-system:kubernetes-dashboard" cannot list persistentvolumeclaims in the namespace "default"secrets is forbidden: User "system:serviceaccount:kube-system:kubernetes-dashboard" cannot list secrets in the namespace "default"services is forbidden: User "system:serviceaccount:kube-system:kubernetes-dashboard" cannot list services in the namespace "default".... 说明 kubernetes-dashboard权限不足。 法一:创建一个管理员权限的用户,生成Token访问dashboard参考自:Creating-sample-user 创建一个管理员Service Account文件在本地创建一个dashboard-adminuser.yaml,内容是: 123456789101112131415161718apiVersion: v1kind: ServiceAccountmetadata: name: admin-user namespace: kube-system---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata: name: admin-userroleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-adminsubjects:- kind: ServiceAccount name: admin-user namespace: kube-system 然后执行: 1kubectl apply -f dashboard-adminuser.yaml 生成Bearer Token1kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep admin-user | awk '{print $1}') 然后复制粘贴token,就能进入kubernetes Dashboard的管理界面了。 查看所有的ServiceAccount1kubectl get serviceaccount --all-namespaces 法二:也可以把kubernetes-dashboard 用户的权限绑定成 admin 的权限直接执行下面命令:1kubectl create clusterrolebinding kubernetes-dashboard -n kube-system --clusterrole=cluster-admin --serviceaccount=kube-system:kubernetes-dashboard 或者创建一个文件然后再create: vi kube-dashboard-access.yaml 1234567891011121314apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata: name: kubernetes-dashboard labels: k8s-app: kubernetes-dashboardroleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-adminsubjects:- kind: ServiceAccount name: kubernetes-dashboard namespace: kube-system 1kubectl create -f kube-dashboard-access.yaml","categories":[{"name":"Linux","slug":"Linux","permalink":"https://renqiangme.github.io/categories/Linux/"}],"tags":[{"name":"Kubernetes","slug":"Kubernetes","permalink":"https://renqiangme.github.io/tags/Kubernetes/"},{"name":"k8s","slug":"k8s","permalink":"https://renqiangme.github.io/tags/k8s/"},{"name":"kubernetes-dashboard","slug":"kubernetes-dashboard","permalink":"https://renqiangme.github.io/tags/kubernetes-dashboard/"}]},{"title":"kubernetes简单安装笔记","slug":"kubernetes简单安装笔记","date":"2019-04-24T04:13:48.000Z","updated":"2019-04-24T04:20:28.422Z","comments":true,"path":"2019/04/24/kubernetes简单安装笔记/","link":"","permalink":"https://renqiangme.github.io/2019/04/24/kubernetes简单安装笔记/","excerpt":"","text":"安装Kubernetes线上的云环境我们可以使用云平台的Kubernetes Service来管理部署我们的服务。 本地开发测试环境:Linux系统(单个节点Kubernetes)可以通过 microk8s可以非常快速的搭建起一个 Kubernetes 单机环境,安装极其非常方便。ubuntu 自带 snap 命令,可以直接执行,centos 需要先安装 snap。 centos安装 snap123456789yum copr enable ngompa/snapcore-el7yum -y install snapdyum copr enable ngompa/snapcore-el7yum install epel-releaseyum install yum-plugin-copryum copr enable ngompa/snapcore-el7yum -y install snapdsystemctl enable --now snapd.socketln -s /var/lib/snapd/snap /snap snap安装Kubernetes1234snap install microk8s --classic#开启 DNS 服务microk8s.enable dns dashboard microk8s 常用操作1234567891011121314151617181920212223# 1. 启动 microk8s.start# 2. 关闭microk8s.stop# 3. 状态microk8s.status# 4. kubectl 操作# 查看 clustermicrok8s.kubectl cluster-info# 查看 nodesmicrok8s.kubectl get nodes# 查看 podsmicrok8s.kubectl get pods# docker 操作microk8s.docker psmicrok8s.docker images 为microk8s.kubectl取别名可以看到,在 microk8s 环境中执行 kubectl 时,需要在 kubectl 命令前添加前缀 microk8s.。为了跟其他系统环境统一我们可以取个别名kubectl 1snap alias microk8s.kubectl kubectl 查看节点和集群信息使用 kubectl get -h 可以看到更多关于kubectl get的用法,下面列举查看用得比较多的指令: 查看node信息: kubectl get nodes 查看services信息: kubectl get services 查看deployment信息: kubectl get deployments 查看pod信息: kubectl get pods 执行kubectl get nodes可以看到只会有1个master节点。12345678910111213$ kubectl get nodesNAME STATUS ROLES AGE VERSIONdocker-for-desktop Ready master 1d v1.10.11$ kubectl get servicesNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEkubernetes ClusterIP 10.96.0.1 <none> 443/TCP 1d$ kubectl get deploymentsNo resources found.$ kubectl get podsNo resources found. 因为是本地运行minikube,所以只会有一个主节点,这个以后也不会改变,默认会有一个名为kubernetes的服务,注意其类型是 ClusterIP ,只能从集群内部访问,且其访问端口为443,而真正的部署和pod(类似于容器)现在都还是空的. Linux系统(多个节点Kubernetes)我们也可以使用kubeadm 来安装k8s集群,可以参照官方文档一步一步安装。 安装完成之后,多个节点,执行kubectl get nodes可以看到会有多个节点。 1234567$ kubectl get nodesNAME STATUS ROLES AGE VERSIONk8s-2-master-01 Ready master 34d v1.13.4k8s-2-node-02 Ready <none> 34d v1.13.4k8s-2-node-03 Ready <none> 34d v1.13.4k8s-2-node-04 Ready <none> 33d v1.13.4 Mac / windows系统可以使用Minikube,最新版的docker for mac已经自带了。界面可视化安装,就不写步骤了。","categories":[{"name":"Linux","slug":"Linux","permalink":"https://renqiangme.github.io/categories/Linux/"}],"tags":[{"name":"Kubernetes","slug":"Kubernetes","permalink":"https://renqiangme.github.io/tags/Kubernetes/"},{"name":"k8s","slug":"k8s","permalink":"https://renqiangme.github.io/tags/k8s/"}]},{"title":"Linux设置Swap交换分区","slug":"Linux设置Swap交换分区","date":"2018-08-21T05:12:51.000Z","updated":"2019-03-18T04:49:17.638Z","comments":true,"path":"2018/08/21/Linux设置Swap交换分区/","link":"","permalink":"https://renqiangme.github.io/2018/08/21/Linux设置Swap交换分区/","excerpt":"有时,服务器上面程序跑多了,受限于内存不够,会出现程序被kill掉或者起不来的情况。 这个时候我们可以设置下Swap(交换分区)。Swap(交换分区),类似于 Windows 的虚拟内存,就是当内存不足的时候,把一部分硬盘空间虚拟成内存使用,从而解决内存容量不足的情况。","text":"有时,服务器上面程序跑多了,受限于内存不够,会出现程序被kill掉或者起不来的情况。 这个时候我们可以设置下Swap(交换分区)。Swap(交换分区),类似于 Windows 的虚拟内存,就是当内存不足的时候,把一部分硬盘空间虚拟成内存使用,从而解决内存容量不足的情况。 1.检查 Swap 空间在设置 Swap 文件之前,有必要先检查一下系统里有没有既存的 Swap 文件。 运行命令:1swapon -s 如果返回的信息概要是空的,则表示 Swap 文件不存在。 然后我们还需要检查下需要把Swap(交换分区)设置的那个目录所在的磁盘是否还有剩余空间,可以使用:df -lh 2.创建 Swap 文件1dd if=/dev/zero of=/tmp/swapfile bs=1024 count=1024k 这样就建立一个/tmp/swapfile的分区文件,大小为1G。 参数解读:1234if=文件名:输入文件名,缺省为标准输入。即指定源文件。< if=input file >of=文件名:输出文件名,缺省为标准输出。即指定目的文件。< of=output file >bs=bytes:同时设置读入/输出的块大小为bytes个字节count=blocks:仅拷贝blocks个块,块大小等于bs指定的字节数。 3.格式化并激活 Swap 文件创建好 Swap 文件,还需要格式化后才能使用。运行命令: 1mkswap /tmp/swapfile 激活 Swap ,运行命令:1swapon /tmp/swapfile 如果以上在空间足够的情况下,应该就成功了,可以运行命令:swapon -s 或者 free -m 检查下。 如果要机器重启的时候自动挂载 Swap ,那么还需要修改 fstab 配置。 用 vim 打开 /etc/fstab 文件,在其最后添加如下一行:1/tmp/swapfile swap swap defaults 0 0 赋予 Swap 文件适当的权限:12chown root:root /tmp/swapfile chmod 600 /tmp/swapfile 4.修改swappiness同时,我们还可以修改 Linux Swap 空间的 swappiness ,调整对硬盘的缓存。 Linux会使用硬盘的一部分做为 Swap 分区,用来进行进程调度–进程是正在运行的程序–把当前不用的进程调成等待(standby),甚至睡眠(sleep),一旦要用,再调成活动(active),睡眠的进程就会在 Swap 分区,把内存空出来让给活动的进程。 如果内存够大,应当告诉 Linux 不必太多的使用 Swap 分区,可以通过修改 swappiness 的参数来设置。swappiness=0 的时候表示最大限度使用物理内存,然后才是 Swap 空间,swappiness=100 的时候表示积极的使用 Swap 分区,并且把内存上的数据及时的搬运到 Swap 空间里面。 一般swappiness 的默认值是60。 通过以下命令可以查看swappiness的值:1cat /proc/sys/vm/swappiness 使用 sysctl 临时性的修改,重启系统会恢复成系统默认,命令:1sysctl vm.swappiness=10 永久设置,还需要vi /etc/sysctl.conf,在这个文档的最后加上这样一行:1vm.swappiness=10 #可以是其他值,:wq保存后Swap分区在系统重启后都会生效了 其他,删除某swap分区a.先停止正在使用swap分区:1swapoff /tmp/swapfile b. 删除swap分区文件1rm -rf /tmp/swapfile c.删除掉我们之前在fstab文件里追加的开机自动挂载配置内容:1/tmp/swapfile swap swap defaults 0 0","categories":[{"name":"Linux","slug":"Linux","permalink":"https://renqiangme.github.io/categories/Linux/"}],"tags":[{"name":"Linux","slug":"Linux","permalink":"https://renqiangme.github.io/tags/Linux/"},{"name":"Swap","slug":"Swap","permalink":"https://renqiangme.github.io/tags/Swap/"}]},{"title":"给MongoDB新增一个readWriteAnyDatabase的角色账户","slug":"给MongoDB新增一个readWriteAnyDatabase的角色账户","date":"2018-05-01T09:18:01.000Z","updated":"2019-03-18T04:48:54.833Z","comments":true,"path":"2018/05/01/给MongoDB新增一个readWriteAnyDatabase的角色账户/","link":"","permalink":"https://renqiangme.github.io/2018/05/01/给MongoDB新增一个readWriteAnyDatabase的角色账户/","excerpt":"安装好MongoDB时,通常开了一个最高管理权限的root账户来方便我们管理数据库,实际开发中并一般不使用这个账户,我们可以单独添加一个账户来连接数据库。","text":"安装好MongoDB时,通常开了一个最高管理权限的root账户来方便我们管理数据库,实际开发中并一般不使用这个账户,我们可以单独添加一个账户来连接数据库。 MongoDB的账户角色:数据库用户角色:read、readWrite 数据库管理角色:dbAdmin、dbOwner、userAdmin 集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManage 备份恢复角色:backup、restore 所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase 超级用户角色:root 内部角色:__system Read:允许用户读取指定数据库 readWrite:允许用户读写指定数据库 dbAdmin:允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问system.profile userAdmin:允许用户向system.users集合写入,可以在指定数据库里创建、删除和管理用户 clusterAdmin:只在admin数据库中可用,赋予用户所有分片和复制集相关函数的管理权限。 readAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读权限 readWriteAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读写权限 userAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的userAdmin权限 dbAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的dbAdmin权限。 root:只在admin数据库中可用。超级账号,超级权限 新增一个readWriteAnyDatabase的角色账户12345678910111213141516171819202122#以root登录(这个root的角色是userAdminAnyDatabase)./mongo --port 27017 -u "root" -p "xxx" --authenticationDatabase "admin" #切换到admin dbuse admin#查看所有用户db.system.users.find()#新增用户,并授予readWriteAnyDatabase的角色db.createUser({user:"mongodb-admin",pwd:"123456",roles:[{role:"readWriteAnyDatabase", db:"admin"}]})#新增xxxx角色#db.grantRolesToUser("mongodb-admin",[{role:"xxx",db:"admin"}])#以mongodb-admin登录mongo --port 27017 -u mongodb-admin -p '123456' --authenticationDatabase 'admin'#测试创建集合和查询,如果没有报错,说明权限已经okuse testdb.createCollection("Account")db.Account.find()","categories":[{"name":"MongoDB","slug":"MongoDB","permalink":"https://renqiangme.github.io/categories/MongoDB/"}],"tags":[{"name":"MongoDB","slug":"MongoDB","permalink":"https://renqiangme.github.io/tags/MongoDB/"}]},{"title":"使用Systemd部署管理SpringBoot应用","slug":"使用System部署SpringBoot应用","date":"2018-04-17T05:28:12.000Z","updated":"2019-04-24T10:03:15.321Z","comments":true,"path":"2018/04/17/使用System部署SpringBoot应用/","link":"","permalink":"https://renqiangme.github.io/2018/04/17/使用System部署SpringBoot应用/","excerpt":"如果不使用Docker和Kubernets部署管理SpringBoot应用,可以选择Systemd。 因为SpringBoot自带Tomcat之类的Web应用服务器,可以直接java -jar xxx.jar的方式启动起来。 如果我们直接使用nohup java -jar xxx.jar & 之类的虽然也可以实现后台运行,但是是有可能因为某些原因挂掉的,所以我们需要找到一种工具让应用可以重启或者开机启动。 我们可以使用Python的Supervisor,也有盆友说可以使用Node的pm2,但是我一般都是选择Systemd,现在Linux系统都是自带这个的。","text":"如果不使用Docker和Kubernets部署管理SpringBoot应用,可以选择Systemd。 因为SpringBoot自带Tomcat之类的Web应用服务器,可以直接java -jar xxx.jar的方式启动起来。 如果我们直接使用nohup java -jar xxx.jar & 之类的虽然也可以实现后台运行,但是是有可能因为某些原因挂掉的,所以我们需要找到一种工具让应用可以重启或者开机启动。 我们可以使用Python的Supervisor,也有盆友说可以使用Node的pm2,但是我一般都是选择Systemd,现在Linux系统都是自带这个的。 步骤生成jar包:进入到SpringBoot项目的目录,然后执行:mvn clean package,找到target目录里面的jar包。 上传jar包:scp -P xx_port xxx.jar username@host:./ SSH登录进入服务器之后,首先需要安装JDK,然后把jar包复制到/home/www/applications 在/etc/systemd/system/目录下面新建一个service的配置,配置内容参考: 1234567891011121314[Unit]Description=service-testAfter=syslog.target[Service]User=rootWorkingDirectory=/home/www/applicationsRestart=alwaysExecStart=/usr/local/jdk1.8.0_161/bin/java -jar /home/www/applications/service-test-1.0.jarExecStop=/usr/bin/kill -15 $MAINPIDSuccessExitStatus=143[Install]WantedBy=multi-user.target 新增一个新的service之后,需要让配置生效,如果修改配置文件,需要reload。 使xx service生效:systemctl enable xx.service 刷新配置:systemctl daemon-reload 启动xx service: systemctl start xx.service 查看xx service的status: systemctl status xx.service 重启xx service: systemctl restart xx.service 看xx service日志,按住shift+g可以跳转到最后一行: journalctl -u xx.service 动态像tail -f xxfile一样查看对应service的日志: journalctl -f xx.service","categories":[{"name":"JAVA","slug":"JAVA","permalink":"https://renqiangme.github.io/categories/JAVA/"}],"tags":[{"name":"JAVA","slug":"JAVA","permalink":"https://renqiangme.github.io/tags/JAVA/"},{"name":"SpringBoot","slug":"SpringBoot","permalink":"https://renqiangme.github.io/tags/SpringBoot/"},{"name":"Systemd","slug":"Systemd","permalink":"https://renqiangme.github.io/tags/Systemd/"}]},{"title":"Log4j2日志->Kafka->LogStash->ElasticSearch并邮件报警","slug":"Log4j2日志->Kafka->Logstash->Elasticsearch并邮件报警","date":"2018-01-21T11:08:28.000Z","updated":"2019-03-29T06:38:57.810Z","comments":true,"path":"2018/01/21/Log4j2日志->Kafka->Logstash->Elasticsearch并邮件报警/","link":"","permalink":"https://renqiangme.github.io/2018/01/21/Log4j2日志->Kafka->Logstash->Elasticsearch并邮件报警/","excerpt":"SpringBoot项目中需要把日志记录到:ElasticSearch 并使用 :Kibana 搜索、展示、查看日志。 修改SpringBoot中的配置因为SpringBoot默认使用的日志框架是::Logback,但是:Log4j2 性能可能更高就打算替换掉。","text":"SpringBoot项目中需要把日志记录到:ElasticSearch 并使用 :Kibana 搜索、展示、查看日志。 修改SpringBoot中的配置因为SpringBoot默认使用的日志框架是::Logback,但是:Log4j2 性能可能更高就打算替换掉。 替换方法,修改项目maven的pom.xml配置文件: 1234567891011121314<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId></dependency> 因为需要把日志记录到Kafka,所以引入org.apache.kafka kafka-clients到项目中: 12345<dependency> <groupId>org.apache.kafka</groupId> <artifactId>kafka-clients</artifactId> <version>0.10.0.0</version></dependency> 因为日志在本地测试和线上的kafka的服务器需要分开,通常我们可以在resources目录下面创建: 本地的log4j2的配置文件名叫log4j2-dev.xml 正式线上的log4j2的配置文件名叫log4j2-prd.xml 然后我们可以修改SpringBoot的bootstrap.properties,ACTIVE_ENVIRONMENT为环境变量。12spring.profiles.active=${ACTIVE_ENVIRONMENT:dev}logging.config=classpath:log4j2-${ACTIVE_ENVIRONMENT}.xml log4j2-xxx.xml的内容例子如下:12345678910111213141516171819202122232425262728293031<?xml version="1.0" encoding="UTF-8"?><Configuration status="warn"> <Properties> </Properties> <Appenders> <Console name="STDOUT" target="SYSTEM_OUT"> <PatternLayout pattern="%d %p %c{1.} %t %m%n"/> </Console> <Kafka name="KAFKA-LOGGER" topic="service-logs-test"><!--kafka topic--> <JsonLayout/> <!--JsonLayout:日志格式为json,方便在Elastic中处理--> <Property name="bootstrap.servers">10.2.200.26:9092</Property><!--kafka server的ip:port--> <Property name ="retries" >3</Property> <Property name ="linger.ms" >1000</Property> <Property name ="buffer.memory" > 10485760</Property> </Kafka> <Async name="ASYNC-KAFKA-LOGGER"> <AppenderRef ref="KAFKA-LOGGER"/> <LinkedTransferQueue/> </Async> </Appenders> <Loggers> <logger name="demo.xx.com.test" level="info" additivity="false"><!--日志级别大于info都会被记录到Kafka--> <AppenderRef ref="KAFKA-LOGGER"/> </logger> <!-- Root表示所有Logger用Root中的Appender打印日志 --> <Root level="info"> <AppenderRef ref="STDOUT"/> <AppenderRef ref="ASYNC-KAFKA-LOGGER"/> </Root> </Loggers></Configuration> 在LogStash中的配置LogStash组成结构:Logstash 通过管道进行运作,管道有两个必需的元素,输入和输出,还有一个可选的元素,过滤器。输入插件从数据源获取数据,过滤器插件根据用户指定的数据格式修改数据,输出插件则将数据写入到目的地。因此,需要一个配置文件管理输入、过滤器和输出相关的配置。配置文件内容格式如下:1234567891011121314# 输入input { ...}# 过滤器filter { ...}# 输出output { ...} 所以我们创建一个文件到LogStash的配置文件:logstash.yml中path.config配置的扫描目录。 service-logs.conf配置文件内容如下: 1234567891011121314151617181920212223242526272829303132333435363738394041input { kafka { topics_pattern => ["service-logs-.*"] bootstrap_servers => "10.1.220.27:9092" group_id => "local-logstash" decorate_events => true }}filter { json { source => "message" } mutate { add_field => { "kafka_topic" => "%{[@metadata][kafka][topic]}" "kafka_consumer_group" => "%{[@metadata][kafka][consumer_group]}" "kafka_partition" => "%{[@metadata][kafka][partition]}" "kafka_offset" => "%{[@metadata][kafka][offset]}" "kafka_timestamp" => "%{[@metadata][kafka][timestamp]}" } }}output { if [level] == "ERROR" { http { url => "http://localhost:8088/send/mail" http_method => "post" automatic_retries => 0 connect_timeout => 6 keepalive => false } } elasticsearch { hosts => ["127.0.0.1:9200"] action => "index" index => "logstash-%{[kafka_topic]}" }} 我们可以看到上面output针对日志级别是ERROR的会发送一个HTTP请求到一个发邮件的服务器,因为LogStash自带的邮件发不出来,所以单独用了nodejs写了一个发邮件接口。 如果使用LogStash自带的配置如下: 1234567891011121314151617181920output { if [level] == "ERROR" { email { debug => true to => "xx@qq.com" from => "xxx@126.com" subject => 'Alert - Error' codec => "plain" contenttype => "text/html; charset=UTF-8" body => "Tags: %{tags}\\\\n\\\\Content:\\\\n%{message}" username => "xxx@126.com" password => "xxx" address => "smtp.126.com" domain => "smtp.126.com" port => 25 use_tls => false via => "smtp" } } } LogStash的功能很强大,更多可以阅读官方的文档。","categories":[{"name":"JAVA","slug":"JAVA","permalink":"https://renqiangme.github.io/categories/JAVA/"}],"tags":[{"name":"JAVA","slug":"JAVA","permalink":"https://renqiangme.github.io/tags/JAVA/"},{"name":"Kafka","slug":"Kafka","permalink":"https://renqiangme.github.io/tags/Kafka/"},{"name":"LogStash","slug":"LogStash","permalink":"https://renqiangme.github.io/tags/LogStash/"},{"name":"ElasticSearch","slug":"ElasticSearch","permalink":"https://renqiangme.github.io/tags/ElasticSearch/"}]},{"title":"Git的一些操作记录","slug":"Git的一些操作记录","date":"2018-01-12T01:30:28.000Z","updated":"2019-03-18T04:47:46.288Z","comments":true,"path":"2018/01/12/Git的一些操作记录/","link":"","permalink":"https://renqiangme.github.io/2018/01/12/Git的一些操作记录/","excerpt":"Git撤销某个commit12345678git reset –mixed:此为默认方式,不带任何参数的git reset,即时这种方式,它回退到某个版本,只保留源码,同时清空了暂存区(回退commit和index信息)git reset –soft:回退到某个版本,只回退了commit的信息,git不会清除你的暂存区。如果还要提交,直接commit即可git reset –hard:彻底回退到某个版本,直接覆盖工作区,暂存区,本地的源码所有的内容也会变为上一个版本的内容Git撤销命令后面的可选参数:HEAD 最近一个提交HEAD^ 上一次<commit_id> 每次commit的SHA1值. 可以用git log 看到,也可以在页面上commit标签页里找到","text":"Git撤销某个commit12345678git reset –mixed:此为默认方式,不带任何参数的git reset,即时这种方式,它回退到某个版本,只保留源码,同时清空了暂存区(回退commit和index信息)git reset –soft:回退到某个版本,只回退了commit的信息,git不会清除你的暂存区。如果还要提交,直接commit即可git reset –hard:彻底回退到某个版本,直接覆盖工作区,暂存区,本地的源码所有的内容也会变为上一个版本的内容Git撤销命令后面的可选参数:HEAD 最近一个提交HEAD^ 上一次<commit_id> 每次commit的SHA1值. 可以用git log 看到,也可以在页面上commit标签页里找到 如果本地的源码彻底回退到某个版本,并希望远程Git仓库的记录也回滚的话。 12git reset --hard <commit_id>git push origin HEAD --force 如果本地的源码彻底回退到某个版本,又想回滚到回滚前的某个版本。 1git reflog git reflog 可以查看所有分支的所有操作记录(包括commit和reset的操作),包括已经被删除的commit记录,git log则不能察看已经删除了的commit记录。 修改Git使用的远程仓库三种方式: 1:修改命令 git remte origin set-url url 2:先删后加 git remote rm origin && git remote add origin url 3:直接修改文件: .git/config 打包出Git两个commit之间提交过的文件1git diff xxx xxx --name-only | xargs tar -cvzf update.tar.gz","categories":[{"name":"Git","slug":"Git","permalink":"https://renqiangme.github.io/categories/Git/"}],"tags":[{"name":"Git","slug":"Git","permalink":"https://renqiangme.github.io/tags/Git/"}]},{"title":"Ubuntu安装Elastic Stack","slug":"Ubuntu安装Elastic Stack","date":"2018-01-02T08:18:08.000Z","updated":"2019-03-18T04:47:30.235Z","comments":true,"path":"2018/01/02/Ubuntu安装Elastic Stack/","link":"","permalink":"https://renqiangme.github.io/2018/01/02/Ubuntu安装Elastic Stack/","excerpt":"1.首先安装python-software-properties该程序将安装add-apt-repository的应用程序,更加方便的添加和使用PPA软件库。 12sudo apt-get updatesudo apt-get install -y python-software-properties software-properties-common apt-transport-https","text":"1.首先安装python-software-properties该程序将安装add-apt-repository的应用程序,更加方便的添加和使用PPA软件库。 12sudo apt-get updatesudo apt-get install -y python-software-properties software-properties-common apt-transport-https 2.安装java8123sudo add-apt-repository ppa:webupd8team/java -ysudo apt-get updatesudo apt-get install -y oracle-java8-installer 打印java的版本信息: 1java -version 3.安装elastic3.1:安装之前先添加elastic repository key 到server1wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add - 3.2:找到当前的文档版本,导入当前的repository到sources.list.d:1echo "deb https://artifacts.elastic.co/packages/6.x/apt stable main" | sudo tee -a /etc/apt/sources.list.d/elastic-6.x.list 4:安装elasticsearchElasticsearch是一个基于Apache Lucene(TM)的开源搜索引擎。无论在开源还是专有领域,Lucene可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库。 但是,Lucene只是一个库。想要使用它,你必须使用Java来作为开发语言并将其直接集成到你的应用中,更糟糕的是,Lucene非常复杂,你需要深入了解检索的相关知识来理解它是如何工作的。 Elasticsearch也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。 不过,Elasticsearch不仅仅是Lucene和全文搜索,我们还能这样去描述它: 分布式的实时文件存储,每个字段都被索引并可被搜索 分布式的实时分析搜索引擎 可以扩展到上百台服务器,处理PB级结构化或非结构化数据 而且,所有的这些功能被集成到一个服务里面,你的应用可以通过简单的RESTful API、各种语言的客户端甚至命令行与之交互。 4.1:安装及修改配置文件12sudo apt-get updatesudo apt-get install -y elasticsearch 配置文件路径:/etc/elasticsearch/elasticsearch.yml 可以修改host,port…. 4.2:加入开机自启动服务123sudo systemctl daemon-reloadsudo systemctl enable elasticsearchsudo systemctl start elasticsearch 4.3:通过system进行管理elasticsearch1234567systemctl status elasticsearchsystemctl start elasticsearchsystemctl stop elasticsearchsystemctl restart elasticsearch 4.4:查看运行情况查看端口: 1netstat -plntu 查看elasticsearch的cluster,版本..相关信息: 1curl -XGET 'localhost:9200/?pretty' 查看集群健康情况: 1curl 'localhost:9200/_cat/health?v' 查看集群中的节点列表: 1curl 'localhost:9200/_cat/nodes?v' 查看index情况: 1curl 'localhost:9200/_cat/indices?v' 4.4:参考文档Elasticsearch: 权威指南 5:安装KibanaKibana是一个为Elasticsearch平台分析和可视化的开源平台,使用Kibana能够搜索、展示存储在Elasticsearch中的索引数据。使用它可以很方便用图表、表格、地图展示和分析数据。Kibana能够轻松处理大量数据,通过浏览器接口能够轻松的创建和分享仪表盘,通过改变Elasticsearch查询时间,可以完成动态仪表盘。 5.1:通过apt安装及配置1sudo apt-get install -y kibana 配置文件路径: 1/etc/kibana/kibana.yml 可以修改host,port,以及elasticsearch的url 5.2:加入开机自启动12sudo systemctl enable kibanasudo systemctl start kibana 5.3:通过system进行管理kibana1234567systemctl status kibanasystemctl start kibanasystemctl stop kibanasystemctl restart kibana 6:安装LogstashLogstash 是一个开源的数据收集引擎具有实时管道能力。 Logstash 可以动态的统一数据从不同的来源和使数据规范化到你选择的目的地。 当Logstash 起初驾驭创新到日志收集,它的功能很好的扩展超出使用案例。任何事件的类型可以被丰富和改变使用一个input,filter和输出引擎,使用很多的本地的代码简化了采集的过程。 6.1:通过apt安装1sudo apt-get install -y logstash 6.2:logstash的配置文件目录:12345678/etc/logstash/├── conf.d│ └── kafka-logs-local.conf├── jvm.options├── log4j2.properties├── logstash.yml└── startup.options logstash.yml: path.config:定义扫描input,filter,output的配置目录 path.logs: 定义log配置,在测试配置文件的时候有用。 input:kafka,output:elasticsearch的example: 1234567891011121314151617181920212223242526272829303132333435363738394041input { kafka { topics_pattern => ["service-logs-.*"] bootstrap_servers => "10.1.220.27:9092" group_id => "local-logstash" decorate_events => true }}filter { json { source => "message" } mutate { add_field => { "kafka_topic" => "%{[@metadata][kafka][topic]}" "kafka_consumer_group" => "%{[@metadata][kafka][consumer_group]}" "kafka_partition" => "%{[@metadata][kafka][partition]}" "kafka_offset" => "%{[@metadata][kafka][offset]}" "kafka_timestamp" => "%{[@metadata][kafka][timestamp]}" } }}output { if [level] == "ERROR" { http { url => "http://localhost:8088/send/mail" http_method => "post" automatic_retries => 0 connect_timeout => 6 keepalive => false } } elasticsearch { hosts => ["127.0.0.1:9200"] action => "index" index => "logstash-%{[kafka_topic]}" }} 6.3:加入开机自启动12sudo systemctl enable logstashsudo systemctl start logstash 6.4:通过system进行管理logstash1234567systemctl status logstashsystemctl start logstashsystemctl stop logstashsystemctl restart logstash","categories":[{"name":"Linux","slug":"Linux","permalink":"https://renqiangme.github.io/categories/Linux/"}],"tags":[{"name":"Linux","slug":"Linux","permalink":"https://renqiangme.github.io/tags/Linux/"},{"name":"Ubuntu","slug":"Ubuntu","permalink":"https://renqiangme.github.io/tags/Ubuntu/"},{"name":"Elastic Stack","slug":"Elastic-Stack","permalink":"https://renqiangme.github.io/tags/Elastic-Stack/"}]},{"title":"Ubuntu设置固定的ip","slug":"Ubuntu设置固定的ip","date":"2017-08-18T05:28:18.000Z","updated":"2019-03-18T04:47:07.761Z","comments":true,"path":"2017/08/18/Ubuntu设置固定的ip/","link":"","permalink":"https://renqiangme.github.io/2017/08/18/Ubuntu设置固定的ip/","excerpt":"修改配置文件:/etc/network/interfaces 12345678910111213vim /etc/network/interfaces#增加修改如下:#The primary network interfaceauto ens160iface ens160 inet staticaddress 10.1.220.15netmask 255.255.0.0gateway 10.1.1.1dns-nameservers 8.8.8.8 8.8.4.4service networking restart","text":"修改配置文件:/etc/network/interfaces 12345678910111213vim /etc/network/interfaces#增加修改如下:#The primary network interfaceauto ens160iface ens160 inet staticaddress 10.1.220.15netmask 255.255.0.0gateway 10.1.1.1dns-nameservers 8.8.8.8 8.8.4.4service networking restart","categories":[{"name":"Linux","slug":"Linux","permalink":"https://renqiangme.github.io/categories/Linux/"}],"tags":[{"name":"Linux","slug":"Linux","permalink":"https://renqiangme.github.io/tags/Linux/"},{"name":"Ubuntu","slug":"Ubuntu","permalink":"https://renqiangme.github.io/tags/Ubuntu/"}]},{"title":"部署管理Swoole服务","slug":"部署管理Swoole服务","date":"2017-07-12T03:20:38.000Z","updated":"2019-03-25T13:46:38.846Z","comments":true,"path":"2017/07/12/部署管理Swoole服务/","link":"","permalink":"https://renqiangme.github.io/2017/07/12/部署管理Swoole服务/","excerpt":"使用Systemd管理Swoole服务Systemd 是 Linux 系统工具,用来启动守护进程。 Systemd 并不是一个命令,而是一组命令,涉及到系统管理的方方面面。包括:systemctl,systemd-analyze,hostnamectl,localectl,timedatectl,loginctl","text":"使用Systemd管理Swoole服务Systemd 是 Linux 系统工具,用来启动守护进程。 Systemd 并不是一个命令,而是一组命令,涉及到系统管理的方方面面。包括:systemctl,systemd-analyze,hostnamectl,localectl,timedatectl,loginctl 更多参考:Systemd介绍 所以Swoole的服务器程序可以编写一段service脚本,交由systemd进行管理。实现故障重启、开机自启动等功能。 使用systemd管理swoole服务参考文档:swoole官方文档 Demo: 在/etc/systemd/system/swoole_http.service新建一个service文件,内容如下: 123456789101112131415[Unit]Description=Swoole Http serviceAfter=network.targetAfter=syslog.target[Service]Type=forkingPIDFile=/home/www/http/bin/server.pidExecStart=/home/www/http/bin/serverExecStop=/bin/kill -15 $MAINPIDExecReload=/bin/kill -USR1 $MAINPIDRestart=always[Install]WantedBy=multi-user.target graphical.target 需要注意的是$MAINPID必须要是manager的id,不然启动或者重启的时候会报错。而且还需要修改swoole配置参数,把swoole的守护进程化设置为daemonize => 1。 kill -USR1 pid 重启woker进程和task进程 kill -USR2 pid 重启task进程 kill -15 管理进程id 关掉所有的manager相关进程 关于swoole重启的文档:链接 使用Supervisor管理swoole服务Supervisor是一个客户/服务器系统,它可以在类Unix系统中管理控制大量进程。Supervisor使用python开发,有多年历史,目前很多生产环境下的服务器都在使用Supervisor,部署python程序经常这个。 Supervisor的服务器端称为supervisord,主要负责在启动自身时启动管理的子进程,响应客户端的命令,重启崩溃或退出的子进程,记录子进程stdout和stderr输出,生成和处理子进程生命周期中的事件。可以在一个配置文件中配置相关参数,包括Supervisord自身的状态,其管理的各个子进程的相关属性。配置文件一般位于/etc/supervisord.conf。 Supervisor的客户端称为supervisorctl,它提供了一个类shell的接口(即命令行)来使用supervisord服务端提供的功能。通过supervisorctl,用户可以连接到supervisord服务器进程,获得服务器进程控制的子进程的状态,启动和停止子进程,获得正在运行的进程列表。客户端通过Unix域套接字或者TCP套接字与服务端进行通信,服务器端具有身份凭证认证机制,可以有效提升安全性。当客户端和服务器位于同一台机器上时,客户端与服务器共用同一个配置文件/etc/supervisord.conf,通过不同标签来区分两者的配置。 Supervisor也提供了一个web页面来查看和管理进程状态,这个功能非常酷. 安装Supervisor123456# 我们可以通过pypi安装pip install supervisor# 或者从pypi上下载源码,然后安装python setup.py install# 安装完之后,使用下列命令来生成配置文件echo_supervisord_conf > /etc/supervisord.conf 1# mkdir /etc/supervisord.d 用户存放被监控进程的配置文件 修改/etc/supervisord.conf配置文件:1234在文件结尾[include]节点处把;files = relative/directory/*.ini改为files =/etc/supervisord.d/*.conf同时还需要去掉[include]前面的; 保存并退出。 把supervisor加入开机自启动服务到systemd系统下新建一个service配置文件1vim /lib/systemd/system/supervisor.service 123456789101112131415[Unit]Description=supervisorAfter=network.target[Service]Type=forkingExecStart=/usr/bin/supervisord -c /etc/supervisord.confExecStop=/usr/bin/supervisorctl $OPTIONS shutdownExecReload=/usr/bin/supervisorctl $OPTIONS reloadKillMode=processRestart=on-failureRestartSec=42s[Install]WantedBy=multi-user.target graphical.target 上述文件编写后,执行如下命令即可:1systemctl enable supervisor.service 加入开机自启动服务1systemctl daemon-reload 重新载入systemd,扫描新的或有变动的单元。 实际上supervisor已经加入了systemctl管理了,后续起停supervisor服务都可以通过systemctl来控制了。 123456789systemctl start supervisor.service 启动服务systemctl stop supervisor.service 停止服务systemctl restart supervisor.service 重新启动服务systemctl reload supervisor.service 重载配置文件systemctl status supervisor.service 查看服务状态 在/etc/supervisord.d 增加一个程序的demo配置参数:123456789101112131415161718192021222324252627[program:cat] ;程序名command=/bin/cat ;命令绝对路径,可以包含参数process_name=%(program_name)s ;进程名numprocs=1 ;supervisor启动多少个该程序,如果大于1,那么进程名必须包括%(process_num)sdirectory=/tmp ;该进程的启动时的工作目录umask=022 ;掩码priority=999 ;优先级autostart=true ;该程序是否在supervisor启动时启动autorestart=true ;如果为false,那么该程序的相关进程永远不会自动重启。如果为unexpected,该程序的相关进程仅会在退出码为exitcodes中的值时重启;如果为true时startsecs=10 ;最大启动时间startretries=3 ;最大启动重试次数。超过这个次数后,该进程会标记为FATAL状态exitcodes=0,2 ;退出码,关联autorestart=unexpectedstopsignal=TERM ;关闭该程序相关进程所发送的信号量。可以为TERM, HUP, INT, QUIT, KILL, USR1, or USR2stopwaitsecs=10 ;supervisord父进程等待该程序的相关子进程返回SIGCLILD信号量的时间,超时后则发送SIGKILLuser=chrism ;启动该程序进程的用户redirect_stderr=false ;如果为true,则将该程序的进程错误输出到supervisor主日志文件中stdout_logfile=/tmp ;标准输出stdout_logfile_maxbytes=1MB ;日志轮滚stdout_logfile_backups=10 ;日志轮滚stdout_capture_maxbytes=1MB stderr_logfile=/a/path stderr_logfile_maxbytes=1MBstderr_logfile_backups=10stderr_capture_maxbytes=1MBenvironment=A="1",B="2" ;!环境变量信息serverurl=AUTO ;传送给该子进程的环境变量SUPERVISOR_SERVER_URL ,AUTO则自动提供一个Supervisord的URL。用于该进程可以和内部HTTP Server进行通信,简化进程管理。 从swoole的文档我们得知:Swoole提供了柔性终止/重启的机制,管理员只需要向SwooleServer发送特定的信号,Server的worker进程可以安全的结束。 1234567891011121314SIGTERM: 向主进程/管理进程发送此信号服务器将安全终止在PHP代码中可以调用$serv->shutdown()完成此操作SIGUSR1: 向主进程/管理进程发送SIGUSR1信号,将平稳地restart所有worker进程在PHP代码中可以调用$serv->reload()完成此操作swoole的reload有保护机制,当一次reload正在进行时,收到新的重启信号会丢弃如果设置了user/group,Worker进程可能没有权限向master进程发送信息,这种情况下必须使用root账户,在shell中执行kill指令进行重启reload指令对addProcess添加的用户进程无效#重启所有worker进程kill -USR1 主进程PID#仅重启task进程kill -USR2 主进程PID supervisor的程序restart的原理是实际上是发信号,所以我们需要给swoole的程序stop信号配置为:stopsignal=TERM 同时还需要把swoole的守护进程化设置为daemonize => 0,不然会报spawned error supervisorctl控制program现在supervisor的server端我们已经交给systemd去管理,现在我们可以通过supervisorctl去控制配置添加的program 1234567supervisorctl -c supervisor.conf status 察看supervisor的状态supervisorctl -c supervisor.conf reload 重新载入 配置文件supervisorctl -c supervisor.conf start [all]|[appname] 启动指定/所有supervisor管理的程序进程supervisorctl -c supervisor.conf stop [all]|[appname] 关闭指定/所有 supervisor管理的程序进程","categories":[{"name":"PHP","slug":"PHP","permalink":"https://renqiangme.github.io/categories/PHP/"}],"tags":[{"name":"PHP","slug":"PHP","permalink":"https://renqiangme.github.io/tags/PHP/"},{"name":"Systemd","slug":"Systemd","permalink":"https://renqiangme.github.io/tags/Systemd/"},{"name":"Swoole","slug":"Swoole","permalink":"https://renqiangme.github.io/tags/Swoole/"},{"name":"Supervisor","slug":"Supervisor","permalink":"https://renqiangme.github.io/tags/Supervisor/"}]},{"title":"Python获取音频时长和分割音频","slug":"Python获取音频时长和分割音频","date":"2017-06-26T12:12:07.000Z","updated":"2019-03-18T04:46:23.249Z","comments":true,"path":"2017/06/26/Python获取音频时长和分割音频/","link":"","permalink":"https://renqiangme.github.io/2017/06/26/Python获取音频时长和分割音频/","excerpt":"ffmpeg是视频和音频处理的利器,各种转格式,提取视频中的图片,合并或者分隔音频,录制屏幕,加字幕啊…都是可以的。 因为有需求需要获取音频的长度然后来分割。 虽然ffmpeg -i xxx file也可以获取到音频的长度,但是可能需要正则去匹配,然后发现他们家族的ffprobe就可以直接返回json格式的音频信息。ffprobe是一个多媒体流分析工具。","text":"ffmpeg是视频和音频处理的利器,各种转格式,提取视频中的图片,合并或者分隔音频,录制屏幕,加字幕啊…都是可以的。 因为有需求需要获取音频的长度然后来分割。 虽然ffmpeg -i xxx file也可以获取到音频的长度,但是可能需要正则去匹配,然后发现他们家族的ffprobe就可以直接返回json格式的音频信息。ffprobe是一个多媒体流分析工具。 大概命令如下: ffprobe -v quiet -print_format json -show_format -show_streams 1.wav python中可以这样子调用: import subprocess as sp try: command = ['ffprobe', '-v', 'quiet', '-print_format', 'json', '-show_format','-show_streams', item["file_path"]] wav_info = sp.check_output(command, stderr=sp.STDOUT) print(wav_info) except sp.CalledProcessError as e: print('get audio info by ffprobe error %s' % e.output) 分割音频就需要用到ffmpeg了,大概命令如下: ffmpeg -i 1.wav -ss 00:00:03 -t 00:00:12 -acodec copy tmp.wav 源音频:source_mp3 开始位置:-ss 结束位置:-t 原始编码:-acodec 需要注意的是:input的音频格式必须和output的音频格式一致,不然要报格式错误! python中可以这样子调用: try: cut_command = ['ffmpeg', '-y', '-i', origin_wav, '-ss', start_time, '-t',end_time, '-acodec', 'copy', cut_wav] wav_cut_result = sp.check_call(cut_command) if wav_cut_result == 0: #todo success except sp.CalledProcessError as e: print('cut audio info error %s' % e.output) 音频格式转换: 单声道&采样率16000 ffmpeg -f s16le -ar 16000 -ac 1 -i xx.pcm xx.wav -f:强制格式 s16le:无压缩 -ar:采样率 -ac:声道 -i:输入文件 更多命令相关参数:ffmpeg --help","categories":[{"name":"Python","slug":"Python","permalink":"https://renqiangme.github.io/categories/Python/"}],"tags":[{"name":"Python","slug":"Python","permalink":"https://renqiangme.github.io/tags/Python/"},{"name":"ffmpeg","slug":"ffmpeg","permalink":"https://renqiangme.github.io/tags/ffmpeg/"}]},{"title":"Redis通过模式匹配模糊删除key","slug":"Redis通过模式匹配模糊删除key","date":"2017-03-25T07:33:29.000Z","updated":"2019-03-18T04:45:59.611Z","comments":true,"path":"2017/03/25/Redis通过模式匹配模糊删除key/","link":"","permalink":"https://renqiangme.github.io/2017/03/25/Redis通过模式匹配模糊删除key/","excerpt":"Redis命令del不支持模式匹配,但是keys支持,如果需要通过模式匹配来删除一批,可以执行: 1/usr/local/redis/bin/redis-cli -h xx -p xx -a xx KEYS “test_*” | xargs /usr/local/redis/bin/redis-cli -h xx-p xx -a xx DEL","text":"Redis命令del不支持模式匹配,但是keys支持,如果需要通过模式匹配来删除一批,可以执行: 1/usr/local/redis/bin/redis-cli -h xx -p xx -a xx KEYS “test_*” | xargs /usr/local/redis/bin/redis-cli -h xx-p xx -a xx DEL 关于keys命令的模式匹配介绍,可以参考: https://redis.io/commands/keys","categories":[{"name":"Redis","slug":"Redis","permalink":"https://renqiangme.github.io/categories/Redis/"}],"tags":[{"name":"Redis","slug":"Redis","permalink":"https://renqiangme.github.io/tags/Redis/"}]},{"title":"在Centos上面源码安装TensorFlow","slug":"在Centos上面源码安装TensorFlow","date":"2017-03-18T03:28:19.000Z","updated":"2019-03-18T04:45:42.956Z","comments":true,"path":"2017/03/18/在Centos上面源码安装TensorFlow/","link":"","permalink":"https://renqiangme.github.io/2017/03/18/在Centos上面源码安装TensorFlow/","excerpt":"最先一开始用pip安装,但是总是在运行的时有源码安装效果更好的提示,所以索性源码安装,整个编译过程还真的是蛮久的。","text":"最先一开始用pip安装,但是总是在运行的时有源码安装效果更好的提示,所以索性源码安装,整个编译过程还真的是蛮久的。 源码安装TensorFlow需要先安装Bazel这个google推出的自动化构建工具。 1:安装Bazel之前先安装JDK 2:下载源码zip包https://github.com/bazelbuild/bazel/releases/ 3:然后直接执行./compile.sh等待出现安装成功后4:把bazel导入到环境变量。:vim /etc/profile加入export PATH=/home/yangrenqiang/bazel/output:$PATHsource /etc/profile 5:测试bazel是否安装成功bazel help 6:在github上面下载tensorflow的源码7:执行./configure8:bazel build –config=opt //tensorflow/tools/pip_package:build_pip_package9:bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg10:sudo pip install /tmp/tensorflow_pkg/tensorflow-1.0.1-py2-none-any.whl 具体参考:https://www.tensorflow.org/install/install_sources 关于TensorFlow的中文文档:http://docs.pythontab.com/tensorflow/","categories":[{"name":"Linux","slug":"Linux","permalink":"https://renqiangme.github.io/categories/Linux/"}],"tags":[{"name":"Linux","slug":"Linux","permalink":"https://renqiangme.github.io/tags/Linux/"},{"name":"TensorFlow","slug":"TensorFlow","permalink":"https://renqiangme.github.io/tags/TensorFlow/"}]},{"title":"Linux禁止某些用户和组SSH登录","slug":"Linux禁止某些用户和组SSH登录","date":"2017-02-08T04:10:02.000Z","updated":"2019-03-18T04:45:12.696Z","comments":true,"path":"2017/02/08/Linux禁止某些用户和组SSH登录/","link":"","permalink":"https://renqiangme.github.io/2017/02/08/Linux禁止某些用户和组SSH登录/","excerpt":"Linux系统可以通过sshd的配置项,禁止某些用户SSH登录,方法如下:","text":"Linux系统可以通过sshd的配置项,禁止某些用户SSH登录,方法如下: 1、打开sshd的配置文件 1vim /etc/ssh/sshd_config 2、修改该配置文件,增加或修改如下行 123#禁止用户user1登陆,多个用户空格分隔DenyUsers user1 123#禁止用户组group1的所有用户登录,多个空格分隔DenyGroups group1 3、保存配置后,重启sshd 1/etc/rc.d/init.d/sshd restart 完成上面的配置后,就可以禁止用户或用户组的用户进行SSH登录 4、配置完毕后,在其它linux机器上使用如下命令进行测试 使用ssh测试 123ssh user1@192.168.1.168user1@192.168.1.168's password:Permission denied, please try again. 授权被拒绝,已经实现禁用该用户使用SSH登录","categories":[{"name":"Linux","slug":"Linux","permalink":"https://renqiangme.github.io/categories/Linux/"}],"tags":[{"name":"Linux","slug":"Linux","permalink":"https://renqiangme.github.io/tags/Linux/"},{"name":"SSH","slug":"SSH","permalink":"https://renqiangme.github.io/tags/SSH/"}]},{"title":"Linux禁止root账户远程SSH登录","slug":"Linux禁止root账户远程SSH登录","date":"2017-02-08T03:25:42.000Z","updated":"2019-03-18T04:44:55.451Z","comments":true,"path":"2017/02/08/Linux禁止root账户远程SSH登录/","link":"","permalink":"https://renqiangme.github.io/2017/02/08/Linux禁止root账户远程SSH登录/","excerpt":"为增强服务器的安全,我们通常会禁止root账户远程SSH登录。 首先增加一个普通权限的用户:","text":"为增强服务器的安全,我们通常会禁止root账户远程SSH登录。 首先增加一个普通权限的用户: 12useradd demopasswd demo123 修改配置文件/etc/ssh/sshd_config,禁止root远程SSH登录: 1vi /etc/ssh/sshd_config 把PermitRootLogin改为no 12PermitRootLogin yesPermitRootLogin no 重启sshd服务 1service sshd restart 然后远程管理,用普通用户demo登录,然后用 su root 切换到root用户拿到最高权限,来保障服务器的安全。","categories":[{"name":"Linux","slug":"Linux","permalink":"https://renqiangme.github.io/categories/Linux/"}],"tags":[{"name":"Linux","slug":"Linux","permalink":"https://renqiangme.github.io/tags/Linux/"},{"name":"SSH","slug":"SSH","permalink":"https://renqiangme.github.io/tags/SSH/"}]},{"title":"通过Nginx代理NodeJS支持Websocket","slug":"通过Nginx代理NodeJS支持Websocket","date":"2017-01-20T04:05:42.000Z","updated":"2019-03-25T13:37:46.698Z","comments":true,"path":"2017/01/20/通过Nginx代理NodeJS支持Websocket/","link":"","permalink":"https://renqiangme.github.io/2017/01/20/通过Nginx代理NodeJS支持Websocket/","excerpt":"NGINX自从1.3版本就开始支持WebSocket了,并且可以为WebSocket应用程序做反向代理和负载均衡。 WebSocket 和HTTP协议不同,但是WebSocket中的握手和HTTP中的握手兼容,它使用HTTP中的Upgrade协议头将连接从HTTP升级到WebSocket。这使得WebSocket程序可以更容易的使用现已存在的基础设施。例如,WebSocket可以使用标准的HTTP端口 80 和 443,因此,现存的防火墙规则也同样适用。","text":"NGINX自从1.3版本就开始支持WebSocket了,并且可以为WebSocket应用程序做反向代理和负载均衡。 WebSocket 和HTTP协议不同,但是WebSocket中的握手和HTTP中的握手兼容,它使用HTTP中的Upgrade协议头将连接从HTTP升级到WebSocket。这使得WebSocket程序可以更容易的使用现已存在的基础设施。例如,WebSocket可以使用标准的HTTP端口 80 和 443,因此,现存的防火墙规则也同样适用。一个WebSockets的应用程序会在客户端和服务端保持一个长时间工作的连接。用来将连接从HTTP升级到WebSocket的HTTP升级机制使用HTTP的Upgrade和Connection协议头。反向代理服务器在支持WebSocket方面面临着一些挑战。一项挑战是WebSocket是一个hop-by-hop协议,所以,当代理服务器拦截到一个客户端发来的Upgrade请求时,它(指服务器)需要将它自己的Upgrade请求发送给后端服务器,也包括合适的请求头。此外,由于WebSocket连接是长时间保持的,所以代理服务器需要允许这些连接处于打开状态,而不是像对待HTTP使用的短连接那样将其关闭。 NGINX 通过在客户端和后端服务器之间建立起一条隧道来支持WebSocket。为了使NGINX可以将来自客户端的Upgrade请求发送给后端服务器,Upgrade和Connection的头信息必须被显式的设置。如下所示:12proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade"; 完整配置: 1234567891011121314151617181920212223upstream wsbackend { server 127.0.0.1:3000;#nodejs启动的本地端口 keepalive 8;}server { listen 80; server_name xxx.com; index index.html index.htm index.php default.html default.htm default.php; root /home/wwwroot/xxx.com; location / { proxy_pass http://wsbackend; #这两个HTTP头是因为采用了nginx作为代理后,后端可以通过 X-real-ip 或 X-Forwarded-For取得用户IP地址 proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-NginX-Proxy true; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade;# 声明支持websocket proxy_set_header Connection "upgrade";# 声明支持websocket proxy_redirect off; }}","categories":[{"name":"Nginx","slug":"Nginx","permalink":"https://renqiangme.github.io/categories/Nginx/"}],"tags":[{"name":"Nginx","slug":"Nginx","permalink":"https://renqiangme.github.io/tags/Nginx/"},{"name":"NodeJS","slug":"NodeJS","permalink":"https://renqiangme.github.io/tags/NodeJS/"},{"name":"Websocket","slug":"Websocket","permalink":"https://renqiangme.github.io/tags/Websocket/"}]},{"title":"网页加载优化-PHP压缩网页进Redis,OpenResty端直接输出","slug":"网页加载优化-PHP压缩网页进Redis-OpenResty端直接输出","date":"2016-12-25T14:07:30.000Z","updated":"2019-03-18T04:44:09.518Z","comments":true,"path":"2016/12/25/网页加载优化-PHP压缩网页进Redis-OpenResty端直接输出/","link":"","permalink":"https://renqiangme.github.io/2016/12/25/网页加载优化-PHP压缩网页进Redis-OpenResty端直接输出/","excerpt":"其实商城项目的网页端,观察京东,淘宝他们有很多活动页面或者商品详情页,推广力度很多,流量也就比较多,通常一个页面很大很大,整个网页内容也很多,单纯考虑从webserver到走进php,java连接数据库等等读取数据拼装,再渲染视图输出到浏览器,整个过程下来,并发不大的情况还好,一大起来的就会性能大大的降低。 对于中小型项目,解决的方案肯定没有淘宝京东的方案多。","text":"其实商城项目的网页端,观察京东,淘宝他们有很多活动页面或者商品详情页,推广力度很多,流量也就比较多,通常一个页面很大很大,整个网页内容也很多,单纯考虑从webserver到走进php,java连接数据库等等读取数据拼装,再渲染视图输出到浏览器,整个过程下来,并发不大的情况还好,一大起来的就会性能大大的降低。 对于中小型项目,解决的方案肯定没有淘宝京东的方案多。于是就要想解决优化的方案,像商品详情页有商品相关的静态数据,同时掺杂着一些评论,购买数量等等的动态数据,其实可以把整个网页动静分离,动态数据走接口,静态数据直接gzip压缩存进缓存,通过Openresty在nginx层面通过lua直接读取就输出,然后浏览器自动解压gzip。由于页面数据是压缩了的可以节省网络IO,大大提升页面的加载速度。但是像一些活动页面,动态数据可能没有那么多,改动商品相关的价格库存…等等改动那么频繁,其实可以直接扔进CDN,动态数据也走接口。 下面来看下PHP的几个GZIP压缩相关的函数,都是基于ZLIB库。 gzcompress gzdeflate gzencode函数的区别在于它们压缩的数据格式不同: gzcompress使用的是ZLIB格式; gzdeflate使用的是纯粹的DEFLATE格式; gzencode使用的是GZIP格式; 但是有一点是相同的,它们压缩数据时都使用了DEFLATE压缩算法(理论上ZLIB和GZIP格式可以使用其他的压缩算法,但是目前实践中只使用DEFLATE算法),ZLIB和GZIP只不过是在DEFLATE的基础之上加了一些头部和尾部而已。 顺便提一下,HTTP协议中的Content-Encoding: deflate使用的是ZLIB格式而不是纯DEFLATE格式。 通过测试发现,gzencode和gzdeflate浏览器可以自动解压出来,前提是:http的请求头里面有accept-encoding:gzip, deflate,说明方案是可行的,但是对于一些浏览器可能不支持自动解压,所以需要判断下请求头,如果不支持,就需要lua解压之后再输出。 既然使用Openresty就在社区搜索了下。lua的zlib库有两个:–lua-zlib–通过LuaJIT的FFI库来包装ZLIB模块 选择的是:lua-zlib lua输出判断函数:123456789101112131415161718192021222324252627282930local function echoPage(index_page) --如果index_page=nil 就继续让nginx执行下一阶段,走进php让php自己处理 if not index_page then ngx.exit(ngx.OK) end local accept_encoding_table = ngx.req.get_headers() local accept_encoding = accept_encoding_table[\"accept-encoding\"] local need_uncompress = 0 if accept_encoding ~= nil and #accept_encoding>0 then local begin,stop = ngx.re.find(accept_encoding,'gzip') if begin ~= nil then need_uncompress = 0 else need_uncompress = 1 end else need_uncompress = 1 end if need_uncompress == 1 then local zlib = require \"zlib\" local stream = zlib.inflate() local inflated,stream_eof,bytes_in,bytes_out = stream(res) ngx.say(inflated) else ngx.header[\"Content-Encoding\"] = \"gzip\"--避免Nginx再去压缩,需要发送一个响应头,告诉Nginx是一个gzip压缩的 ngx.send_headers() ngx.say(res) endend 注释:12ngx.exit(ngx.OK)--因为openresty有执行阶段这一个说法,是告诉openresty执行下一阶段ngx.exit(200)--意思是直接返回200,不再向下执行。也可以是其他的http状态码。","categories":[{"name":"OpenResty","slug":"OpenResty","permalink":"https://renqiangme.github.io/categories/OpenResty/"}],"tags":[{"name":"PHP","slug":"PHP","permalink":"https://renqiangme.github.io/tags/PHP/"},{"name":"OpenResty","slug":"OpenResty","permalink":"https://renqiangme.github.io/tags/OpenResty/"},{"name":"Redis","slug":"Redis","permalink":"https://renqiangme.github.io/tags/Redis/"}]},{"title":"Linux学习之权限管理","slug":"Linux学习之权限管理","date":"2016-12-24T15:03:47.000Z","updated":"2019-03-18T10:12:00.338Z","comments":true,"path":"2016/12/24/Linux学习之权限管理/","link":"","permalink":"https://renqiangme.github.io/2016/12/24/Linux学习之权限管理/","excerpt":"ACL权限1:ACL权限简介和开启 A:不再考虑身份。用户或用户组直接拿过来给它改权限 B:查看分区ACL权限是否开启dumpe2fs -h /dev/sda3 #dump2fs命令是查询指定分区详细文件系统信息的命令选项:-h 仅显示超级块中信息,而不显示磁盘块组的详细信息 步骤1:df -h #查看当前系统分区使用情况,容量,已用,可用,挂载点,找到用户所在分区。 步骤2:dumpe2fs -h /dev/sda3 C:临时开启分区ACL权限mount -o remount,acl / #重新挂载根分区,并载入acl权限 D:永久开启分区ACL权限 步骤1:vi /etc/fstab #加入aclUUID=c2cq6f57-b15c-43ea-bca0-f239083d8bd2 / ext4 defaults,acl 1 1 #defaults后面加了一个acl 步骤2:mount -o remount / #重新挂载文件系统或重启动系统,使修改生效","text":"ACL权限1:ACL权限简介和开启 A:不再考虑身份。用户或用户组直接拿过来给它改权限 B:查看分区ACL权限是否开启dumpe2fs -h /dev/sda3 #dump2fs命令是查询指定分区详细文件系统信息的命令选项:-h 仅显示超级块中信息,而不显示磁盘块组的详细信息 步骤1:df -h #查看当前系统分区使用情况,容量,已用,可用,挂载点,找到用户所在分区。 步骤2:dumpe2fs -h /dev/sda3 C:临时开启分区ACL权限mount -o remount,acl / #重新挂载根分区,并载入acl权限 D:永久开启分区ACL权限 步骤1:vi /etc/fstab #加入aclUUID=c2cq6f57-b15c-43ea-bca0-f239083d8bd2 / ext4 defaults,acl 1 1 #defaults后面加了一个acl 步骤2:mount -o remount / #重新挂载文件系统或重启动系统,使修改生效 2:查看与设定ACL权限 A:查看ACL命令 getfacl 文件名 #查看ACL权限 B:设定ACL权限 setfacl 选项 文件名 12345678910选项:-m 设定ACL权限 给用户设置ACL权限 setfacl -m u:qingwa:rx /project/ 给用户组设定ACL权限 setfacl -m g:xxgroup:rwx project/-x 删除指定的ACL权限 setfacl -x g:xxgroup /project/ #删除xxgroup在project下面的ACL权限-b 删除所有的ACL权限 setfacl -b /project/ #会删除在project下面所有用户用户组的ACL权限-d 设定默认的ACL权限-k 删除默认ACL权限-R 递归设定ACL权限 3:最大有效权限与删除ACL权限最大有效权限maskmask是用来指定最大有效权限的。如果我给用户赋予了ACL权限,是需要和mask的权限“相与”才能得到用户的真正权限。(相与—相当于逻辑的与 一个为假就都为假) 4:默认ACL权限和递归ACL权限递归是父目录在设定ACL权限时,所有的子文件和子目录也会拥有相同的ACL权限。1setfacl -m u:用户名:权限 -R 文件名 默认ACL权限默认ACL权限的作用是如果给父目录设定了ACL权限,那么父目录中所有新建的子文件都会继承父目录的ACL权限。1setfacl -m d:u用户名:权限 文件名 文件特殊权限1: SetUIDSetUID的功能 只有可以执行的二进制程序才能设定SUID权限 命令执行者要对该程序拥有x(执行)权限 命令执行者在执行该程序时获得该程序文件宿主的身份(在执行程序的过程中灵魂附体为文件的属主) SetUID权限只在该程序执行过程中有效,也就是说身份改变只在程序执行过程中有效。 设置SUID:1234代表SUIDchmod 4755 文件名chmod u+s 文件名 取消SUID:12chmod 755 文件名chmod u-s 文件名 危险的SetUID:123.关键目录应该严格控制写权限,比如“/”、“/usr”等。.用户的密码设置要严格遵守密码三原则。.对系统中默认应该是具有SetUID权限的文件作一列表,定时检查有没有这之外的文件被设置了SetUID权限。 2: SetGIDSetGID针对文件的作用: 只有可执行的二进制程序才能设置SGID权限 命令执行者要对该程序拥有x(执行)权限 命令执行在执行程序的时候,组身份升级为该程序文件的属组 SetGID权限同样只在该程序执行过程中有效,也就是说组身份改变只在程序执行过程中有效 SetGID针对目录的作用: 普通用户必须对此目录拥有r和x权限,才能进入此目录 普通用户在此目录中的有效组会变成此目录的属组 若普通用户对此目录拥有w权限时,新建的文件的默认属组是这个目录的属组 设定SetGID:1232代表SGIDchmod 2755 文件名chmod g+s 文件名 3: Sticky BITSBIT粘着位作用 粘着位目前只对目录有效 普通用户对该目录拥有w和x权限,即普通用户可以在此目录拥有写入权限 如果没有粘着位,因为普通用户拥有w权限,所以可以删除此目录下所有文件,包括其他用户建立的文件。一旦赋予了粘着位,除了root可以删除所有文件,普通用户就算拥有w权限,也只能删除自己建立的文件,但是不能删除其他用户建立的文件。 设置与取消粘着位12341代表SBIT设置粘着位chmod 1755 目录名chmod o+t 目录名 取消粘着位12chmod 777 目录名chmod o-t 目录名 文件系统属性chattr权限chattr[+-=][选项]文件或目录名1234567+:增加权限-:删除权限=:等于某权限 选项: i:如果对文件设置i属性,那么不允许对文件进行删除,改名,也不能添加和修改数据;如果对目录设置i属性,那么只能修改目录下文件的数据,但不允许建立和删除文件。 a:如果对文件设置a属性,那么只能在文件中增加数据,但是不能删除也不能修改数据;如果对目录设置a属性,那么只允许在目录中建立和修改文件,但是不允许删除。 2、查看文件系统属性:lsattr 选项 文件名 选项: -a 显示所有文件和目录 -d若目标是目录,仅列出目录本身的属性,而不是子文件的。 系统命令sudo权限 1: root把本来只能超级用户执行的命令赋予普通用户执行 sudo的操作对象是系统命令 2:sudo使用visudo #需要超级管理员执行这个命令 实际修改的是/etc/sudoers文件","categories":[{"name":"Linux","slug":"Linux","permalink":"https://renqiangme.github.io/categories/Linux/"}],"tags":[{"name":"Linux","slug":"Linux","permalink":"https://renqiangme.github.io/tags/Linux/"}]},{"title":"Linux学习笔记之Vim","slug":"Linux学习笔记之Vim","date":"2016-12-24T14:52:07.000Z","updated":"2019-03-18T10:01:29.113Z","comments":true,"path":"2016/12/24/Linux学习笔记之Vim/","link":"","permalink":"https://renqiangme.github.io/2016/12/24/Linux学习笔记之Vim/","excerpt":"一、Vim常用操作Vim是一个功能强大的全屏幕文本编辑器。是linux/unix上最常用的文本编辑器。它的作用是建立、编辑、显示文本文件。 Vim没有菜单,只有命令!","text":"一、Vim常用操作Vim是一个功能强大的全屏幕文本编辑器。是linux/unix上最常用的文本编辑器。它的作用是建立、编辑、显示文本文件。 Vim没有菜单,只有命令! Vim三个工作模式:12345678命令模式 vi filename 进去命令模式 输入:wq保存退出 插入模式当你在命令模式的时候,输入插入命令 i a o就可以进入插入模式,进入插入模式的标志是下方出现了INSERT字样。按ESC退出。 编辑模式当你是命令模式的时候,按一个冒号 ':'就可以进入编辑模式。比如set number命令设置行号 设置完就回到命令模式 插入命令:1234567命令 作用a 在光标所在字符后插入A 在光标所在行尾插入i 在光标所在字符前插入I 在光标所在行行首插入o 在光标下面插入新行O 在光标上面插入新行 定位命令:123456789命令 作用:set nu 设置行号:set nonu 取消行号gg 到第一行G 到最后一行nG 到第n行:n 到第n行$ 移至行尾0 移至行首 删除命令:1234567命令 作用x 删除光标所在处字符nx 删除光标所在处后n个字符dd 删除光标所在行 ndd删除n行dG 删除光标所在行到文件末尾内容D 删除光标所在处到行尾内容:n1,n2d 删除n1行到n2行指定范围的行 复制和剪切命令:123456命令 作用yy 复制当前行nyy 复制当前行以下n行dd 剪切当前行ndd 复制当前行以下n行p或P 粘贴在当前光标所在行下或行上 替换和取消命令1234命令 作用r 取代光标所在处字符R 从光标所在处开始替换字符,按Esc结束 【下方会出现replace字符】u 取消上一步操作 搜索和搜索替换命令12345678910命令 作用/string 1:搜索指定的字符串 2:搜索时忽略大小写 :set icn 搜索指定字符串的下一个出现位置:%s/old/new/g 全文替换指定字符串:n1,n2s/old/new/g 在一定范围内替换指定字符串:替换范围%s 全文替换起始行,终止行 s /要替换的字符串/替换的新的字符串/g c 询问确认 保存和退出命令1234567命令 作用:w 保存修改:W new_filename 另存为指定文件:wq 保存修改并退出ZZ 快捷键,保存修改并退出:q! 不保存修改退出:wq! 保存修改并退出(文件所有者及root可使用) 二、Vim常用技巧技巧1123456:r 文件名 ----把文件内容导入到刚刚光标所在的位置:! 命令 -----可以执行命令例如 :!which ls ----可以查看ls命令所在位置可以把以上结合起来,可以把一个命令执行结果导入文件中 :r !命令 技巧21234567定义快捷键 :map 快捷键 触发命令范例::map ^P I#<ESC> 定义快捷键位ctrl+P 触发的命令为 I跳到行首并进入插入模式,然后插入#号,然后进入到命令模式 :map ^B 0x 定义快捷键ctrl+B 触发的命令为 0光标跳到行首并删除光标所在的字符 即可实现:删除注释注意:快捷键一般跟ctrl结合起来 这里的^不是数字6那个 实际是ctrl+v 可以结合快捷键三个键一起按! 技巧312345连续行注释 :n1,n2s/^/#/g 连续多行注释 :n1,n2s/^#//g 去掉连续多行的注释 :n1,n2s/^/\\/\\//g 有些程序我们需要//注释的时候 可以连续多行这个命令 技巧4123替换:ab mymail 763191973@qq.com在用vim编辑器执行 以上 当我们在插入模式 的时候 输入mymail的时候 一回车就会变成了763191973@qq.com 注意!!!!:如果有定义的快捷键 ab在重启的时候 会发现都消失 如果你想永久有效 需要写在每个用户的宿主目录下面的家目录下面的配置文件里面。如果是root就在/root目录下面,如果是其他用户就在/home/xx下面。文件.vimrc 可以存放一些编辑模式的命令 快捷键 ab","categories":[{"name":"Linux","slug":"Linux","permalink":"https://renqiangme.github.io/categories/Linux/"}],"tags":[{"name":"Linux","slug":"Linux","permalink":"https://renqiangme.github.io/tags/Linux/"},{"name":"Vim","slug":"Vim","permalink":"https://renqiangme.github.io/tags/Vim/"}]},{"title":"OpenResty中获取和设置cookie","slug":"OpenResty中获取和设置cookie","date":"2016-12-24T14:27:52.000Z","updated":"2019-03-18T04:42:48.275Z","comments":true,"path":"2016/12/24/OpenResty中获取和设置cookie/","link":"","permalink":"https://renqiangme.github.io/2016/12/24/OpenResty中获取和设置cookie/","excerpt":"1:获取cookielocal cookie_xx_value = ngx.var.cookie_xx","text":"1:获取cookielocal cookie_xx_value = ngx.var.cookie_xx 2:设置cookie因为cookie的过期时间格是林尼治时间需要注意转下。 12local expires = 3600 * 24 -- cookie expires = 1 dayngx.header[\"Set-Cookie\"] = \"hello=world; Path=/; Expires=\" .. ngx.cookie_time(ngx.time() + expires) 如果想同时设置多个cookie,可以传一个table 1234567local expires = 3600 * 24 -- cookie expires = 1 daylocal cookie_table = {\"hello=world; Path=/;Domain=/; Expires=\" .. ngx.cookie_time(ngx.time() + expires),\"hello2=world2; Path=/;Domain=/; Expires=\" .. ngx.cookie_time(ngx.time() + expires),\"hello3=world3; Path=/;Domain=/; Expires=\" .. ngx.cookie_time(ngx.time() + expires)}ngx.header[\"Set-Cookie\"] = cookie_table 更多cookie相关可以参考wikipedia:https://en.wikipedia.org/wiki/HTTP_cookie 也可以直接使用github上面分享的lua的cookie封装好的库。","categories":[{"name":"OpenResty","slug":"OpenResty","permalink":"https://renqiangme.github.io/categories/OpenResty/"}],"tags":[{"name":"OpenResty","slug":"OpenResty","permalink":"https://renqiangme.github.io/tags/OpenResty/"},{"name":"Cookie","slug":"Cookie","permalink":"https://renqiangme.github.io/tags/Cookie/"}]},{"title":"Linux学习之用户管理","slug":"Linux学习之用户管理","date":"2016-12-24T12:14:09.000Z","updated":"2019-03-18T09:55:37.589Z","comments":true,"path":"2016/12/24/Linux学习之用户管理/","link":"","permalink":"https://renqiangme.github.io/2016/12/24/Linux学习之用户管理/","excerpt":"用户配置文件用户管理简介 .越是对服务器安全性要求高的服务器,越需要建立合理的用户权限等级制度和服务器操作规范 .在linux中主要是通过用户配置文件来查看和修改用户信息","text":"用户配置文件用户管理简介 .越是对服务器安全性要求高的服务器,越需要建立合理的用户权限等级制度和服务器操作规范 .在linux中主要是通过用户配置文件来查看和修改用户信息 用户信息文件/etc/passwdvim /etc/passwd如果不知道这个文件是干什么的 可以执行 man 5 passwd 查看帮助用户很多:如 root:x:0:0:root:/root:/bin/bash 第1个字段:用户名称 第2个字段:密码标志 (直接一个x 并没有直接列出密码 而是放在了/etc/shadow下面 原因/etc/passwd 各个用户都是可读的,就可能被暴力拆解 而/etc/shadow也是通过加密的 只有管理员有权限!) 第3个字段:UID(用户ID) 0:超级用户 1-499系统用户(伪用户)500-65535:普通用户 第4个字段:GID(用户初始组ID) 组:相同类型的集合123初始组:linux用户一建立就默认属于一个组 跟window不一样 window每添加一个用户就会放入到user组里面。而linux你创建一个user1就会创建一个跟用户名相同名的user1用户组。每个用户必须要有一个初始组且只能有一个。建议:虽然初始组能够改,但并不建议改,原因:改了初始组把所建立的文件搞糊涂!附加组:指用户可以加入多个其他的用户组,并拥有这些组的权限,附加组可以有多个。 第5个字段:用户说明 第6个字段:家目录 普通用户:/home/用户名 超级用户:/root/ 第7个字段:登录之后的Shell Shell 就是Linux的命令解释器 在/etc/passwd当中,除了标准Shell是/bin/bash之外,还可以写如/sbin/nologin 影子文件/etc/shadow实际就是 /etc/passwd的影子文件 只是权限更低 都是000000000例如: root:$6$JmdhYiD4y7zwPiMu$kq9iu9C.0on1X1Ia14QZslgSWRy1pK8sQsVmCauGykqOFAyawpvFkaVM83nuqum4oJ92Y3sPPIXlpw5Fksp3m/:16326:0:99999:7:::第一个字段:用户名第二个字段:加密密码 加密算法升级为SHA512散列加密算法 如果密码位是“!!”或“*”代表没有密码,不能登录第三个字段:密码最后一次修改日期 使用1970年1月1日作为标准时间,每过一天时间戳加1第四个字段:两次密码的修改间隔时间(和第3个字段相比)第五个字段:密码有效期(和第3个字段相比)第六个字段:密码修改到期前的警告天数(和第5字段相比)第七个字段:密码过期后的宽限天数(和第五个字段相比) 0:代表密码过期后立即失效 1:代表密码永远不会失效第八个字段:账号失效时间 要用时间戳表示 把时间戳换算为日期 date -d “1970-01-01 16066 days” 把日期换算为时间戳 echo $((date –date=”2014/01/06” +%s)/86400+1)第九个字段:保留 组信息文件/etc/group和组密码文件/etc/gshadow组信息文件/etc/group 例如:root:x:0:第一个字段:组名 第二个字段:组密码标志 第三个字段:GID 第四个字段:组中附加用户组密码文件/etc/gshadow第一个字段:组名 第二个字段:组密码 第三个字段:组管理员用户名 第四个字段:组中附加用户 用户管理相关文件用户的家目录普通用户:/home/用户名,所有者和所属组都是此用户,权限是700超级用户:/root/ 所有者和所属组都是root用户,权限是550 如果你想把普通用户变为超级用户 家目录并不会修改 只是权限变为了超级权限。普通用户变为超级用户的方法:修改用户信息文件/etc/passwd 把uid变为0 这样我们再登录的时候就会发现输入命令前面如果是#就说明是超级用户 如果是$就是普通用户 用户的邮箱/var/spool/mail/用户名是不是和我们用的QQ邮箱一样呢?QQ邮箱之所以能够转发是靠QQ自带的服务器进行转发,linux虽然可以作为客户端收发邮件,但是也要依赖服务器去发送邮件。QQ邮箱有专门的服务器去发送邮件,在linux中用户之间可以传递邮件,利用linux的内存直接转发,每个用户都有邮箱,我们用的只是邮箱的客户端,并没有搭建服务器。 用户模板目录/etc/skel在用户家目录执行 ls -a 会发现出现了一些隐藏文件,这是在用户创建的时候自动创建的。这些自动创建的文件是从/etc/skel自动拷贝过去的。如果我想让所有用户一添加就在家目录出现某个文件,比如你登陆的我的系统要遵守xx规则,几点关机,警告信息…等等。只需要在/etc/skel下面添加文件就行了! 用户管理命令用户添加命令 useradd123456789格式:useradd [选项] 用户名 选项: -u UID: 手工指定用户的UID号 -d 家目录: 手工指定用户的家目录 -c 用户说明: 手工指定用户的说明 -g 组名: 手工指定用户的初始组 -G 组名: 指定用户的附加组 -s shell: 手工指定用户的登录shell 。默认是/bin/bash 设置用户默认值的文件 /etc/default/useradd 和 /etc/login.defs 修改用户密码 passwd12345678910111213141516passwd [选项] 用户名 选项: -S 查询用户密码的密码状态。仅root用户可用。 eg: passwd -S qingwa qingwa PS 2014-09-14 0 99999 7 -1 #用户名密码设定时间2014-09-14 密码修改间隔时间(0)密码有效期(99999) #警告时间(7) 密码不失效(-1) 实际上就跟 /etc/shadow里面看到的一样 -l 暂时锁定用户。仅root用户可用。在密码前面加上!! 让其密码失效 -u 解锁用户。仅root用户可用。 --stdin 可以通过管道符输出的数据作为用户的密码 echo "123" | passwd --stdin qingwa 管道符:直接将前面的输出作为后面的输入 修改用户信息 usermod1234usermod -c "test user" lamp #修改用户的说明usermod -G root lamp #把lamp用户加入root组usermod -L lamp #锁定用户usermod -U lamp #解锁用户 修改用户密码状态 chage1234567891011chage [选项] 用户名选项:-l 列出用户的详细密码状态-d 日期 修改密码最后一次更改日期(shadow第3字段)-m 天数 两次密码修改间隔(shadow第4字段)-M 天数 密码有效期(shadow第5字段)-W 天数 密码过期前警告天数(shadow第6字段)-I 天数 密码过后宽限天数(shadow第7字段)-E 日期 账号失效时间(shadow第8字段)因为选项过多直接修改vim /etc/shadow文件就行了常用的一个:chage -d 0 qingwa #这个命令其实是把密码修改日期归0了 这样用户一登陆就要修改密码 删除用户 userdel1234userdel [-r] 用户名选项: -r 删除用户的同时删除用户家目录 id 用户名 #查看用户的uid 组id 用户切换命令 su1234567su [选项] 用户名选项: - #选项只使用“-”代表连带用户的环境变量一起切换 -c 命令 #仅执行一次命令,而不切换用户身份eg: su - root #切换成rootsu - root -c "useradd qinwa" 不切换成root,但是执行useradd命令添加qingw用户 用户组管理命令添加用户组12groupadd [选项] 组名 选项:-g GID #指定组ID 修改用户组123groupmod [选项] 组名-g GID #修改组ID-n 新组名 #修改组名 eg:groupmod -n testgrp group1 #把组名group1修改为testgrp 删除用户组1groupdel 组名 把用户添加入组或从组中删除123gpasswd 选项 组名选项:-a 用户名 #把用户加入组 -d 用户名 #把用户从组中删除","categories":[{"name":"Linux","slug":"Linux","permalink":"https://renqiangme.github.io/categories/Linux/"}],"tags":[{"name":"Linux","slug":"Linux","permalink":"https://renqiangme.github.io/tags/Linux/"}]},{"title":"Linux学习笔记之常用命令之目录处理命令","slug":"Linux学习笔记之常用命令之目录处理命令","date":"2016-12-24T10:35:29.000Z","updated":"2019-03-18T09:48:02.716Z","comments":true,"path":"2016/12/24/Linux学习笔记之常用命令之目录处理命令/","link":"","permalink":"https://renqiangme.github.io/2016/12/24/Linux学习笔记之常用命令之目录处理命令/","excerpt":"————————常用命令————— 1文件处理命令 1.1命令格式与目录处理命令 1.2目录处理命令 1.3文件处理命令 1.4链接命令 2权限管理命令 3文件搜索命令 4帮助命令 5用户管理命令 6压缩解压命令 7网络命令 8关机重启命令","text":"————————常用命令————— 1文件处理命令 1.1命令格式与目录处理命令 1.2目录处理命令 1.3文件处理命令 1.4链接命令 2权限管理命令 3文件搜索命令 4帮助命令 5用户管理命令 6压缩解压命令 7网络命令 8关机重启命令 1、文件处理命令1.1 命令格式:命令 [-选项][参数] 方括号是可选的 例:ls -la /etc 说明: 1、个别命令使用不遵循此格式 2、当有多个选项时,可以写在一起 -l a—>-la 3、简化选项与完整选项 -a等于–all linux简化的习惯一个- 完整的得用两个– 1.2 目录处理命令:ls 英文原意:list命令所在路径:/bin/ls执行权限:所有用户功能描述:显示目录文件 语法:ls 选项[-ald][文件或目录] -a 显示所有文件,包括隐藏文件 [all] -l 详细信息显示 [long] -h 人性化显示把文件大小显示为KB MB [human] -d 查看目录属性 [directory] -i 查看文件的i节点,可以理解为系统会给每个文件一个ID号 [inode] 任何一个文件的详细信息: -rw-r--r-- 文件类型:- 二进制文件 d 目录[directory] l 软链接文件[link] rw- r-- r-- u g o u所有者 g所有组 o其他人 (在上面rw-三个一组) r读 w写 x执行 mkdir 英文原意:make directories命令所在路径:/bin/mkdir执行权限:所有用户语法:mkdir-p[目录名]功能描述:创建根目录 -p递归创建 范例: mkdir -p /tmp/Japan/boduo mkdir /tmp/Japan/longze/tmp/Japan/canjing 这个会报错 应该如果不-p递归 你在一个本来不存在的目录里面再去创建目录 肯定是不行的 cd 英文原意:change directory;命令所在路径:shell内置命令;执行权限:所有用户;语法:cd[目录];功能描述:切换目录 范例: cd /tem/Japan/boduo切换到指定目录 cd .. 回到上一级目录 rmdir 英文原意:remove empty directories命令所在路径:/bin/rmdir执行权限:所有用户语法:rmdir[目录名]功能描述:删除空目录 如果不为空得用rm -r xxx 范例:rmdir /tmp/Japan/boduo cp 英文原意:copy ; 命令所在路径:/bin/cp ;执行权限:所有用户;语法:cp -rp [原文件或目录][目标目录] -r 复制目录 -p 保留文件属性功能描述:复制文件或目录(可以同时复制多个文件或目录 只要指定目标位置) 例子:mv -r /tmp/Japan /root/riben 把tmp目录下面的Japan复制到root目录下面并且更改名字为riben mv 英文原意:move命令所在路径:/bin/mv执行权限:所有用户;语法:mv[原文件或目录][目标目录]功能描述:剪切文件或改名 例子:mv /tmp/Japan /root/riben 把tmp目录下面的Japan剪切到root目录下面并且更改名字为riben 改名:cd /rootmv Japan riben 如果在当前目录下面mv不就是在改名么! rm英文原意:remove命令所在路径:/bin/rm执行权限:所有用户语法:rm -rf[文件或目录] -r 删除目录 -f 强制执行功能描述:删除文件 rm grub.config 1.3 文件处理命令 touch命令所在路径:/bin/touch执行权限:所有用户语法:touch[文件名]功能描述:创建空文件 范例:touch Japanlovestory.list //在当前路径下面创建文件 touch /root/Japanlovestory.list //如果加了完整路径则在root路径下面创建一个空文件 linux中并不像window中对特殊符号不允许 但是建议在Linux中也别用 另外注意空格: touch program files 因为在window中可以在文件命名的时候 中间去敲一个空格 但是注意!!这条命令会创建两个文件 program files 如果真的需要创建一个“program files”的文件,可以用引号引起来 touch "program files" 虽然可以敲一个空白符 但是并不建议这么做,因为在以后查找的时候 会产生很多麻烦 cat命令所在路径:/bin/cat执行权限:所有用户语法:cat[文件名]功能描述:显示文件内容 -n显示行号 范例:cat /etc/issue cat -n /etc/services 此命令并适合浏览很长很长的文件!要用more tac命令所在路径:/usr/bin/tac执行权限:所有用户语法:tac [文件名]功能描述:显示文件内容(反向列示)—反过来倒着显示 但是并不支持显示行号 范例:tac /etc/services more命令所在路径:/bin/more执行权限:所有用户语法:more [文件名] 空格或者f 翻页 enter 换行 q或Q 退出功能描述:分页显示文件内容 范例:more /etc/services不足:只可以按往下面翻页 不能往上面翻页 所以得用:less less命令所在路径:/usr/bin/less执行权限:所有用户 语法:less [文件名] pageup向上翻页 空格或者f 翻页 enter 换行 向上方向箭头 上面一行 q或Q 退出 /xxx 搜索关键词xxx n向下切换搜索的结果所在位置[next]功能描述:分页显示文件内容(可向上翻页 并且可以查找) 范例:less /etc/services head命令所在路径:/usr/bin/head执行权限:所有用户语法:head [文件名]功能描述:显示文件前面几行 -n指定行数 范例:head -n 20 /etc/services如果你不指定行号,会默认显示10行。 tail命令所在路径:/usr/bin/tail执行权限:所有用户语法:tail [文件名]功能描述:显示文件后面几行 -n指定行数 -f动态显示文件末尾内容 常用来监控日志 因为它会动态显示 范例:tail -n 18 /etc/services如果你不指定行号,会默认显示10行。 1.4链接命令 ln英文原意:link命令所在路径:/bin/ln执行权限:所有用户 语法:ln -s [原文件][目标文件] -s 创建软链接功能描述:生成链接文件 范例:ln -s /etc/issue /tmp/issue.soft 创建文件/etc/issue的软链接/tmp/issue.soft ln /etc/issue /tmp/issue.hard 创建文件/etc/issue的硬链接/tmp/issue.hard 硬链接没有 -s选项 软链接特征:类似windows快捷方式 1:lrwxrwxrwx l开头表示文件类型为软链接 软链接所有用户的文件权限均为可读可写可执行 2:文件大小 当我们创建一个软链接的时候 跟原文件相比 大小相比原文件小很多,因为它只是一个符号链接 3:/tmp/issue.soft -> /etc/issue 箭头指向源文件 什么时候用软链接即什么时候在window中用快捷方式 硬链接特征: 1:拷贝 cp-p + 同步更新 echo "www.thaibl.com" >> /etc/issue (相当于拷贝并保留原文件属性(最后修改时间,大小,内容)外加同步更新,就算一个文件删除了,另外一个依然存在) 2:通过i节点识别。 当给某个文件创建一个硬链接的时候 我们会发现硬链接文件的节点跟原文件的节点一样。[所以才会实时更新][ls -i] 3:不能跨分区 比如不能把都在 /tmp目录下面的文件 创建到/bin目录下面去 而软链接没有这个限制 4:不能针对目录使用[不能跟某个目录创建硬链接,而软链接没有这个限制] 2、权限管理命令 代表字符 权限 对文件的含义 对目录的含义 r 读权限 可以查看文件的内容 可以列出目录中的内容 w 写权限 可以修改文件内容 可以在目录中创建删除文件 x 执行权限 可以执行文件 可以进入目录 注意:对所属用户来说 一个文件是否有删除权限,要看文件所在的目录是否有写权限假如我们在 root下面创建一个temp目录 然后touch /temp/testfile 然后chmod 777 /temp 再去创建useradd qingwa passwd qingwa 创建一个普通用户qingwa之后再去登录,执行rw /temp/testfile 由于我们设置了temp目录对普通用户来说也是有写的权限,所以能删除!! chmod命令英文原意:change the permissions mode of a file命令所在路径:/bin/chmode执行权限:所有用户 语法: 一、chmod [{ugoa}{+-=}{rwx}][文件或目录] //u所有者 g所有组 o其他人 +增加权限 -减少权限 =不管你之前有什么权限,现在必须是这个权限 rwx可读可写可执行 例子:chmod u+x /tmp/test.html 即给test.html 所有者增加x可执行的权限 chmod g+x,o-r /tmp/text/html 可以给多个用户修改多个权限,用逗号隔开就行了 二、[mode=421][文件或目录] -------通常用这个 //权限的数字表示,r--4 w---2 x---1 rwxrw-r-- 7 6 4 例子:假如我们想要这个权限640 rw-r----- 可以这样:chmod 640 /tmp/test.html 三、-R 递归修改 假如在tmp/a/b thmod -R 777 /tmp/a 因为是递归修改 我们ls -lh的时候会发现b目录的权限也会被递归修改为777 功能描述:改变文件或目录权限 chown命令英文原意:change file ownership命令所在路径:/bin/chown执行权限:所有用户语法:chown[用户][文件或目录]功能描述:改变文件或目录的所有者 范例:chown qingwa yang //改变文件qingwa的所有者为yang chgrp命令英文原意:change file group ownership命令所在路径:/bin/chgrp执行权限:所有用户语法:chgrp[用户组][文件或目录]功能描述:改变文件或目录的所属组 范例:chgrp lampbrother fengjie //改变文件fengjie的所属组为lampbrother [groupadd 添加用户组] umask英文原意:the user file-creation mask命令所在路径:Shell内置命令执行权限:所有用户语法:umask [-S] -S 以rwx形式显示新建文件缺省权限功能描述:显示、设置文件的缺省权限范例:umask -S注意:linux中创建一个新文件默认是rw-r–r–出于安全考虑是不让新建的文件有可执行的权限644假如我想修改默认新建文件的权限,就是以后创建的新文件的权限为rwxr-xr– 754需要这么做:777-754=023umask 023以后新建的文件的权限就是:rwxr-xr– 754 3、文件搜索命令 在linux中,最重要的事情不是搜索你能找得到文件,而是应该规划好目录结构,放好位置,因为搜索会很占用系统资源,如果在服务器访问高发期间,小心崩溃。 find命令所在路径:/bin/find执行权限:所有用户语法:find [搜索范围][匹配条件]功能描述:文件搜索 A:find /etc -name init 在目录/etc中查找文件名为 init [-iname不区分大小写] B:find /etc -size +204800 在目录/etc下查找大于100M的文件 +n 大于 -n小于 n等于 注意:在linux中得换算为数据块 1数据块等于512字节即0.5k--100M=102400kb=204800kb C:find / -user qingwa 在根目录下面查找所有者为qingwa的文件 -group根据所属组查找 D:find /etc -cmin -5 在/etc下查找5分钟内被修改过属性的文件和目录 -amin 访问时间[access] -cmin 文件属性[change] -mmin 文件内容[modify] +xx表示超过时间 -xx表示多少时间以内 E:find /etc -size +163840 -a -size -204800 在/etc下查找大于80MB小于100MB的文件 -a两个条件同时满足 [and] -o两个条件满足任意一个即可 F:find /etc -name inittab -exec ls -l {}\\; 在/etc下查找inittab文件并显示其详细信息 -exec/ok 命令 {}\\; 对搜索结果执行操作 G:-type根据文件类型查找 f文件 d目录 l软链接文件 H: 根据i节点查找 find . -inum 31531 -exec rm {}\\;查找节点为31531的文件并立即执行删除命令 locate命令所在路径:/usr/bin/locate执行权限:所有用户语法:locate 文件名功能描述:在文件资料库中查找文件 范例:locate inittab -i 选项不区分大小写 注意1: locate搜索速度很快 相当于window那个everything那个软件。 原因是:用locate locate 会得到很多行信息,系统会定期把信息存放到mlocate.db文件里, 不像find会在某个分区某个文件去查找,只需要搜索mlocate.db这个文件就行了。 但是有一个问题,新建的文件实际上是没有被收录到这个文件里的,所以用locate去查找的时候,是查找不了的。 解决办法:执行下update命令 回去更新这个文件资料库,再去查找就会找到了。 注意2:locate是无法找到临时目录下面的文件的 比如/tmp which命令所在路径:/usr/bin/which执行权限:所有用户语法:which命令功能描述:搜索命令所在目录及别名信息 范例:which ls whereis 命令所在路径:/usr/bin/whereis执行权限:所有用户语法:whereis [命令名称]功能描述:搜索命令所在目录及帮助文档路径 范例:whereis ls grep命令所在路径:/bin/grep执行权限:所有用户语法:grep -iv[指定字串][文件]功能描述:在文件中搜寻字串匹配的行并输出 -i 不区分大小写 -v 排除指定字串 范例:grep -i mysql /root/install.log 在/root/install.log文件中不区分大小写的查找mysql grep -v ^# /etc.initab排除以#开头的行的字符串 4、帮助命令 man英文原意:manual命令所在路径:/usr/bin/man执行权限:所在用户语法:man[命令或配置文件]功能描述:获得帮助信息 范例:man ls 查看ls命令的帮助信息 man services 查看配置文件services的帮助信息 man 5 passwd 查看用户信息 Linux中,执行man命令查询帮助文档时,是以vi形式打开帮助文档,所以退出时应该键入:q命令 whatis 命令查看到命令简短的介绍信息[该命令是干什么的] apropos 配置文件的名称查看配置文件的简短信息 技巧:命令 –help 会把该命令常见的选项列出来 touch –help info 跟 man差不多也是显示帮助信息 help命令所在路径:Shell内置命令执行权限:所有用户语法:help命令功能描述:获得Shell内置命令的帮助信息范例:help umask 查看umask命令的帮助信息 用which找不到的命令都是Shell内置命令 5、用户管理命令 useradd 命令所在路径:/usr/sbin/useradd执行权限:root语法:useradd用户名功能描述:添加新用户 范例:useradd qingwa passwd命令所在路径:/usr/bin/passwd执行权限:所有用户语法:passwd用户名功能描述:设置用户密码 范例 passwd amdin888 普通用户只能更改自己的密码 而root可以更改所有用户的密码 who命令所在路径:/usr/bin/who执行权限:所有用户语法:who功能描述:查看登录用户信息 范例:who 显示规则:登录用户名 登录终端 tty本地终端 pts表示远程终端(用不同的数字,终端号来区分不同的登录终端) 登录时间(什么时候登录的) w命令所在路径:/usr/bin/w执行权限:所有用户语法:w功能描述:查看登录用户详细信息 范例:w up linux连续运行多少时间了([uptime命令也行]) ; load average负载均衡的三个值 ; IDLE表示用户登录过来空闲了多久了 ; JCPU当前用户登录过来累计的占用时间; PCPU表示当前登录过来用户当前操作占用的时间 ; WHAT表示当前执行的什么操作、命令 6、压缩解压命令 .gz(window中很少).zip(linux window中都有).rar(在linux中在需要装一个rar for linux的解压软件) gzip命令所在路径:/bin/gzip执行权限:所有用户语法:gzip [文件]功能描述:压缩文件 注意:跟window是不一样的,只能压缩文件,不能压缩目录,而且压缩完不保留原文件 只剩压缩包了压缩后文件的格式:.gz gunzip命令英文原意:GUNunzip命令所在路径:/bin/gunzip执行权限:所有用户语法:gunzip[压缩文件]功能描述:解压.gz的压缩文件 范例:gunzip buduo.gz tar压缩命令所在路径:/bin/tar执行权限:所有用户 语法:tar 选项[-zcf][压缩后文件名][目录] -c打包 !!! -v显示详细信息 -f指定文件名 -z打包同时压缩功能描述:打包目录压缩后文件格式:.tar.gz 例子:tar -cvf Japan.tar.gz Japan 把Japan这个目录压缩成Japan.tar tar解压 -x解包 !!!! -v显示详细信息 -f指定解压软件 -z解压缩 范例:tar -zxvf Japan.tar.gz zip命令所在路径:/usr/bin/zip执行权限:所有用户语法:zip 选项[-r] [压缩后文件名] [文件或目录] -r 压缩目录功能描述:压缩文件或目录压缩后文件格式:.zip 压缩原文件仍未保留 还会显示压缩比 但是压缩比并没有 gzip tar 那么强 解压:unzip [压缩文件] bzip2命令所在路径:/usr/bin/bzip2执行权限:所有用户语法:bzip2 选项 [-k][文件] -k 产生压缩文件后保留原文件功能描述:压缩文件压缩文件格式:.bz2 范例:bzip2 -k boduo tar -cjf Japan.tar.bz2 Japan 把-z换成-j就可以利用tar压缩成.tar.bz2格式 这个压缩格式比率惊人。 bunzip2命令所在路径:/usr/bin/bunzip2执行权限:所有用户语法:bunzip2 选项[-k][压缩文件] -k解压后保留原文件功能描述:解压 范例:bunzip2 -k boduo.bz2 tar -xjf Japan.tar.bz2 7、网络命令 write指令所在路径:/usr/bin/write执行权限:所有用户语法:write <用户名>功能描述:给在线用户发信息(w可以看到哪些用户在线),ctrl+D保存结束 范例:# write linzhiling xxxxxxxxxxxxx ctrl+D保存结束 wall命令英文原意:write all命令所在路径:/usr/bin/wall执行权限:所有用户语法:wall [message]功能描述:发广播信息(给所有在线用户) 范例:# wall qingwa is a animal ping命令所在路径:/bin/ping执行权限:所有用户语法:ping 选项 IP地址 -c 指定发送次数功能描述:测试网络连通性 范例:# ping 192.168.88.99 ctrl+c结束 ifconfig命令英文原意:interface configure命令所在路径:/sbin/ifconfig执行权限:root语法:ifconfig 网卡名称 IP地址功能描述:查看和设置网卡信息 范例:# ifconfig eth0 192.168.88.99 linux有两套网卡eth0|eth1…本地真实的网卡,按照数字方式一次后推lo 回环网卡,用来本机通信和测试的,地址也是固定的 都是127.0.0.1 mail命令所在路径:/bin/mail执行权限:所有用户语法:mail[用户名]功能描述:查看发送电子邮件 范例:mail root 这个就不像write命令 可以用户不在线 ctrl+D保存结束 last 命令所在路径:/usr/bin/last执行权限:所有用户语法:last功能描述:列出目前与过去登入系统的用户信息 范例:# last [运用非常广泛]这个命令非常有效常用的命令!!可以看 有什么其他用户登录了服务器. 如果有时候我们不想那么多信息,想看到用户最后一次登录的时间,可以用lastlog命令!! traceroute命令所在路径:/bin/traceroute执行权限:所有用户语法:traceroute功能描述:显示数据包到主机间的路径 范例:traceroute www.thaibl.com[运用非常广泛] netstat命令所在路径:/bin/netstat执行权限:所有用户语法:netstat [选项]功能描述:显示网络相关信息 选项: -t:TCP协议 传输控制协议的简称【三次握手 安全】相当于A打电话B A你是?B你是? AB要通话了 -u:UDP协议 用户数据报协议【快 不管你在不在线 直接甩给你】相当于发短信 不管你是谁、关机与否、可能被谁看到不管 -l:监听 -r:路由 -n:显示IP地址和端口号 范例: # netstat -tlun 查看本机监听的端口 # netstat -an 查看本机所有的网络连接 # netstat -rn 查看本机路由表 [运用非常广泛,非常重要] setup命令所在路径:/usr/bin/setup执行权限:root语法:setup功能描述:配置网络 范例:# setup 挂载命令mount命令所在位置:/bin/mount执行权限:所有用户命令语法:mount [-t 文件系统] 设备文件名 挂载点 范例: # mount -t iso9660 /dev/sr0/ /mnt/cdrom = mount /dev/sr0/ /mnt/cdrom umount 设备文件名|挂载点umount /dev/sr0 卸载光盘需要跳到宿主目录去执行卸载命令 8、关机重启命令 shutdown 命令语法:shutdown [选项] 时间 选项:-c 取消前一个关机命令 -h 关机 -r 重启 eg:shutdown -h now 马上关机 shutdown -h 20:30 晚上八点关机 shutdown -r now 马上重启 shutdown -c 取消前一个关机命令 linux中还有其他重启关机命令,但是早期只有shutdown保存原来开启的服务 现在其他的也有了 但还是推荐这个老命令 提醒:关机或重启之前必须先把服务停掉!这样才能保证用户不能碰触我,硬盘才会空闲下来,才会重启。 服务器不能关机 只能重启!!! 其他关机命令:halt poweroff 这个就不要用了 直接断电!!! init 0 其他重启命令:reboot init 6 系统运行级别: 0:关机 1:单用户(类似windows启动时按F8进入安全模式,其实就是启动最小的服务,其他多余附加的程序都不用,只启动核心的程序,用来做一些修复。只能root登录进去) 2:不完全多用户,不含NFS服务 3:完全多用户 4:未分配 5:图形界面 6:重启 cat /etc/inittab #修改系统默认运行级别 id:3:initdefault: `runlevel` #查询系统运行级别 退出登录命令:logout","categories":[{"name":"Linux","slug":"Linux","permalink":"https://renqiangme.github.io/categories/Linux/"}],"tags":[{"name":"Linux","slug":"Linux","permalink":"https://renqiangme.github.io/tags/Linux/"}]},{"title":"Composer与__autoload自动加载冲突问题","slug":"Composer与__autoload自动加载冲突问题","date":"2016-12-24T08:53:08.000Z","updated":"2019-03-18T04:38:51.215Z","comments":true,"path":"2016/12/24/Composer与__autoload自动加载冲突问题/","link":"","permalink":"https://renqiangme.github.io/2016/12/24/Composer与__autoload自动加载冲突问题/","excerpt":"最近改一些旧的项目遇到的一个有意思的问题。一个项目从入口文件进来,定义了自动加载函数__autoload()1234function __autoload($className){ $class = $className . '.class.php'; require_once(CLASS_DIR.$class);}","text":"最近改一些旧的项目遇到的一个有意思的问题。一个项目从入口文件进来,定义了自动加载函数__autoload()1234function __autoload($className){ $class = $className . '.class.php'; require_once(CLASS_DIR.$class);} 然后这个旧的项目在程序某个操作类下面引入了composer来自动加载。1234567891011121314151617181920<?phprequire BASIC_PATH.'vendor/autoload.php';print_r(spl_autoload_functions());class Testtest{ public function __construct($upload_type,$act_id,$img_name=''){ print_r(spl_autoload_functions()); echo '<br/><br/>'; $client = new MongoDB\\Client($GLOBALS['config']['mongodb_loho']); var_dump($client); echo '<br/><br/>'; $upload = new Upload(); var_dump($upload); echo '<br/><br/>'; $client2 = new MongoDB\\Client($GLOBALS['config']['mongodb_loho']); var_dump($client2); echo '<br/><br/>'; $upload2 = new Upload(); var_dump($upload2); }} 打印结果如下:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657Array( [0] => Array ( [0] => Composer\\Autoload\\ClassLoader Object ( [prefixLengthsPsr4:Composer\\Autoload\\ClassLoader:private] => Array ( [M] => Array ( [MongoDB\\] => 8 ) ) [prefixDirsPsr4:Composer\\Autoload\\ClassLoader:private] => Array ( [MongoDB\\] => Array ( [0] => E:\\UPUPW_NP5.5_64\\htdocs\\tupian\\vendor/mongodb/mongodb/src ) ) [fallbackDirsPsr4:Composer\\Autoload\\ClassLoader:private] => Array ( ) [prefixesPsr0:Composer\\Autoload\\ClassLoader:private] => Array ( ) [fallbackDirsPsr0:Composer\\Autoload\\ClassLoader:private] => Array ( ) [useIncludePath:Composer\\Autoload\\ClassLoader:private] => [classMap:Composer\\Autoload\\ClassLoader:private] => Array ( ) [classMapAuthoritative:Composer\\Autoload\\ClassLoader:private] => [missingClasses:Composer\\Autoload\\ClassLoader:private] => Array ( ) ) [1] => loadClass ))Array( [0] => __autoload)<br/><br/>MongoDB\\Client.class.php 我们会发现,上面的代码,进行到构造函数里面的时候,打印出返回所有已注册的__autoload()函数的时候,只有入口文件定义的,这是为什么呢?按理说使用了require包含的类库文件作用是全局的,手册上面有:When a file is included, the code it contains inherits the variable scope of the line on which the include occurs. Any variables available at that line in the calling file will be available within the called file, from that point forward. However, all functions and classes defined in the included file have the global scope!使用get_included_files()函数打印出来的时候也是看得到的。然后在在网上搜索了下,这篇文章恰好能够解释:http://www.jb51.net/article/31279.htm 把require BASIC_PATH.’vendor/autoload.php’;放在外面,使用spl_autoload_functions函数打印的时候,发现并没有把composer的加入到类里面,估计是scope的问题,程序执行到这里,发现已经定义了全局的自动加载函数__autoload,就执行执行这个自动加载的函数,然后找不到直接抛出一个严重错误,中断执行,但是在构造函数开头添加一句:1spl_autoload_register('__autoload'); 把定义的全局构造函数加入到全局变量autoload_functions的hash table中,就既可以自动找到composer引入的类,又可以自动找到全局的autoload定义的类。从而实现自动加载。 加入把文件开头包含composer的入口文件移动到构造函数里面,就会发现全局的自动加载的函数的类找不到了,因为:__autoload 方法在 spl_autoload_register 后会失效,因为 autoload_func 函数指针已指向 spl_autoload 方法。 解决办法也是:1spl_autoload_register( '__autoload' ); 把__autoload 方法加入 autoload_functions list","categories":[{"name":"PHP","slug":"PHP","permalink":"https://renqiangme.github.io/categories/PHP/"}],"tags":[{"name":"PHP","slug":"PHP","permalink":"https://renqiangme.github.io/tags/PHP/"},{"name":"Composer","slug":"Composer","permalink":"https://renqiangme.github.io/tags/Composer/"}]},{"title":"PHP遍历某个目录下面的文件并使用多进程记录到数据库的几种方法比较","slug":"PHP遍历某个目录下面的文件并使用多进程记录到数据库的几种方法比较","date":"2016-12-24T08:00:30.000Z","updated":"2019-03-18T04:43:02.617Z","comments":true,"path":"2016/12/24/PHP遍历某个目录下面的文件并使用多进程记录到数据库的几种方法比较/","link":"","permalink":"https://renqiangme.github.io/2016/12/24/PHP遍历某个目录下面的文件并使用多进程记录到数据库的几种方法比较/","excerpt":"最近工作需要写一个脚本去跑某个目录下面的文件然后记录到数据库,比较了下三种遍历目录的方法. 打印了测试目录weixin下面有多少文件,文件一共3千多,层级深度还是比较深的。","text":"最近工作需要写一个脚本去跑某个目录下面的文件然后记录到数据库,比较了下三种遍历目录的方法. 打印了测试目录weixin下面有多少文件,文件一共3千多,层级深度还是比较深的。1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768<?php/* * php import.php xxx目录 比如:php import.php images * 此目录是跟脚本同级顶级的目录 */$t1 = microtime(true);define('BASIC_PATH',P(dirname(__FILE__)).'/');if(empty($argv)){ exit(\"请在命令行执行此脚本\\n\");}if(count($argv) <= 1 || empty($argv[1])){ exit(\"请输入需要导入的文件夹,比如php import.php images\\n\");}//默认只取第一个参数,暂不多个文件夹处理$need_import_dir = BASIC_PATH.$argv[1];//调用法1getFiles1($need_import_dir);//调用法2getFiles2($need_import_dir);//调用法3$directory = new RecursiveDirectoryIterator($need_import_dir);getFiles3($directory);$t2 = microtime(true);echo '耗时'.round($t2-$t1,3).\"秒\\n\";//自定义函数function P($path){return str_replace('\\\\','/',$path);}//法1:传统遍历目录function getFiles1($dir){ if(!is_dir($dir)){ exit('不是dir'); } $handle = opendir($dir); if($handle){ while(false !== ($file = readdir($handle))){ if($file != '.' && $file != '..'){ $filename = $dir.\"/\".$file; if(is_file($filename)){ echo 'File path = '.$filename.\"\\n\"; }else{ getFiles1($filename); } } } closedir($handle); }}//法2:迭代器遍历目录,并将这个树形结构的迭代器展开为一维结构function getFiles2($dir){ $directory = new RecursiveDirectoryIterator($dir,RecursiveDirectoryIterator::SKIP_DOTS); $ierator = new RecursiveIteratorIterator($directory,RecursiveIteratorIterator::LEAVES_ONLY); foreach($ierator as $fileinfo){ echo 'File path = ' .$fileinfo->getPathname(). \"\\n\"; }}//法3:迭代器+递归函数遍历目录,$dir为RecursiveDirectoryIterator迭代器对象function getFiles3($dir){ for(;$dir->valid();$dir->next()){ if($dir->isDir() && !$dir->isDot()) { if($dir->haschildren()) { getFiles3($dir->getChildren()); } }elseif($dir->isFile()){ echo 'File path = '.$dir->getPathName().\"\\n\"; } }} 法1:测试打印了几次,耗时分别在0.048,0.062,0.078法2:测试打印了几次,耗时分别在0.092,0.103,0.151,0.065法3:测试打印了几次,耗时分别在0.037,0.044,0.039,0.045 法2:主要是使用了迭代器RecursiveIteratorIterator,作用是把多维的树形数组转成一维,耗时较多 法1相对法3,传统的不断打开文件句柄也会耗时些 所以建议还是使用法3,关于SPL(PHP标准类库)的了解文章:文章地址 在编码中我们可以多使用SPL标准类库提供给我们的类,告别一些传统的方法,使用一些新的解决方法和思维。 现在已经能够遍历出某个目录下面的所有文件了。如果还想追求速度,可以使用多进程pcntl相关函数来完成。我其中使用了LimitIterator这个迭代器来控制每个进程的处理的遍历出来文件的偏移,这样子来加快任务处理速度,进程的数量我是通过命令find weixin -type f -print | wc -l查看目录下面的文件个数计算的来设置每个进程处理文件个数偏移的。12345678910111213141516171819202122232425262728//$need_import_dir需要导入文件的目录$directory = new RecursiveDirectoryIterator($need_import_dir,RecursiveDirectoryIterator::SKIP_DOTS);$ierator = new RecursiveIteratorIterator($directory,RecursiveIteratorIterator::LEAVES_ONLY);//PHP多进程for ($i = 0; $i < 2; $i++) { $pid = pcntl_fork(); if ($pid == -1) { echo \"Could not fork!\\n\"; exit(1); } if (!$pid) { echo \"child process $i running\\n\"; $offset = $i*1800; $limit_iterator = new LimitIterator($ierator,$offset,1800); foreach($limit_iterator as $file=>$fileinfo){ //传文件路径,记录到数据库 recordFile($fileinfo->getPathname()); } //子进程执行完毕之后就退出,以免继续fork出新的子进程 exit($i); } usleep(1);//歇一微秒避免并发记录}//等待子进程执行完毕,避免出现僵尸进程while (pcntl_waitpid(0, $status) != -1) { $status = pcntl_wexitstatus($status); echo \"Child $status completed\\n\";} 这样子处理速度直接快接近一半了。也可以不用上面的方法,可以使用法3把所有文件路径跑出来存到一个数组里面,再创建多个进程通过数组偏移来处理。1234567891011121314151617181920212223242526$directory = new RecursiveDirectoryIterator($need_import_dir,RecursiveDirectoryIterator::SKIP_DOTS);//把法3改成返回一个数组里面存着所有的文件$total_files = getFiles3($directory);$chunk_size = 1800;//分割下,每个数组大小可以具体设置。$chunk_list = array_chunk($total_files,$chunk_size);//PHP多进程for ($i = 0; $i < count($chunk_list); $i++) { $pid = pcntl_fork(); if ($pid == -1) { echo \"Could not fork!\\n\"; exit(1); } if (!$pid) { foreach($chunk_list[$i] as $value){ recordFile($value); } //子进程执行完毕之后就退出,以免继续fork出新的子进程 exit($i); } usleep(1);}//等待子进程执行完毕,避免出现僵尸进程while (pcntl_waitpid(0, $status) != -1) { $status = pcntl_wexitstatus($status); echo \"Child $status completed\\n\";} 经过测试还是第一种通过LimitIterator迭代器偏移开启两个进程更快一些。 ——————2016-10-10","categories":[{"name":"PHP","slug":"PHP","permalink":"https://renqiangme.github.io/categories/PHP/"}],"tags":[{"name":"PHP","slug":"PHP","permalink":"https://renqiangme.github.io/tags/PHP/"}]},{"title":"Github的SSH和HTTPS记住账号密码方法","slug":"Github的SSH和HTTPS记住账号密码方法","date":"2016-12-24T07:58:08.000Z","updated":"2019-03-18T04:39:10.311Z","comments":true,"path":"2016/12/24/Github的SSH和HTTPS记住账号密码方法/","link":"","permalink":"https://renqiangme.github.io/2016/12/24/Github的SSH和HTTPS记住账号密码方法/","excerpt":"其实关于这两种认证方式也是适用于Gitlab等相关git.很多时候,我们在打算克隆一个仓库到本地的时候,有两种方式可以选择,即:SSH和HTTPS.克隆还好,但是需要推送的时候,也许会遇到权限,需要账号密码啊。 通过HTTPS方式克隆的代码到本地如果遇到:1error: The requested URL returned error: 403 Forbidden while accessing 这是权限问题,可以修改.git/config文件追加用户名和密码,也可以直接敲下面命令:1git remote set-url origin https://youruser:password@github.com/user/repo.git","text":"其实关于这两种认证方式也是适用于Gitlab等相关git.很多时候,我们在打算克隆一个仓库到本地的时候,有两种方式可以选择,即:SSH和HTTPS.克隆还好,但是需要推送的时候,也许会遇到权限,需要账号密码啊。 通过HTTPS方式克隆的代码到本地如果遇到:1error: The requested URL returned error: 403 Forbidden while accessing 这是权限问题,可以修改.git/config文件追加用户名和密码,也可以直接敲下面命令:1git remote set-url origin https://youruser:password@github.com/user/repo.git 其实更常用的是SSH的方式来推送代码: 首先需要生成 SSH Keys,需要用到 ssh-keygen 命令。1ssh-keygen -t rsa -C "xxx@qq.com" -f ~/.ssh/git-github 简单介绍下参数含义: -t 指定密钥类型,默认即 rsa ,可以省略-C 设置注释文字,比如你的邮箱-f 指定密钥文件存储文件名,会生成 git-github 和 git-github.pub 两个密钥文件 回车后,遇到提示输入 yes 即可,剩下一路回车,密钥文件就在指定路径下生成了。 接下来就去git管理界面的设置里面将 SSH 公钥添加到 Github设置里面把git-github.pub公钥的内容复制进去添加就行了。 本地添加SSH别名如果本机有其它密钥,连接 github 时可能不会自动使用刚生成的密钥,需要设置别名: $ sudo vi ~/.ssh/config加入类似的一段代码: 12345host git-github user git hostname github.com port 22 identityfile ~/.ssh/git-github 保存退出。 测试连接1ssh -T git-github Hi xxx! You’ve successfully authenticated, but GitHub does not provide shell access. 表示设置的 SSH Keys 认证通过,但 Github 不提供 shell 访问。此时就可以正常使用 Github 了。","categories":[{"name":"Git","slug":"Git","permalink":"https://renqiangme.github.io/categories/Git/"}],"tags":[{"name":"Git","slug":"Git","permalink":"https://renqiangme.github.io/tags/Git/"},{"name":"GitHub","slug":"GitHub","permalink":"https://renqiangme.github.io/tags/GitHub/"}]},{"title":"修改MongoDB3.x版本的auth认证方式为2.x版本的认证方式","slug":"MongoDB3.x版本的auth认证方式为2.x版本的认证方式","date":"2016-12-24T05:02:30.000Z","updated":"2019-03-25T13:55:24.211Z","comments":true,"path":"2016/12/24/MongoDB3.x版本的auth认证方式为2.x版本的认证方式/","link":"","permalink":"https://renqiangme.github.io/2016/12/24/MongoDB3.x版本的auth认证方式为2.x版本的认证方式/","excerpt":"最近在用OpenResty的做一些任务,其中在使用MongoDB的Lua库的时候,因为MongoDB开启了auth,需要账号密码才能连接。 MongoDB 2.xx的认证方式,使用的是md5加密,认证耗时更短,如果使用3.xx认证处耗时很严重在Lua中。","text":"最近在用OpenResty的做一些任务,其中在使用MongoDB的Lua库的时候,因为MongoDB开启了auth,需要账号密码才能连接。 MongoDB 2.xx的认证方式,使用的是md5加密,认证耗时更短,如果使用3.xx认证处耗时很严重在Lua中。怎么改呢? MongoDB改验证方式:1、停止mongodb,2、以不验证模式启动3、删除原有用户名密码4、12use admin;db.system.version.insert({“_id”:”authSchema”,”currentVersion”:3}) 5、新增用户名密码!6、停止mongodb7、以验证方式启动MongoDB 如果insert不行就update","categories":[{"name":"MongoDB","slug":"MongoDB","permalink":"https://renqiangme.github.io/categories/MongoDB/"}],"tags":[{"name":"MongoDB","slug":"MongoDB","permalink":"https://renqiangme.github.io/tags/MongoDB/"}]},{"title":"OpenResty中使用Lua的MongoDB库,使用连接池节省连接认证时间","slug":"OpenResty中使用Lua的MongoDB库,使用连接池节省连接认证时间","date":"2016-12-24T01:36:37.000Z","updated":"2019-03-25T13:13:52.395Z","comments":true,"path":"2016/12/24/OpenResty中使用Lua的MongoDB库,使用连接池节省连接认证时间/","link":"","permalink":"https://renqiangme.github.io/2016/12/24/OpenResty中使用Lua的MongoDB库,使用连接池节省连接认证时间/","excerpt":"因为服务器的mongodb开启了auth认证的,所以每次连接都要验证密码,测试了下GitHub上面的几个lua的mongodb库,无论是官方的mongorover,还是纯的lua库:lua-resty-mongol3,一个简单的insert操作都比php耗费的时间更长,如果业务用lua来做的优势就没有那么明显了,单纯的不认证的insert操作lua的优势很是明显的,所以要么取消认证,要么就是可以结合openresty的连接池。而且发现使用连接池后,纯的lua mongodb库竟然比mongorover更快。","text":"因为服务器的mongodb开启了auth认证的,所以每次连接都要验证密码,测试了下GitHub上面的几个lua的mongodb库,无论是官方的mongorover,还是纯的lua库:lua-resty-mongol3,一个简单的insert操作都比php耗费的时间更长,如果业务用lua来做的优势就没有那么明显了,单纯的不认证的insert操作lua的优势很是明显的,所以要么取消认证,要么就是可以结合openresty的连接池。而且发现使用连接池后,纯的lua mongodb库竟然比mongorover更快。下面是动态判断该连接是否是连接池里面的一些判断,把连接与认证封装在一起,减少不必要认证次数。同时修改了仓库的源码,以支持支持自定义连接池,这样可以让不同 用户名、密码、数据库 的连接分开,不相互干扰。 新建一个lua文件,只做连接操作。 123456789101112131415161718192021222324252627282930313233343536local mongo = require "resty.mongol"local _M = {}--把连接与认证封装在一起,减少不必要认证次数local function connect(config) local db = mongo:new() if not db then return nil,nil, "db not initialized" end if config.host == nil or config.host == '' or config.port == nil or config.port == '' or config.database == nil or config.database == '' then return nil,nil, "host,port,database can't empty" end local user = config.user if(user == nil or user == '') then user = '' end --支持自定义连接池,这样可以让不同 用户名、密码、数据库 的连接分开,不相互干扰,mongol库本身是没有实现的,所以修改了源码 local pool = user .. ":" .. config.database .. ":" .. config.host .. ":" .. config.port local ok, err = db:connect(config.host, config.port, {pool = pool}) if not ok then return nil,nil,err end --选择数据库 local select_db = db:new_db_handle(config.database) --获取连接池里面的已经auth过连接的数量 local times,err =db:get_reused_times() if((times == 0 or times == nil) and #user > 0) then ok,err = select_db:auth_scram_sha1(config.user,config.password) if not ok then return nil,nil,err end end return db,select_db,nilendreturn _M","categories":[{"name":"OpenResty","slug":"OpenResty","permalink":"https://renqiangme.github.io/categories/OpenResty/"}],"tags":[{"name":"MongoDB","slug":"MongoDB","permalink":"https://renqiangme.github.io/tags/MongoDB/"},{"name":"OpenResty","slug":"OpenResty","permalink":"https://renqiangme.github.io/tags/OpenResty/"},{"name":"Lua","slug":"Lua","permalink":"https://renqiangme.github.io/tags/Lua/"}]}]}