mac安装MySQL-python报错:EnvironmentError: mysql_config not found

原创 2017年04月19日 17:30:56 2912
使用命令 pip install MySQL-python==1.2.5安装MySQL-python时报错:

报错信息: mysql_config not found

查找不到mysql_config 文件。

在网上搜了下,很凌乱。

源博客:http://stackoverflow.com/questions/25459386/mac-os-x-environmenterror-mysql-config-not-found

只是做了一些提示,我这里把我解决的过程总结一下:

1.确保安装了python;

2.确保你安装了mysql ,没有安装的话可以在这里下载安装包安装:https://dev.mysql.com/downloads/connector/python/

3.运行命令修改环境变量:export PATH=$PATH:/usr/local/mysql/bin

4.安装MySQL-python:pip install MySQL-python==1.2.5

这种方式解决了我的问题:

执行

ln -s /usr/local/mysql/bin/mysql_config /usr/local/bin/mysql_config

将mysql_config链接到/usr/local/bin目录下

2018/4/14 posted in  linux

mac 在virtualenv下安装mysql-python python mysql驱动包

export PATH=$PATH:/usr/local/mysql/bin/
pip install python-mysqldb

是由于安装的时候需要有这个目录的权限,所以使用virtualenv的时候肯定会遇到这个问题。

2017/9/30 posted in  linux

ubuntu 16 下的shadowsocks 全局代理

线上服务器经常对外网有比较多的依赖,有很多场景会使用shadowsocks的翻墙,比如使用github、使用apt-get、客户端使用Google的服务等等,各种不同的场景配置不一样。前面有整理github来进行,这里使用polipo来进行全部的服务器的shadowsocks代理。

前面的shadowsock的安装可以参看前面的文章,下面主要整理配置全局代理。

配置全局代理

启动shawdowsocks服务后,发现并不能翻墙上网,这是因为shawdowsocks是socks 5代理,需要客户端配合才能翻墙。

为了让整个系统都走shawdowsocks通道,需要配置全局代理,可以通过polipo实现。

首先是安装polipo:

sudo apt-get install polipo

接着修改polipo的配置文件/etc/polipo/config:

logSyslog = true
logFile = /var/log/polipo/polipo.log
proxyAddress = "0.0.0.0"
socksParentProxy = "127.0.0.1:1080"
socksProxyType = socks5
chunkHighMark = 50331648
objectHighMark = 16384
serverMaxSlots = 64
serverSlots = 16
serverSlots1 = 32
##重启polipo服务:

sudo /etc/init.d/polipo restart

为终端配置http代理:

export http_proxy="http://127.0.0.1:8123/"

接着测试下能否翻墙:

curl www.google.com

如果有响应,则全局代理配置成功。

注意事项

服务器重启后,下面两句需要重新执行:

sudo sslocal -c shawdowsocks.json -d start
export http_proxy="http://127.0.0.1:8123/"

这样的话就可以对全局进行shadowsocks代理了。

2017/9/24 posted in  linux

Nginx upstream time out bug fix

问题报道

上来贴一部分日志记录,这个和前面的错误日志还是有一定的区别

2017/08/15 09:03:43 [error] 9529#0: *1090065 upstream timed out (110: Connection timed out) while connecting to upstream, client: 111.178.21.169, server: oa.hansap.com, request: "POST /fysdtdkj/uc/singleLogin.do HTTP/1.1", upstream: "http://10.11.11.164:80/fysdtdkj/uc/singleLogin.do", host: "oa.hansap.com"
2017/08/15 09:03:59 [error] 9529#0: *1088945 upstream timed out (110: Connection timed out) while connecting to upstream, client: 27.17.54.74, server: hangouweixin.hansap.com, request: "GET /favicon.ico HTTP/1.1", upstream: "http://10.11.103.17:80/favicon.ico", host: "hangouweixin.hansap.com"
2017/08/15 09:04:13 [error] 9529#0: *1090187 upstream timed out (110: Connection timed out) while connecting to upstream, client: 27.17.54.74, server: oa.hansap.com, request: "GET /fysdtdkj/j_spring_security_exit_user?j_username=admin HTTP/1.1", upstream: "http://10.11.11.164:80/fysdtdkj/j_spring_security_exit_user?j_username=admin", host: "oa.hansap.com", referrer: "http://oa.hansap.com/fysdtdkj/platform/console/main.do"
2017/08/15 09:04:26 [error] 9529#0: *1090315 upstream timed out (110: Connection timed out) while connecting to upstream, client: 27.17.54.74, server: hangouweixin.hansap.com, request: "POST /web/index.php?c=utility&a=notice& HTTP/1.1", upstream: "http://10.11.103.17:80/web/index.php?c=utility&a=notice&", host: "hangouweixin.hansap.com", referrer: "http://hangouweixin.hansap.com/web/index.php?c=account&a=display&"
2017/08/15 09:04:53 [error] 9529#0: *1089772 upstream timed out (110: Connection timed out) while connecting to upstream, client: 27.17.54.74, server: hangouweixin.hansap.com, request: "POST /web/index.php?c=account&a=display&do=package& HTTP/1.1", upstream: "http://10.11.103.17:80/web/index.php?c=account&a=display&do=package&", host: "hangouweixin.hansap.com", referrer: "http://hangouweixin.hansap.com/web/index.php?c=account&a=display&"
2017/08/15 09:05:03 [error] 9529#0: *1088945 upstream timed out (110: Connection timed out) while connecting to upstream, client: 27.17.54.74, server: hangouweixin.hansap.com, request: "GET /web/index.php?c=home&a=welcome&do=members& HTTP/1.1", upstream: "http://10.11.103.17:80/web/index.php?c=home&a=welcome&do=members&", host: "hangouweixin.hansap.com", referrer: "http://hangouweixin.hansap.com/web/index.php?c=account&a=display&"
2017/08/15 09:11:00 [error] 9529#0: *1094373 upstream timed out (110: Connection timed out) while connecting to upstream, client: 58.48.126.38, server: jhczlc.com, request: "GET / HTTP/1.1", upstream: "http://10.11.103.15:8080/", host: "www.whljyl.com"

这是贴出来的一部分日志报错,是过滤的upstream timed out (110: Connection timed out) while connecting to upstream

当前修改的方式暂时使用

  1. nginx proxy

适当的调整proxy_read_timeout值。

location / {
        ...
        proxy_read_timeout 150;
        ...
    }
  1. Upstream timed out (110: Connection timed out) while reading response header from upstream

这种情况主要在下面两种情况下发生:

a. Nginx 作为 proxy,需要适当的调整 proxy timeout 的值。

    location / {
        ...
        proxy_connect_timeout 300;
        proxy_read_timeout 300;
        proxy_send_timeout 300;
        ...
    }

b. Nginx作为 php-fpm 等其他的有上游服务,需要适当的调整 fastcgi_read_timeout 选项值

 location ~* .php$ {
        include         fastcgi_params;
        fastcgi_index   index.php;
        fastcgi_read_timeout 150;
        fastcgi_pass    127.0.0.1:9000;
        fastcgi_param   SCRIPT_FILENAME    $document_root$fastcgi_script_name;
    }
  1. open() “_usr_local_nginx_html/favicon.ico” failed (2: No such file or directory)

只需要关闭 favicon.ico 的 log:

    location = /favicon.ico {
        log_not_found off;
        access_log off;
    } 
2017/8/15 posted in  linux

Ubuntu 14.04 使用 Cron 实现计划任务

Timing

Windows 自带定时执行任务的工具叫做“计划任务”,Linux 下我们使用 Cron 实现这一功能。

启动 cron 服务

通常 ubuntu 下自带 cron,如果没有也可以通过以下命令进行安装:

$ apt-get install cron

若已经安装,输入以下命令判断 cron 服务是否启动:

$ pgrep cron

如果有 pid (一串数字)输出则说明 cron 服务已经启动,没有任何输出说明需要手动启动 cron 服务。
启动 cron 服务:

$ service cron start

管理任务计划文件

cron 的所有任务计划都记录在 crontab 任务计划文件中,通过 crontab 命令对该任务文件进行管理。

usage: crontab [-u user] file crontab [ -u user] [ -i ] { -e | -l | -r } (default operation is replace, per 1003.2) -e (edit user's crontab) -l (list user's crontab) -r (delete user's crontab) -i (prompt before deleting user's crontab)

参数说明:

参数 说明 -u user 指定用户 -e 编辑某个用户的计划任务文件,若不指定用户,默认编辑当前用户的计划任务文件 -l 显示某个用户的计划任务文件,若不指定用户,默认显示当前用户的计划任务文件 -r 删除某个用户的计划任务文件,若不指定用户,默认删除当前用户的计划任务文件 -i 在删除之前推送确认提示

使用示例:

$ crontab -u foo -e \#编辑用户 foo 的计划任务文件 $ crontab -e \#编辑当前用户的计划任务文件 $ crontab -u foo -l \#显示用户 foo 的计划任务文件 $ crontab -l \#显示当前用户的计划任务文件 $ crontab -r \#删除当前用户的计划任务文件

编辑任务计划文件

初次使用 crontab -e,可能需要选择编辑器,输入编辑器序号点击回车后进入计划任务文件编辑模式。若直接进入编辑模式忽略以上内容。

进入编辑模式后,按照指定格式添加任务计划。

任务计划的语法格式如下:

m h dom mon dow command
0-59 0-23 1-31 1-12 0-7 command
  • m: 表示分钟
  • h: 表示小时
  • dom: 表示日期
  • mon: 表示月份
  • dow: 表示星期
  • command: 预执行的命令
    另外需要使用一些特殊符号实现灵活的配置:

    • 代表所有值
  • / 代表“每”

    • 代表范围
  • , 分割数字
    任务示例如下:

## 指定具体执行时间
2 * * * * ls \#每个小时的第2分钟执行一次 ls 命令
30 7 * * * ls \#每天7:30执行一次 ls 命令
30 20 * * 2 ls \#每周二,20:30执行一次 ls 命令(0和7表示星期天) \#\# 指定间隔时间
*/2 * * * * ls \#每隔2分钟执行一次 ls 命令 \#\# 指定时间段
30 7 3-6 * * ls \#每个月的3,4,5,6号的7:30分各执行一次 ls 命令 \#\# 指定多个时间
30 7 3,6 * * ls \#每月的3号和6号的7:30分各执行一次 ls 命令

另外,使用 run-parts 可以运行指定目录下所有的脚本(注意脚本必须加上 “#!_bin_bash",否则 run-parts 会调用失败).

30 7 * * * run-parts /home \#每天7:30运行 /home 目录下的所有脚本

按照指定格式添加任务,保存后,任务生效。

下面是一个实际的计划任务文件,包含系统自带注释和一个每两分钟执行一次输出字符串 ”Hello World“ 到 /home 目录下 cron_test 文件的计划任务。

# Edit this file to introduce tasks to be run by cron. # # Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
# # To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').# # Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
# # Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
# # For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
# # For more information see the manual pages of crontab(5) and cron(8)
# # m h dom mon dow command
*/2 * * * * echo "Hello World" >> /home/cron_test

Ubuntu 14.04 使用 Cron 实现计划任务

修改编辑器

在首次使用crontab -e的时候会启动

2017/8/3 posted in  linux

Mac 开发的神秘面纱:后娘养的嫡长子

本来,标题是「揭开 macOS 开发的神秘面纱」,可想想,以我目前对 macOS 开发的理解,还是去掉「揭开」二字吧 😂。

本文不是系统性的文章,更像是 随笔 。回想自己过去 1.6 年的 macOS 开发历程,挑些有意思的来说。如果想看完就去挖 macOS 这座金矿(如果是的话),你会失望的; 且作佚事来读吧

注:严格地说,应该叫作「 macOS 开发 」,因为去年起,苹果将 Mac 操作系统更名为 macOS;不过,苹果电脑依旧以 Mac 命名,如 MacBookPro,故而 Mac 开发也说得过去;再加上,以小写字母开头作为文章名,总觉得怪怪的,是以本文混用「Mac 开发」与「macOS 开发」。

0) Mac 是「后妈的嫡长子」

说 Mac 是嫡长子,是因为 苹果就是做电脑起家的 。虽说后来 iPod、iPhone 风生水起,但嫡长子的血统还是纯正的;而 iOS 正是基于 macOS 开发的。这里的故事很多,感兴趣可以读读《乔布斯传》之类的书或文章。

可惜的是, 有了 iPhone 这棵摇钱树之后,Mac 电脑靠边站了 ,macOS 自然也被冷落,不到万不得已,不更新;即使更新,也像挤牙膏一样。

Mac 哪里被冷落了?多了去了。

比如,我每周都会收到一款苹果给开发者的邮件,本意是告知本周 App 的活跃程度。而我每次收到的邮件内容都是这样的:

baf47be07ba2edc4a8700b2bbc88fbe3

因为我尚未上架 iOS 应用、只有 macOS App;而 在苹果看来,macOS App 岂能叫 App ?! 是以,这里的数据是空的……

其它的,不胜枚举。

1) Mac 是个小市场

有多小?

先说说硬件 ,这是 2016 第四季度出货量对比:

设备 出货量 营收 Mac 537 万 72 亿美元 iPhone 7,830 万 543 亿美元

不论是出货量、还是营收,均是零头。

再来看看 App 的数量:

AppShopper 的数据来看, 不足 3 万的 macOS App 数量,不到 iOS App 的 1% ;对,是「百分之一」, 零头的零头

112eab8fd46c781bc6807a4f80cbf16d

当然,这里主要统计的是上架 MAS (Mac App Store) 的应用,在 MAS 之外也有很多。不过,2 个数量级的差异,没跑。

现说说操作系统占比:

MarketShare 的数据, macOS 仅占 6.12%,仅有 Windows 用户的 6.7%.

f1f1217618e85bc0c68c49523c8a18eb

其中, macOS 版本的分散程度 ,虽比 Windows 好很多,但也 不如 iOS:

5fca2073c79199a44ad8b8af524218d5

看到这里,是不是觉得有些心凉, 觉得 Mac 好可怜有没有……

不过,Mac 电脑确实是在慢慢增加的,知名度也在变高。比如, 国内现代都市剧中出现的电脑,大多都是 Mac ;苹果也刚刚宣布 全球 Mac 活跃用户有 1 亿

2) Swift or Objective-C

我开发的应用 (KlibiPiciPic MoveriPasteiTimeriHosts ),全部基于 Swift;不过,即使你也打算基于 Swift,还是建议对 Objective-C 有基本的了解。 因为,毕竟 Objective-C 是苹果一直以来使用的开发语言,绝大多数的文档、教程,都是基于 Objective-C 的。

虽说可以很容易地改编为 Swift、或被 Swift 调用,但这就像是:你有一本英文词典,理论上就可以直接看英文文章,因为看见不懂的单词可以查嘛;但也知道,这不现实,毕竟你总不能每个单词都查吧?

所以:

  • 如果你已经有 Objective-C 基础,就直接使用 Objective-C 开发 Mac 应用好了。要不要学 Swift?看你自己心情,我不提供建议;
  • 如果你并没有 Objective-C 基础,建议你先学学 Objective-C 基础,然后再学 Swift,并基于 Swift 开发。
    ## 3) Mac 文档及教程

官方文档主要有这些:

实际上,由于我们一般是「 面向 Google 编程 」,一般遇到问题都是先搜索,不太需要记录这些网址。只是,如果你想系统性、深入地学习某个点时,可以正向地从官方文档入手。

不过,对于 苹果的开发文档 ,友情提醒: 并不怎么好 。如果套用这句话:「为什么懂得这么多道理,却仍过不好这一生?」

便是:「 为什么我看了所有 Mac 文档,却仍无法开发 Mac 应用?

文档更多是偏向对某个具体知识点的介绍,而如果想系统性地入门 macOS,最好是通过一本好的书,以及自己的练习。由于 iPhone 的热销,市面上 iOS 的书,可谓汗牛充栋。而 macOS 的书呢?呵呵

我自己是看《 Cocoa Programming for Mac OS X 》这本书入门 macOS 开发的,这几乎是我在 2015 年能找到的唯一一本基于 Swift 的 macOS 开发教程。另外一本是 Swift Development with Cocoa ,跟这本书没法比。

其他 macOS 的书,我看的不多,也没什么好推荐的。如果你有觉得哪本书不错,欢迎留言告诉我。

4) macOS 数据结构及持久化

首先要说的是, 虽说是 macOS 开发,但实际上很多基础的东西都是通用的 ,比如 JSON 格式、MySQL 数据库等等。

另外, macOS 和 iOS 相比 ,像 TouchBar 这种独有的东西,并不多; 更多的是通用的 ,或者说是并行的两套。

使用 plist 文件存储数据:

  • 默认仅支持简单的数据结构;此方式仅适合保存少量数据,如偏好设置中的 On/Off 选项
  • 可使用 UserDefaults 管理默认的 plist 文件。注意:沙盒模式和普通模式下默认的 plist 文件的位置不同
  • 可在命令行中使用 defaults 命令来管理 plist 文件中的数据
  • 可使用 Xcode 打开 plist 文件进行管理
    序列化后存储:

  • 对于自定义类型,适配 NSSecureCoding 协议后,可使用 NSKeyedArchiver 转换为 Data 格式

  • 进而,可存储在普通文件中,也可存储于 plist 文件中
    Core Data:

  • Core Data 本质上是对数据访问方式的封装

  • 对于简单的数据结构,使用 Core Data 会带来额外的复杂度,并不划算。对于复杂的应用,Core Data 可以显著减少代码量

  • 持久化方面,Core Data 提供了对象-关系映射 (ORM) 的功能,不编写任何SQL语句,即可将数据保存在 SQLite 数据库文件中,也能还原到内存中
    CloudKit:

  • 存储方面,CloudKit 本质上类似于云端的关系数据库

  • 除了存储,CloudKit 更有用的场景,是在多设备、macOS 与 iOS 间同步数据。比如,系统自带的 Notes 等应用,均是通过 CloudKit 来存储、同步数据。其中,通知机制可以最小化需要同步的数据量

  • 再有,就是提供基于 CloudKit 的共享功能
    注:数据持久化存储方式有非常多,也要视具体的需求而定;这里仅提及一些常用的方式。

5) macOS 界面开发

我们所说 macOS 开发,通常默认指开发「有界面及交互的、能运行在 macOS 上的应用」, 其核心,就在于界面及交互

我们也常听到 Cocoa,那 什么是 Cocoa 呢? 援引《Cocoa Programming for OS X》中的介绍:

Cocoa is your application’s interface to the window server to receive events and draw to the screen. At the same time it has access to the Unix layer where it can make lower level calls.

02cf5f7b094b21451a41131f2200aa55

也就是说, Cocoa 是这样一个中间环节:负责衔接你的应用与窗口系统,同时也可直接操作系统底层。

界面的开发,是个无底洞 ;可以是个简单的单窗口应用,也可以是 Pages、iMovie 这样复杂的应用。

对于初学者,建议从菜单栏程序入手 。可以暂时绕开窗口、控件这些复杂的话题,又可以创建出能解决实际问题的一些应用。比如,iPic 主交互即位于菜单栏:

5f6de1af8c1fe8f701a2dc7505e14ff

这部分,可参见我之前写的教程: Status Bar App 教程是 16 年 4 月写的,现在来看有些可能已经过时,比如当时是基于 Swift 2.2;不过整体还是可以参考的。

回到界面的开发。首先, 要理解 App 的整体生命周期。 尤其是 App 启动时,都做了哪些事、先后顺序及依赖是什么。

然后, 实际的工作,就是搞定界面布局,以及熟悉一个个控件的用法 ,如 NSButton、NSTextField、NSTableView 等等。 建议的学习步骤:

  • 先随意玩玩,能让控件跑起来;一些控件复杂,跑不起来也不用觉得沮丧
  • 如果官方有 Programming Guide,认真读一遍
  • 如果官方有示例程序,学习之,熟悉正确的用法
  • 过一遍 API Reference,了解控件所有的可能性和局限
  • 解决自己实际的问题,真正用起来 我一般的开发步骤:

6) macOS 设计模式之解耦

随着程序变得复杂,代码变多,也很容易交织在一起。对于进一步开发和维护,是非常头痛的事。

0c403868f569cf2e78a8274ce0828d

怎么避免这样的情况呢?其中一个思路是: 解耦

抽象的说,就是 把复杂的东西拆成一个个独立的模块,然后通过一些方式让这些模式有机地组合在一起

有哪些方式呢?顺着这个思路,我列出一些概念。

MVC模式 (Model-View-Controller)

  • 这一模式在界面开发里大量使用,比如你经常看到的 XXViewController,就是其中的 Controller 部分。
  • 简单的说,就是 把界面与逻辑分离 。界面部分,如布局、样式等。通常,代码量最多的,都是在 Controller 中。View 与 Controller 之间, 通过引用、绑定来传递数据 ,即将数据显示在界面中、从界面读取用户产生的数据。
    Delegate

  • 有两个角度来理解代理。以 NSWindowDelegate 为例,可理解为 Window 本身有丰富的可定制性,程序可选择性地实现某些功能、特性。

  • 另一个角度是,同样对于 NSWindowDelegate,对事件(如窗口即将关闭)的响应,Window 本身是不知道的,或者说是具体的业务相关的。Window 自己做不到,只能委托给自己的「代理」去决定。比如,当窗口即将关闭时,程序提示用户保存未保存的数据。
    Callback

  • 对于非实时的操作,可以使用 Callback 回调的方式,来解耦调用者和执行者之间的等待。

  • 比如,程序在从网络下载图片时,可能需要 1ms,也可能需要 2s,程序总不能傻等着。于是,程序告诉下载的模块:我去忙别的事了,你下载好了告诉我。怎么告诉?就是通过 Callback 回调机制实现。

  • 与之关联的概念,如代码块。
    Notification

  • 对于「 如果……就…… 」这样的逻辑,比较适合的是通知机制。

  • 这里的通知,不止是从网络上推送下来的通知,也可以是程序内部的通知。

  • 比如,用户在偏好设置的界面中完成账户升级后,在程序内发出账户类型变更的通知;程序的主窗口之前注册以监听这一通知,便可根据账户类型实时调整界面。

    7) 发布 macOS 应用

自己辛苦开发的程序,通常是愿意让更多人来用的。如果能赚点小钱,当然更好啦。

7.0) macOS 应用签名

对于简单的程序,可以复制到别的电脑上运行,但最好还是要对程序进行签名。尤其是使用 CloudKit 等一些苹果特性的程序,必须签名。

怎么签名呢?前提是交钱。也就是, 必须每年交给苹果 $99 的人头税,才能成为苹果开发者 ,进而给应用签名。

7.1) MAS 与沙盒模式

在 MAS (Mac App Store) 上提交的应用,必须运行在沙盒模式中。

沙盒模式有诸多限制 ,比如,默认不能访问用户的任何文件、一些接口无法使用等等。 和 iOS 的沙盒模式相比,macOS 的沙盒模式还是宽松很多的 。以访问文件的权限为例,应用可以申请访问如 Downloads 等指定目录。向谁申请呢?苹果,而不是用户。一旦通过(虽然并不容易),便可直接访问该目录,无需用户授权。

事实上, 沙盒模式确实限制了程序的发挥空间 ,一些应用(如屏幕取词翻译、截图工具)干脆无法上架,或者额外开通「Accessibility」权限才能正常工作。而据说苹果已不再放行需要此权限的应用上架。

7.2) MAS 付费方式

苹果支持多种内购方式,要想通过应用收费,最简单的方式是: 设置程序必须付费才能下载 。这样,程序内无需区分免费版与高级版,无需做任何功能限制,代码简单。苹果系统保证了,使用哪个 Apple ID 下载的应用,只能在使用哪个 Apple ID 上登录的电脑上使用。比如, 你自己购买了某个付费应用,直接把 .app 复制到朋友的电脑上,是无法运行的

不过,这一方式也有局限:用户在付费之前,无法体验到产品的所有功能,也就很难决定是否要付费。对于这一局限,一些程序的做法时:在产品官网提供一个全功能、但仅能运行一段时间(如 7 天)的 体验版 。这样,用户可以在体验所有功能后,决定是否购买。

再进一步,就是 免费版 + 内购的模式 。用户可免费下载应用,但应用仅开放基础功能,需要内购才能使用高级功能。这样,既能最大化地获取用户,又能适时地收费,我的所有应用都采用此方式,相信也是未来一段时间的趋势。

对于内购,又分为一次性购买和订阅制 。一次性购买容易理解;订阅制可以有按月、季度、年等不同周期。对于订阅制,又分为自动续订和手动续订。目前,苹果对于订阅制、尤其是自动续订的订阅制,审核较严。

另外,还有 消耗型内购 ,这种在游戏中较为常见,比如花钱买装备,或者为账户充值等。

对于内购的开发 ,还是比较繁琐的,比如要处理展示、购买、用户购买后退款、恢复、订阅续订、订阅未续订导致过期等等逻辑。好在, 我封装了 IAPHelper ,可以很方便地处理这些逻辑(如下代码为购买部分); 开源 ,可以 Pod 方式集成,已经在我的产品中应用多年,大家可放心使用。

IAP.purchaseProduct(productIdentifier, handler: { (productIdentifier, error) in if let identifier = productIdentifier { // The product of 'productIdentifier' purchased. } else if let error = error as? NSError { if error.code == SKError.Code.paymentCancelled.rawValue { // User cancelled } else { // Some error happened } }
})

7.3) 不完美的 MAS

之前苹果与微信怒怼的打赏分成事件,想必让更多朋友知道了: 凡是应用从用户收到的钱中,苹果均要收 30% 的拔毛费。

MAS 的诸多限制,以及不菲的拔毛费,让很多知名的 macOS App 纷纷下架,如 Sketch、Dash 等等。

不过, 要在 MAS 之外发布,还是要做很多事情的 ,比如下载、支付、退款、激活码等等。对于小程序,还是挺繁琐的,并不划算。另外,毕竟 MAS 还能带来一些自然流量。

如果在 MAS 之外发布,还有一点需要注意: .app 程序本质上是一个文件夹 。如果需要在网络上传送(如作为邮件的附件),最好是进行压缩,甚至是制作 .dmg 文件,我使用的是 create-dmg 这个小工具,非常方便,生成的样式也简单大方。

基于上面的原因,目前我的应用全部在 MAS 上发布,尚未在 MAS 之外发布。

尾巴

macOS 开发的话题还有非常多,比如 Storyboard、绑定、动画、并发、Undo、Pasteboard、Drag & Drop、本地化、单元测试等等,本文不可能全部提及。并且,写起来也好累,毕竟必须对这些点有完全的掌握,才可能写出来。暂时先挖坑放着,以后再填。

对 macOS 开发感兴趣?欢迎留言交流。

原文:「 自在开发 」公众号 (ID: IndieDev)

Mac 开发的神秘面纱:后娘养的嫡长子

2017/7/20 posted in  linux

CentOS根分区扩容方法

Linux的磁盘管理是很重要的一部分,这里面涉及到比较多的部分需要理解。在安装之处可以设定相应的磁盘空间,但是新增磁盘的时候,挂盘、查询、挂载、格式化、mount,这样的操作还是比较多的。

当前我们采用vmware下面的CentOS的操作系统,现在的需求是创建一块新的磁盘,能够用户扩展虚拟机的根分区。

初始的磁盘状态就不在这里演示了。

vmware磁盘加盘

vmware的添加磁盘也在这里说一下,还是挺有意思的。

添加磁盘的最后一步,有一个选项,如下所示

5C5E6DEF-4C71-42A0-B966-E6A96CA05908

可以看到虚拟设备节点 SCSI(0:1) ,这里应该表示3个插槽,每个插槽有15个

连接到SCSI接口的设备使用ID号进行区别,SCSI设备ID号为0~15,SCSI接口卡本身的ID号是7。Linux对连接到SCSI接口卡的硬盘使用_dev_sdx的方式命名,x的值可以是a、b、c、d等,即ID号为0的SCSI硬盘名为_dev_sda,ID号为1的SCSI硬盘名为_dev_sdb,以此类推。LINUX对SCSI硬盘最多支持15个分区。

所以这里可以看到SCSI(0:7) 不存在。

在虚拟机中刷新fdisk 表

[[vmware 下 ubuntu的挂盘和卸载盘]] 文章中介绍了可以动态的刷新盘,按照这个步骤来操作即可。

echo "- - -" > /sys/class/scsi_host/host2/scan

然后fdisk -l就可以看到刷新出来的盘

[root@jku-server-slave ~]# fdisk -l

Disk /dev/sda: 214.7 GB, 214748364800 bytes
255 heads, 63 sectors/track, 26108 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00042985

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *           1          64      512000   83  Linux
Partition 1 does not end on cylinder boundary.
/dev/sda2              64       26109   209202176   8e  Linux LVM

Disk /dev/mapper/VolGroup-lv_root: 53.7 GB, 53687091200 bytes
255 heads, 63 sectors/track, 6527 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000


Disk /dev/mapper/VolGroup-lv_swap: 8405 MB, 8405385216 bytes
255 heads, 63 sectors/track, 1021 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000


Disk /dev/mapper/VolGroup-lv_home: 152.1 GB, 152127406080 bytes
255 heads, 63 sectors/track, 18495 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000


Disk /dev/sdb: 16.1 GB, 16106127360 bytes
255 heads, 63 sectors/track, 1958 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

查看df -h

[root@jku-server-slave ~]# df -h
Filesystem                    Size  Used Avail Use% Mounted on
/dev/mapper/VolGroup-lv_root   50G  7.4G   40G  16% /
tmpfs                         3.9G     0  3.9G   0% /dev/shm
/dev/sda1                     485M   39M  421M   9% /boot
/dev/mapper/VolGroup-lv_home  140G  188M  133G   1% /home

磁盘分区和挂载

磁盘分区

[root@jku-server-slave ~]# fdisk /dev/sdb
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0x8d6de234.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.

Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

WARNING: DOS-compatible mode is deprecated. It's strongly recommended to
         switch off the mode (command 'c') and change display units to
         sectors (command 'u').

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-1958, default 1): 1
Last cylinder, +cylinders or +size{K,M,G} (1-1958, default 1958): 1958

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.

sdb2分区格式化

[root@jku-server-slave ~]# mkfs.ext4 /dev/sdb1
mke2fs 1.41.12 (17-May-2010)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
983040 inodes, 3931900 blocks
196595 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=4026531840
120 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks:
    32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208

Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information:
done

This filesystem will be automatically checked every 27 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.

格式化sdb2分区为物理卷

[root@jku-server-slave ~]# pvcreate /dev/sdb1
  dev_is_mpath: failed to get device for 8:17
  Physical volume "/dev/sdb1" successfully created

查看物理卷的情况

[root@jku-server-slave ~]# pvdisplay
  --- Physical volume ---
  PV Name               /dev/sda2
  VG Name               VolGroup
  PV Size               199.51 GiB / not usable 3.00 MiB
  Allocatable           yes (but full)
  PE Size               4.00 MiB
  Total PE              51074
  Free PE               0
  Allocated PE          51074
  PV UUID               0wfker-mZQI-yQKG-b3qT-fFF0-3xq9-0K9xWZ

  "/dev/sdb1" is a new physical volume of "15.00 GiB"
  --- NEW Physical volume ---
  PV Name               /dev/sdb1
  VG Name
  PV Size               15.00 GiB
  Allocatable           NO
  PE Size               0
  Total PE              0
  Free PE               0
  Allocated PE          0
  PV UUID               6YTfQU-gbQJ-eMYH-c97g-x2Rv-VaSj-Te7Xxt

查看卷组状态

[root@jku-server-slave ~]# vgdisplay
  --- Volume group ---
  VG Name               VolGroup
  System ID
  Format                lvm2
  Metadata Areas        1
  Metadata Sequence No  4
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                3
  Open LV               3
  Max PV                0
  Cur PV                1
  Act PV                1
  VG Size               199.51 GiB
  PE Size               4.00 MiB
  Total PE              51074
  Alloc PE / Size       51074 / 199.51 GiB
  Free  PE / Size       0 / 0
  VG UUID               eSpwQ5-jGFv-OkVH-XSiw-YmVC-JZk9-d1CJgC

可以看到当前卷组是199G

将sdb2转换为扩展分区

[root@jku-server-slave ~]# vgextend VolGroup /dev/sdb1
  Volume group "VolGroup" successfully extended

查看当前逻辑卷

[root@jku-server-slave ~]# lvdisplay
  --- Logical volume ---
  LV Path                /dev/VolGroup/lv_root
  LV Name                lv_root
  VG Name                VolGroup
  LV UUID                QwMJ1h-F5Ba-iPRK-v4Vm-o1sN-zhjG-y1jTsd
  LV Write Access        read/write
  LV Creation host, time localhost.localdomain, 2016-10-18 10:38:47 +0800
  LV Status              available
  # open                 1
  LV Size                50.00 GiB
  Current LE             12800
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           253:0

  --- Logical volume ---
  LV Path                /dev/VolGroup/lv_home
  LV Name                lv_home
  VG Name                VolGroup
  LV UUID                u5IFJS-xX2L-cU81-Rl6r-xqJ2-Z33W-ryVNWm
  LV Write Access        read/write
  LV Creation host, time localhost.localdomain, 2016-10-18 10:39:13 +0800
  LV Status              available
  # open                 1
  LV Size                141.68 GiB
  Current LE             36270
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           253:2

  --- Logical volume ---
  LV Path                /dev/VolGroup/lv_swap
  LV Name                lv_swap
  VG Name                VolGroup
  LV UUID                pqNOBG-fVI7-e3q4-hgLe-5yaj-JWXi-3gneoO
  LV Write Access        read/write
  LV Creation host, time localhost.localdomain, 2016-10-18 10:40:11 +0800
  LV Status              available
  # open                 1
  LV Size                7.83 GiB
  Current LE             2004
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           253:1

查看扩展后卷组情况

[root@jku-server-slave ~]# vgdisplay
  --- Volume group ---
  VG Name               VolGroup
  System ID
  Format                lvm2
  Metadata Areas        2
  Metadata Sequence No  5
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                3
  Open LV               3
  Max PV                0
  Cur PV                2
  Act PV                2
  VG Size               214.50 GiB
  PE Size               4.00 MiB
  Total PE              54913
  Alloc PE / Size       51074 / 199.51 GiB
  Free  PE / Size       3839 / 15.00 GiB
  VG UUID               eSpwQ5-jGFv-OkVH-XSiw-YmVC-JZk9-d1CJgC

可以看到扩展后的卷组大小已经加上了

将逻辑卷则新增到/分区中

[root@jku-server-slave ~]# lvextend -L +11G /dev/VolGroup/lv_root
  Extending logical volume lv_root to 61.00 GiB
  Logical volume lv_root successfully resized
[root@jku-server-slave ~]# e2fsck -f /dev/VolGroup/lv_root
e2fsck 1.41.12 (17-May-2010)
/dev/VolGroup/lv_root is mounted.
e2fsck: Cannot continue, aborting.


[root@jku-server-slave ~]# resize2fs /dev/VolGroup/lv_root
resize2fs 1.41.12 (17-May-2010)
Filesystem at /dev/VolGroup/lv_root is mounted on /; on-line resizing required
old desc_blocks = 4, new_desc_blocks = 4
Performing an on-line resize of /dev/VolGroup/lv_root to 15990784 (4k) blocks.
The filesystem on /dev/VolGroup/lv_root is now 15990784 blocks long.

最后查看绑定情况

[root@jku-server-slave ~]# df -h
Filesystem                    Size  Used Avail Use% Mounted on
/dev/mapper/VolGroup-lv_root   61G  7.4G   50G  13% /
tmpfs                         3.9G     0  3.9G   0% /dev/shm
/dev/sda1                     485M   39M  421M   9% /boot
/dev/mapper/VolGroup-lv_home  140G  188M  133G   1% /home

tips: 最后想办法把这个整理到ubuntu中去

经测试,ubuntu所有命令相同,同样适用。

2017/5/26 posted in  linux

vmware 下 ubuntu的挂盘和卸载盘

刷新发现

当前部分操作系统,直接在vmware上添加之后,不会自动的在虚拟机内识别。

echo "- - -" > _sys_class_scsi_host_host2/scan

这样就可以自动识别了。

扩展磁盘空间

前面新加的盘,使用fdisk -l 能够查看到_dev_sdb, 如果没有挂在,此时不想使用了,可以直接在vmware里面删除掉这块挂在的盘,这个设备就不会在fdisk里面出现了。

如果再挂在一个和刚才一样大的盘,会自动识别,但是大小不一样的话,就不会自动识别了。

磁盘的一些发现

在vmware添加磁盘的时候,如果挂载虚拟设备节点到SCSI(0:1)上的时候,这是在fdisk上进行刷新发现,比如_dev_sdb。 如果此时删除这一块磁盘,然后再重新在SCSI(0:1)上创建一块不同大小的新盘,这是新出来的fdisk其实还是以前的磁盘大小。只有通过重启来解决。如果刷新这个还没有找到,后续可以了解一下

这是如果要不重启解决的方法就是不在(0:1)上,放在如SCSI(0:4)上的时候,这是就会出来新的_dev_sdc 。这样就不会冲突。

2017/5/26 posted in  linux

Ansible 学习文档

安装

第一步就是安装ansible

git clone git://github.com/ansible/ansible.git --recursive
$ cd ./ansible

##安装pip, 官方指南这里没有指定要安装markupsafe,不装的话这里可能会报错
sudo apt-get install python-pip python-dev build-essential markupsafe

$ source ./hacking/env-setup

认证

说起远程设备,Ansible会默认假定你使用 SSH Key(我们推荐这种)但是密码也一样可以.通过在需要的地方添加 –ask-pass选项 来启用密码验证.如果使用了sudo 特性,当sudo需要密码时,也同样适当的提供了–ask-sudo-pass选项.

也许这是常识,但也值得分享:任何管理系统受益于被管理的机器在主控机附近运行.如果在云中运行,可以考虑在使用云中的一台机器来运行Ansible.

作为一个进阶话题,Ansible不止支持SSH来远程连接.连接方式是插件化的而且还有许多本地化管理的选项诸如管理 chroot, lxc, 和 jail containers.一个叫做‘ansible-pull’的模式能够反转主控关系并使远程系统通过定期从中央git目录检出 并 拉取 配置指令来实现背景连接通信.

测试第一个ping命令

配置 _etc_ansible/hosts 文件

192.168.11.85 ansible_ssh_user=abc ansible_ssh_pass=****** ansible_sudo_pass=******

注意使用这种模式默认是认为不安全的,后面我们可以使用其他的模式,这里仅用于做测试

使用ssh登陆的模式,需要ubuntu安装 sshpass , 使用命令 apt-get install sshpass

使用这种模式,需要加入服务器的know_host , 所以先在服务器上ssh一下目标服务器,以记下konw_host比较好

然后在使用ping命令即可

 ansible all -m ping

Inventory文件

1. 主机和组

mail.example.com

#分组模式
[webservers]
foo.example.com
bar.example.com

[dbservers]
one.example.com
two.example.com
three.example.com

#多适配模式
[webservers_multiple]
www[01:50].example.com

[databases_multiple]
db-[a:f].example.com

#带参数的模式
[targets]

localhost              ansible_connection=local
other1.example.com     ansible_connection=ssh        ansible_ssh_user=mpdehaan
other2.example.com     ansible_connection=ssh        ansible_ssh_user=mdehaan

2. 主机变量

[atlanta]
host1 http_port=80 maxRequestsPerChild=808
host2 http_port=303 maxRequestsPerChild=909

3. 组的变量

[atlanta]
host1
host2

[atlanta:vars]
ntp_server=ntp.atlanta.example.com
proxy=proxy.atlanta.example.com

vars 定义了为组的变量

4. 一个组作为另一个组的成员

[atlanta]
host1
host2

[raleigh]
host2
host3

[southeast:children]
atlanta
raleigh

[southeast:vars]
some_server=foo.southeast.example.com
halon_system_timeout=30
self_destruct_countdown=60
escape_pods=2

[usa:children]
southeast
northeast
southwest
northwest

带子成员的组有children变量

在children里面填入相应的组,既可以生成成员组。

inventory 参数说明

ansible_ssh_host
      将要连接的远程主机名.与你想要设定的主机的别名不同的话,可通过此变量设置.

ansible_ssh_port
      ssh端口号.如果不是默认的端口号,通过此变量设置.

ansible_ssh_user
      默认的 ssh 用户名

ansible_ssh_pass
      ssh 密码(这种方式并不安全,我们强烈建议使用 --ask-pass 或 SSH 密钥)

ansible_sudo_pass
      sudo 密码(这种方式并不安全,我们强烈建议使用 --ask-sudo-pass)

ansible_sudo_exe (new in version 1.8)
      sudo 命令路径(适用于1.8及以上版本)

ansible_connection
      与主机的连接类型.比如:local, ssh 或者 paramiko. Ansible 1.2 以前默认使用 paramiko.1.2 以后默认使用 'smart','smart' 方式会根据是否支持 ControlPersist, 来判断'ssh' 方式是否可行.

ansible_ssh_private_key_file
      ssh 使用的私钥文件.适用于有多个密钥,而你不想使用 SSH 代理的情况.

ansible_shell_type
      目标系统的shell类型.默认情况下,命令的执行使用 'sh' 语法,可设置为 'csh' 或 'fish'.

ansible_python_interpreter
      目标主机的 python 路径.适用于的情况: 系统中有多个 Python, 或者命令路径不是"/usr/bin/python",比如  \*BSD, 或者 /usr/bin/python
      不是 2.X 版本的 Python.我们不使用 "/usr/bin/env" 机制,因为这要求远程用户的路径设置正确,且要求 "python" 可执行程序名不可为 python以外的名字(实际有可能名为python26).

      与 ansible_python_interpreter 的工作方式相同,可设定如 ruby 或 perl 的路径....

例子:

some_host         ansible_ssh_port=2222     ansible_ssh_user=manager
aws_host          ansible_ssh_private_key_file=/home/example/.ssh/aws.pem
freebsd_host      ansible_python_interpreter=/usr/local/bin/python
ruby_module_host  ansible_ruby_interpreter=/usr/bin/ruby.1.9.3
2017/5/3 posted in  linux

四层、七层负载均衡的区别

内容安排:

  • 简介
  • 区别
  • Nginx、LVS及HAProxy负载均衡软件的优缺点
    一、简介

  1. 所谓四层就是基于IP+端口的负载均衡;七层就是基于URL等应用层信息的负载均衡; 同理,还有基于MAC地址的二层负载均衡和基于IP地址的三层负载均衡。 换句换说,二层负载均衡会通过一个虚拟MAC地址接收请求,然后再分配到真实的MAC地址;三层负载均衡会通过一个虚拟IP地址接收请求,然后再分配到真实的IP地址;四层通过虚拟IP+端口接收请求,然后再分配到真实的服务器;七层通过虚拟的URL或主机名接收请求,然后再分配到真实的服务器。

  2. 所谓的四到七层负载均衡,就是在对后台的服务器进行负载均衡时,依据四层的信息或七层的信息来决定怎么样转发流量。 比如四层的负载均衡,就是通过发布三层的IP地址(VIP),然后加四层的端口号,来决定哪些流量需要做负载均衡,对需要处理的流量进行NAT处理,转发至后台服务器,并记录下这个TCP或者UDP的流量是由哪台服务器处理的,后续这个连接的所有流量都同样转发到同一台服务器处理。七层的负载均衡,就是在四层的基础上( 没有四层是绝对不可能有七层的 ),再考虑应用层的特征,比如同一个Web服务器的负载均衡,除了根据VIP加80端口辨别是否需要处理的流量,还可根据七层的URL、浏览器类别、语言来决定是否要进行负载均衡。举个例子,如果你的Web服务器分成两组,一组是中文语言的,一组是英文语言的,那么七层负载均衡就可以当用户来访问你的域名时,自动辨别用户语言,然后选择对应的语言服务器组进行负载均衡处理。

  3. 负载均衡器通常称为四层交换机或七层交换机。四层交换机主要分析IP层及TCP/UDP层,实现四层流量负载均衡。七层交换机除了支持四层负载均衡以外,还有分析应用层的信息,如HTTP协议URI或Cookie信息。

  4. 负载均衡分为L4 switch(四层交换),即在OSI第4层工作,就是TCP层啦。此种Load Balance不理解应用协议(如HTTP_FTP_MySQL等等)。例子:LVS,F5。

  5. 另一种叫做L7 switch(七层交换),OSI的最高层,应用层。此时,该Load Balancer能理解应用协议。例子: haproxy,MySQL Proxy。

注意:上面的很多Load Balancer既可以做四层交换,也可以做七层交换。

二、区别

  1. 技术原理上
  2. 所谓四层负载均衡 ,也就是主要通过报文中的目标地址和端口,再加上负载均衡设备设置的服务器选择方式,决定最终选择的内部服务器。以常见的TCP为例,负载均衡设备在接收到第一个来自客户端的SYN 请求时,即通过上述方式选择一个最佳的服务器,并对报文中目标IP地址进行修改(改为后端服务器IP),直接转发给该服务器。TCP的连接建立,即三次握手是客户端和服务器直接建立的,负载均衡设备只是起到一个类似路由器的转发动作。在某些部署情况下,为保证服务器回包可以正确返回给负载均衡设备,在转发报文的同时可能还会对报文原来的源地址进行修改。

1787733-614f0b870366e3c

  1. 区别

  2. 所谓七层负载均衡 ,也称为“内容交换”,也就是主要通过报文中的真正有意义的应用层内容,再加上负载均衡设备设置的服务器选择方式,决定最终选择的内部服务器。

  3. 以常见的TCP为例,负载均衡设备如果要根据真正的应用层内容再选择服务器,只能先代理最终的服务器和客户端建立连接(三次握手)后,才可能接受到客户端发送的真正应用层内容的报文,然后再根据该报文中的特定字段,再加上负载均衡设备设置的服务器选择方式,决定最终选择的内部服务器。负载均衡设备在这种情况下,更类似于一个代理服务器。负载均衡和前端的客户端以及后端的服务器会分别建立TCP连接。所以从这个技术原理上来看,七层负载均衡明显的对负载均衡设备的要求更高,处理七层的能力也必然会低于四层模式的部署方式。

  4. 应用场景 七层应用负载的好处,是使得整个网络更智能化。例如访问一个网站的用户流量,可以通过七层的方式,将对图片类的请求转发到特定的图片服务器并可以使用缓存技术;将对文字类的请求可以转发到特定的文字服务器并可以使用压缩技术。当然这只是七层应用的一个小案例,从技术原理上,这种方式可以对客户端的请求和服务器的响应进行任意意义上的修改,极大的提升了应用系统在网络层的灵活性。很多在后台,例如Nginx或者Apache上部署的功能可以前移到负载均衡设备上,例如客户请求中的Header重写,服务器响应中的关键字过滤或者内容插入等功能。

  5. 另外一个常常被提到功能就是安全性。网络中最常见的SYN Flood攻击,即黑客控制众多源客户端,使用虚假IP地址对同一目标发送SYN攻击,通常这种攻击会大量发送SYN报文,耗尽服务器上的相关资源,以达到Denial of Service( DoS )的目的。从技术原理上也可以看出,四层模式下这些SYN攻击都会被转发到后端的服务器上;而七层模式下这些SYN攻击自然在负载均衡设备上就截止,不会影响后台服务器的正常运营。另外负载均衡设备可以在七层层面设定多种策略,过滤特定报文,例如SQL Injection等应用层面的特定攻击手段,从应用层面进一步提高系统整体安全。

  6. 现在的7层负载均衡,主要还是着重于应用HTTP协议,所以其应用范围主要是众多的网站或者内部信息平台等基于B_S开发的系统。 4层负载均衡则对应其他TCP应用,例如基于C_S开发的ERP等系统。

三、Nginx、LVS及HAProxy负载均衡软件的优缺点

负载均衡 (Load Balancing) 建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力,同时能够提高网络的灵活性和可用性。

Nginx_LVS_HAProxy是目前使用最广泛的三种负载均衡软件。

一般对负载均衡的使用是随着网站规模的提升根据不同的阶段来使用不同的技术。具体的应用需求还得具体分析,如果是中小型的Web应用,比如日PV小于1000万,用Nginx就完全可以了;如果机器不少,可以用DNS轮询,LVS所耗费的机器还是比较多的;大型网站或重要的服务,且服务器比较多时,可以考虑用LVS。

一种是通过硬件来进行,常见的硬件有比较昂贵的F5和Array等商用的负载均衡器,它的优点就是有专业的维护团队来对这些服务进行维护、缺点就是花销太大,所以对于规模较小的网络服务来说暂时还没有需要使用;另外一种就是类似于Nginx_LVS_HAProxy的基于 Linux的开源免费的负载均衡软件,这些都是通过软件级别来实现,所以费用非常低廉。

目前关于网站架构一般比较合理流行的架构方案:Web前端采用Nginx/HAProxy+ Keepalived作负载均衡器;后端采用 MySQL数据库一主多从和读写分离,采用LVS+Keepalived的架构。当然要根据项目具体需求制定方案。

下面说说各自的特点和适用场合。

Nginx的优点是:

  1. 工作在网络的7层之上,可以针对http应用做一些分流的策略,比如针对域名、目录结构,它的正则规则比HAProxy更为强大和灵活,这也是它目前广泛流行的主要原因之一,Nginx单凭这点可利用的场合就远多于LVS了。

  2. Nginx对网络稳定性的依赖非常小,理论上能ping通就就能进行负载功能,这个也是它的优势之一;相反LVS对网络稳定性依赖比较大。

  3. Nginx安装和配置比较简单,测试起来比较方便,它基本能把错误用日志打印出来。LVS的配置、测试就要花比较长的时间了,LVS对网络依赖比较大。

  4. 可以承担高负载压力且稳定,在硬件不差的情况下一般能支撑几万次的并发量,负载度比LVS相对小些。

  5. Nginx可以通过端口检测到服务器内部的故障,比如根据服务器处理网页返回的状态码、超时等等,并且会把返回错误的请求重新提交到另一个节点,不过其中缺点就是不支持url来检测。比如用户正在上传一个文件,而处理该上传的节点刚好在上传过程中出现故障,Nginx会把上传切到另一台服务器重新处理,而LVS就直接断掉了,如果是上传一个很大的文件或者很重要的文件的话,用户可能会因此而不满。

  6. Nginx不仅仅是一款优秀的负载均衡器/反向代理软件,它同时也是功能强大的Web应用服务器。LNMP也是近几年非常流行的web架构,在高流量的环境中稳定性也很好。

  7. Nginx现在作为Web反向加速缓存越来越成熟了,速度比传统的Squid服务器更快,可以考虑用其作为反向代理加速器。

  8. Nginx可作为中层反向代理使用,这一层面Nginx基本上无对手,唯一可以对比Nginx的就只有 lighttpd了,不过 lighttpd目前还没有做到Nginx完全的功能,配置也不那么清晰易读,社区资料也远远没Nginx活跃。

  9. Nginx也可作为静态网页和图片服务器,这方面的性能也无对手。还有Nginx社区非常活跃,第三方模块也很多。

Nginx的缺点是:

  1. Nginx仅能支持http、https和Email协议,这样就在适用范围上面小些,这个是它的缺点。

  2. 对后端服务器的健康检查,只支持通过端口来检测,不支持通过url来检测。不支持Session的直接保持,但能通过ip_hash来解决。

LVS:使用Linux内核集群实现一个高性能、高可用的负载均衡服务器,它具有很好的可伸缩性(Scalability)、可靠性(Reliability)和可管理性(Manageability)。

LVS的优点是:

  1. 抗负载能力强、是工作在网络4层之上仅作分发之用,没有流量的产生,这个特点也决定了它在负载均衡软件里的性能最强的,对内存和cpu资源消耗比较低。

  2. 配置性比较低,这是一个缺点也是一个优点,因为没有可太多配置的东西,所以并不需要太多接触,大大减少了人为出错的几率。

  3. 工作稳定,因为其本身抗负载能力很强,自身有完整的双机热备方案,如LVS+Keepalived。

  4. 无流量,LVS只分发请求,而流量并不从它本身出去,这点保证了均衡器IO的性能不会受到大流量的影响。

  5. 应用范围比较广,因为LVS工作在4层,所以它几乎可以对所有应用做负载均衡,包括http、数据库、在线聊天室等等。

LVS的缺点是:

  1. 软件本身不支持正则表达式处理,不能做动静分离;而现在许多网站在这方面都有较强的需求,这个是Nginx/HAProxy+Keepalived的优势所在。

  2. 如果是网站应用比较庞大的话,LVS_DR+Keepalived实施起来就比较复杂了,特别后面有 Windows Server的机器的话,如果实施及配置还有维护过程就比较复杂了,相对而言,Nginx_HAProxy+Keepalived就简单多了。

HAProxy的特点是:

  1. HAProxy也是支持虚拟主机的。

  2. HAProxy的优点能够补充Nginx的一些缺点,比如 支持Session的保持,Cookie的引导;同时支持通过获取指定的url来检测后端服务器的状态。

  3. HAProxy跟LVS类似,本身就只是一款负载均衡软件;单纯从效率上来讲HAProxy会比Nginx有更出色的负载均衡速度,在并发处理上也是优于Nginx的。

  4. HAProxy 支持TCP协议的负载均衡转发 ,可以对MySQL读进行负载均衡,对后端的MySQL节点进行检测和负载均衡,大家可以用LVS+Keepalived对MySQL主从做负载均衡。

  5. HAProxy负载均衡策略非常多,HAProxy的负载均衡算法现在具体有如下8种:① roundrobin,表示简单的轮询,这个不多说,这个是负载均衡基本都具备的;② static-rr,表示根据权重,建议关注;③ leastconn,表示最少连接者先处理,建议关注;④ source,表示根据请求源IP,这个跟Nginx的IP_hash机制类似,我们用其作为解决session问题的一种方法,建议关注;⑤ ri,表示根据请求的URI;⑥ rl_param,表示根据请求的URl参数’balance url_param’ requires an URL parameter name;⑦ hdr(name),表示根据HTTP请求头来锁定每一次HTTP请求;

  6. ⑧ rdp-cookie(name),表示根据据cookie(name)来锁定并哈希每一次TCP请求。

Nginx和LVS对比的总结:

  1. Nginx工作在网络的7层,所以它可以针对http应用本身来做分流策略,比如针对域名、目录结构等,相比之下LVS并不具备这样的功能,所以Nginx单凭这点可利用的场合就远多于LVS了;但Nginx有用的这些功能使其可调整度要高于LVS,所以经常要去触碰触碰,触碰多了,人为出问题的几率也就会大。

  2. Nginx对网络稳定性的依赖较小,理论上只要ping得通,网页访问正常,Nginx就能连得通,这是Nginx的一大优势!Nginx同时还能区分内外网,如果是同时拥有内外网的节点,就相当于单机拥有了备份线路;LVS就比较依赖于网络环境,目前来看服务器在同一网段内并且LVS使用direct方式分流,效果较能得到保证。另外注意,LVS需要向托管商至少申请多一个ip来做Visual IP,貌似是不能用本身的IP来做VIP的。要做好LVS管理员,确实得跟进学习很多有关网络通信方面的知识,就不再是一个HTTP那么简单了。

  3. Nginx安装和配置比较简单,测试起来也很方便,因为它基本能把错误用日志打印出来。LVS的安装和配置、测试就要花比较长的时间了;LVS对网络依赖比较大,很多时候不能配置成功都是因为网络问题而不是配置问题,出了问题要解决也相应的会麻烦得多。

  4. Nginx也同样能承受很高负载且稳定,但负载度和稳定度差LVS还有几个等级:Nginx处理所有流量所以受限于机器IO和配置;本身的bug也还是难以避免的。

  5. Nginx可以检测到服务器内部的故障,比如根据服务器处理网页返回的状态码、超时等等,并且会把返回错误的请求重新提交到另一个节点。目前LVS中 ldirectd也能支持针对服务器内部的情况来监控,但LVS的原理使其不能重发请求。比如用户正在上传一个文件,而处理该上传的节点刚好在上传过程中出现故障,Nginx会把上传切到另一台服务器重新处理,而LVS就直接断掉了,如果是上传一个很大的文件或者很重要的文件的话,用户可能会因此而恼火。

  6. Nginx对请求的异步处理可以帮助节点服务器减轻负载,假如使用 apache直接对外服务,那么出现很多的窄带链接时apache服务器将会占用大 量内存而不能释放,使用多一个Nginx做apache代理的话,这些窄带链接会被Nginx挡住,apache上就不会堆积过多的请求,这样就减少了相当多的资源占用。这点使用squid也有相同的作用,即使squid本身配置为不缓存,对apache还是有很大帮助的。

  7. Nginx能支持http、https和email(email的功能比较少用),LVS所支持的应用在这点上会比Nginx更多。在使用上,一般最前端所采取的策略应是LVS,也就是DNS的指向应为LVS均衡器,LVS的优点令它非常适合做这个任务。重要的ip地址,最好交由LVS托管,比如数据库的 ip、webservice服务器的ip等等,这些ip地址随着时间推移,使用面会越来越大,如果更换ip则故障会接踵而至。所以将这些重要ip交给 LVS托管是最为稳妥的,这样做的唯一缺点是需要的VIP数量会比较多。Nginx可作为LVS节点机器使用,一是可以利用Nginx的功能,二是可以利用Nginx的性能。当然这一层面也可以直接使用squid,squid的功能方面就比Nginx弱不少了,性能上也有所逊色于Nginx。Nginx也可作为中层代理使用,这一层面Nginx基本上无对手,唯一可以撼动Nginx的就只有lighttpd了,不过lighttpd目前还没有能做到 Nginx完全的功能,配置也不那么清晰易读。另外,中层代理的IP也是重要的,所以中层代理也拥有一个VIP和LVS是最完美的方案了。具体的应用还得具体分析,如果是比较小的网站(日PV小于1000万),用Nginx就完全可以了,如果机器也不少,可以用DNS轮询,LVS所耗费的机器还是比较多的;大型网站或者重要的服务,机器不发愁的时候,要多多考虑利用LVS。

现在对网络负载均衡的使用是随着网站规模的提升根据不同的阶段来使用不同的技术:

第一阶段:利用Nginx或HAProxy进行单点的负载均衡,这一阶段服务器规模刚脱离开单服务器、单数据库的模式,需要一定的负载均衡,但是仍然规模较小没有专业的维护团队来进行维护,也没有需要进行大规模的网站部署。这样利用Nginx或HAproxy就是第一选择,此时这些东西上手快, 配置容易,在七层之上利用HTTP协议就可以。这时是第一选择。

第二阶段:随着网络服务进一步扩大,这时单点的Nginx已经不能满足,这时使用LVS或者商用Array就是首要选择,Nginx此时就作为LVS或者Array的节点来使用,具体LVS或Array的是选择是根据公司规模和预算来选择,Array的应用交付功能非常强大,本人在某项目中使用过,性价比也远高于F5,商用首选,但是一般来说这阶段相关人才跟不上业务的提升,所以购买商业负载均衡已经成为了必经之路。

第三阶段:这时网络服务已经成为主流产品,此时随着公司知名度也进一步扩展,相关人才的能力以及数量也随之提升,这时无论从开发适合自身产品的定制,以及降低成本来讲开源的LVS,已经成为首选,这时LVS会成为主流。

最终形成比较理想的基本架构为:Array_LVS — Nginx_Haproxy — Squid/Varnish — AppServer。

四层、七层负载均衡的区别

2017/4/28 posted in  linux

vmware 下在ubuntu上添加磁盘

firephoenix@ubuntu:~$ su - root
Password:
root@ubuntu:~#
root@ubuntu:~#
root@ubuntu:~#
root@ubuntu:~#
root@ubuntu:~# fdisk -l

Disk /dev/sdb: 53.7 GB, 53687091200 bytes
255 heads, 63 sectors/track, 6527 cylinders, total 104857600 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

Disk /dev/sdb doesn't contain a valid partition table

Disk /dev/sda: 53.7 GB, 53687091200 bytes
255 heads, 63 sectors/track, 6527 cylinders, total 104857600 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x000358f5

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *        2048      499711      248832   83  Linux
/dev/sda2          501758   104855551    52176897    5  Extended
/dev/sda5          501760   104855551    52176896   8e  Linux LVM

Disk /dev/mapper/ubuntu--vg-root: 49.1 GB, 49102716928 bytes
255 heads, 63 sectors/track, 5969 cylinders, total 95903744 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

Disk /dev/mapper/ubuntu--vg-root doesn't contain a valid partition table

Disk /dev/mapper/ubuntu--vg-swap_1: 4290 MB, 4290772992 bytes
255 heads, 63 sectors/track, 521 cylinders, total 8380416 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

Disk /dev/mapper/ubuntu--vg-swap_1 doesn't contain a valid partition table
root@ubuntu:~# ‘’
‘’: command not found
root@ubuntu:~#
root@ubuntu:~#
root@ubuntu:~# fdisk /dev/sdb
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0x6084a024.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.

Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

Command (m for help): n
Partition type:
   p   primary (0 primary, 0 extended, 4 free)
   e   extended
Select (default p): p
Partition number (1-4, default 1):
Using default value 1
First sector (2048-104857599, default 2048):
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-104857599, default 104857599):
Using default value 104857599

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.
root@ubuntu:~# fdisk -l

Disk /dev/sdb: 53.7 GB, 53687091200 bytes
22 heads, 22 sectors/track, 216647 cylinders, total 104857600 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x6084a024

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1            2048   104857599    52427776   83  Linux

Disk /dev/sda: 53.7 GB, 53687091200 bytes
255 heads, 63 sectors/track, 6527 cylinders, total 104857600 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x000358f5

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *        2048      499711      248832   83  Linux
/dev/sda2          501758   104855551    52176897    5  Extended
/dev/sda5          501760   104855551    52176896   8e  Linux LVM

Disk /dev/mapper/ubuntu--vg-root: 49.1 GB, 49102716928 bytes
255 heads, 63 sectors/track, 5969 cylinders, total 95903744 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

Disk /dev/mapper/ubuntu--vg-root doesn't contain a valid partition table

Disk /dev/mapper/ubuntu--vg-swap_1: 4290 MB, 4290772992 bytes
255 heads, 63 sectors/track, 521 cylinders, total 8380416 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

Disk /dev/mapper/ubuntu--vg-swap_1 doesn't contain a valid partition table
root@ubuntu:~# mkfs -t ext3  /dev/sdb1
mke2fs 1.42.9 (4-Feb-2014)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
3276800 inodes, 13106944 blocks
655347 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=4294967296
400 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks:
    32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
    4096000, 7962624, 11239424

Allocating group tables: done
Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information:
done

root@ubuntu:~#
root@ubuntu:~# mount /dev//
Display all 212 possibilities? (y or n)
root@ubuntu:~# mount /dev/
Display all 212 possibilities? (y or n)
root@ubuntu:~# mount /dev/sdb
sdb   sdb1
root@ubuntu:~# mount /dev/sdb1 /
root@ubuntu:~# df -h
Filesystem                   Size  Used Avail Use% Mounted on
/dev/mapper/ubuntu--vg-root   45G  1.6G   42G   4% /
none                         4.0K     0  4.0K   0% /sys/fs/cgroup
udev                         2.0G  4.0K  2.0G   1% /dev
tmpfs                        396M  712K  395M   1% /run
none                         5.0M     0  5.0M   0% /run/lock
none                         2.0G     0  2.0G   0% /run/shm
none                         100M     0  100M   0% /run/user
/dev/sda1                    236M   38M  186M  17% /boot
root@ubuntu:~# mount /dev/sdb1 /dev/mapper/ubuntu--vg-root
mount: mount point /dev/mapper/ubuntu--vg-root is not a directory
root@ubuntu:~# df -h
Filesystem                   Size  Used Avail Use% Mounted on
/dev/mapper/ubuntu--vg-root   45G  1.6G   42G   4% /
none                         4.0K     0  4.0K   0% /sys/fs/cgroup
udev                         2.0G  4.0K  2.0G   1% /dev
tmpfs                        396M  712K  395M   1% /run
none                         5.0M     0  5.0M   0% /run/lock
none                         2.0G     0  2.0G   0% /run/shm
none                         100M     0  100M   0% /run/user
/dev/sda1                    236M   38M  186M  17% /boot
root@ubuntu:~#

2017/4/20 posted in  linux

OpenVPN 客户端说明文档

Windows版本安装

安装openvpn客户端

请使用提供的文件包中的openvpn客户端,其他的客户端可能因为版本不兼容导致无法访问vpn
64位版本如下
FIREOPENVPN\windows\openvpn-install-2.3.2-I006-x86_64.exe

最好使用以管理员身份运行安装

0BB4CC53-3A84-4777-93BA-191231DFD194

进去后下一步、下一步安装完成

配置Openvpn

配置管理员运行权限

进入目录C:\Program Files\OpenVPN\bin 可以看到openvpn-gui.exe文件,由于需要给操作系统写入一些路由数据,需要给这个权限赋予管理员运行权限。

2348FAF1-FC76-425D-923F-0452E9BF80DB

6ADF3456-FC9C-4527-B5B8-836C42E54B00

配置client文件

FIREOPENVPN\windows文件包中的 rdclient 文件夹 拷贝到 C:\Program Files\OpenVPN\config 目录下

3742C423-7853-4748-866D-60A8941CEBDB

启动openvpn 客户端

使用安装后的桌面快捷方式,或者安装完成后的openvpn-gui.exe 文件,都可以启动openvpn 。

在windows右下角可以看到任务图标,反键任务图标connect即可。

C8168C74-E9E7-4F8D-9B22-AA9CB5A4A82E

连接后会弹出用户名密码标签,填入下发的即可,如 yangfan/

8F109829-0918-4608-A6F2-39C5E3840608

连接完成后图标会变为绿色,表示连接vpn 成功,这时可以ping一下你的ip

MAC版本安装

mac 版本推荐使用Tunnelblick来进行openvpn 的连接。(也可以使用其他的软件)。 Tunnelblick对于openvpn客户端服务器端版本的匹配较好,我们可以放心使用。

1318DB69-DD29-4A0A-AED3-FAE7C7BD6431

运行dmg 安装包之后双击安装即可。需要获取一些安装权限,需要输入
714BCEE0-D3EF-46C4-969B-D8222118185F

输入管理员密码

BFF34DF6-D888-41CA-80AD-B9E461CF66B

选择我有配置文件即可。

找到rdclient.tblk 文件,双击运行。

3B8004FE-8386-4D07-B2C0-DF8F1828A106

78E133FD-F863-4D21-9A51-3AAC64424F5B

安装完成后会有提示表示安装完成。

然后运行菜单中的,连接rdclient即可

46758CD5-9967-45CB-B43B-548E6AB77DB4

输入分配的用户名,密码登陆即可。

A5565C66-48EB-42CC-B969-ABD59F29520

完成后会显示连接成功。

卸载

如果不想使用,可以运行Tunnelblick Uninstaller 卸载即可

EA4298B8-CC09-45D5-A2AE-7E58D4D6D214

点击Uninstall 即可卸载
FC1DCF98-D214-49AC-B556-BF882AB396E3

卸载时会要求输入mac的管理员密码。

2017/3/29 posted in  工作方法 linux

Ubuntu 下 OpenVPN 配置

安装OpenVPN

一下命令安装openvpn

sudo apt-get -y install openvpn libssl-dev openssl

安装完成后查看相应版本:

openvpn --version

查看版本的目的是后面下载相应的openvpn客户端文件的时候,最好下载相应的版本,否则可能会报错。

安装证书工具

sudo apt-get -y install easy-rsa

制作证书

sudo mkdir /etc/openvpn/easy-rsa/
#把/usr/share/easy-rsa/目录下的所有文件全部复制到/etc/openvpn/easy-rsa/下
sudo cp -r /usr/share/easy-rsa/* /etc/openvpn/easy-rsa/
sudo vi /etc/openvpn/easy-rsa/vars

# These are the default values for fields
# which will be placed in the certificate.
# Don't leave any of these fields blank.
export KEY_COUNTRY="CN"
export KEY_PROVINCE="HB"
export KEY_CITY="wuhan"
export KEY_ORG="hansap"
export KEY_EMAIL="pengjunjie@hansap.com"
export KEY_OU="hansap"

# X509 Subject Field
export KEY_NAME="hansapextra"


实际上这里KEY_NAME是OpenVPN的名字,

然后使用source vars命令使其生效,如下:

source vars
#运行source vars的时候会有提示,需要使用clean all来清洗,执行clean-all命令会删除,当前目录下的keys文件夹。
./clean-all

制作CA证书

在easy-rsa目录下

./build-ca

输出的全部回车即可。这时在keys目录下面 /etc/openvpn/easy-rsa/keys/可以查看到 ca.crtca.key

把该CA证书的ca.crt文件复制到openvpn的启动目录_etc_openvpn下,如下:

cp keys/ca.crt /etc/openvpn/

ll /etc/openvpn/

制作Server端证书

在easy-rsa目录下面执行

./build-key-server hansapextra

中间有个密码,可以保持为空

这个时候/etc/openvpn/easy-rsa/keys会生成Server端证书 hansapextra.crt,hansapextra.csr,hansapextra.key

创建交换文件

在easy-rsa目录下执行

./build-dh

在目录/etc/openvpn/easy-rsa/keys会生成 dh2048.pem

把vpnilanni.crt、vpnilanni.key、dh2048.pem复制到_etc_openvpn/目录下,如下:

cp keys/hansapextra.crt keys/hansapextra.key keys/dh2048.pem /etc/openvpn/

制作客户端证书

在目录easy-rsa下

./build-key extraclient

一直确认,后面输入密码可以为空

在目录/etc/openvpn/easy-rsa/keys会生成extraclient.crt,extraclient.csr,extraclient.key

配置Server端

Server端的配置文件默认可以从openvpn的样例中拷贝

cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz /etc/openvpn/

cd /etc/openvpn/
#拷贝过来后解压
gzip -d server.conf.gz
root@vpnserver:/etc/openvpn# grep -vE "^#|^;|^$" server.conf
port 1194
proto tcp
dev tun
ca ca.crt
cert hansapextra.crt
key hansapextra.key  # This file should be kept secret
dh dh2048.pem
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
push "route 192.168.11.0 255.255.255.0"
push "route 172.16.0.0 255.255.0.0"
keepalive 10 120
comp-lzo
persist-key
persist-tun
status openvpn-status.log
verb 3

做一点解释

  1. proto tcp 代表使用tcp的连接,tcp稳定一些。
  2. dev 使用tun模式。这样更使用与使用路由模式,而tap适合于使用将ip出去。
  3. server 10.8.0.0 255.255.255.0 这里可以随便配置一个子网,注意这里只能填写子网,这个子网是客户端分配的网段。
  4. push "route 192.168.11.0 255.255.255.0" 这里会推送两个路由,后面会讲这个路由怎么用

完成后可以启动

/etc/init.d/openvpn start

netstat -tunlp |grep 1194

#使用status也可以查看状态
/etc/init.d/openvpn start

配置Client 端

windows上配置

将client的ctr 和 key 文件,以及ca.crt文件拷贝到客户端,配置client.conf到客户端。

cp extraclient.crt extraclient.key ca.crt /home/firephoenix/        

cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf /home/firephoenix/

配置修改

williamtekiMacBook-Pro:Downloads valentine$ grep -vE "^#|^;|^$" client.conf
client
dev tun
proto tcp
remote 61.183.247.97 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert extraclient.crt
key extraclient.key
ns-cert-type server
comp-lzo
verb 3

安装openvpn for windows客户端,我们可以从这个地址下载,如下:http://build.openvpn.net/downloads/releases/

建议和前面查询的版本相同的版本,如2.3.2版本。

ca.crt,client.conf,extraclient.crt,extraclient.key 四个文件放到一个文件夹中,然后再讲这个文件夹拷贝到c:\Program Files\OpenVPN\config\文件夹下面。

启动OpenVPN的客户端之后就可以看到connect。

配置网络

固定:修改_etc_sysctl.conf,取消这一行的注释:
net.ipv4.ip_forward= 1
然后使之立即生效
sysctl -p

EEEDB226-42C6-4B7D-8BAD-7A3C10EE819F

证书的管理

证书有效期管理

默认的OpenVPN配置,客户端证书有效期是10年。如何自定义客户端证书的时间呢?其实比较简单,编辑vars文件,找到export KEY_EXPIRE=3650这一行,把默认的3650,改为你想设置的天数即可。编辑后保存,运行一次vars,设置好环境变量,再用build-key生成客户端证书,即可。这样一来,客户端证书的有效期,就是你所设置的有效期了。

客户端证书的吊销

和PPTP VPN不一样,PPTP VPN直接删除客户端帐号,就可以了。在OpenVPN中,是通过revoke操作,吊销客户端证书,来实现禁止客户端连接OpenVPN的。
具体的方法如下:

#进入OpenVPN配置文件所在目录
#执行vars,初始化环境
. vars
#使用revoke-full命令,吊销客户端证书
./revoke-full clientName
#clientName是被吊销的客户端证书名称

命令执行后,我们能在keys目录中找到一个文件,名叫:crl.pem ,这个文件中包含了吊销证书的名单。然后,在服务端配置文件中,加入如下一行:

crl-verify crl.pem

最后一步,重启OpenVPN服务,即可

配置管理日志

默认情况下,openvpn server的配置会将日志写入_var_log/syslog 中,这种配置比较难管理,在openvpn中也添加了配置日志的部分。

# By default, log messages will go to the syslog (or
# on Windows, if running as a service, they will go to
# the "\Program Files\OpenVPN\log" directory).
# Use log or log-append to override this default.
# "log" will truncate the log file on OpenVPN startup,
# while "log-append" will append to it.  Use one
# or the other (but not both).
;log         openvpn.log
log-append  openvpn.log

这样在_etc_openvpn/openvpn.log 下面就可以看到相应的登陆日志了。

配置mysql集成OpenVPN用户验证

安装数据库

root@vpnserver:~# apt-get install mysql-server libpam-mysql sasl2-bin

配置数据库

root@vpnserver:~# mysql -uroot -p

#建库
CREATE DATABASE `openvpn` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci

mysql> use openvpn

mysql> GRANT ALL ON openvpn.* TO 'openvpn'@'localhost' IDENTIFIED BY '********';

mysql> CREATE TABLE IF NOT EXISTS `user` (
    -> `username` char(32) COLLATE utf8_unicode_ci NOT NULL,
    -> `password` char(128) COLLATE utf8_unicode_ci DEFAULT NULL,
    -> `active` int(10) NOT NULL DEFAULT '1',
    -> `creation` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
    -> `name` varchar(32) COLLATE utf8_unicode_ci NOT NULL,
    -> `email` char(128) COLLATE utf8_unicode_ci DEFAULT NULL,
    -> `note` text COLLATE utf8_unicode_ci,
    -> `quota_cycle` int(10) NOT NULL DEFAULT '30',
    -> `quota_bytes` bigint(20) NOT NULL DEFAULT '10737418240',
    -> `enabled` int(10) NOT NULL DEFAULT '1',
    -> PRIMARY KEY (`username`),
    -> KEY `idx_active` (`active`),
    -> KEY `idx_enabled` (`enabled`)
    -> ) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Query OK, 0 rows affected (0.02 sec)

mysql> CREATE TABLE IF NOT EXISTS `log` (
    -> `username` varchar(32) COLLATE utf8_unicode_ci NOT NULL,
    -> `start_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
    -> `end_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
    -> `trusted_ip` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
    -> `trusted_port` int(10) DEFAULT NULL,
    -> `protocol` varchar(16) COLLATE utf8_unicode_ci DEFAULT NULL,
    -> `remote_ip` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
    -> `remote_netmask` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
    -> `bytes_received` bigint(20) DEFAULT '0',
    -> `bytes_sent` bigint(20) DEFAULT '0',
    -> `status` int(10) NOT NULL DEFAULT '1',
    -> KEY `idx_username` (`username`),
    -> KEY `idx_start_time` (`start_time`),
    -> KEY `idx_end_time` (`end_time`)
    -> ) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

mysql> exit

修改openvpn配置

nano /etc/pam.d/openvpn

auth sufficient pam_mysql.so user=openvpn passwd=******** host=localhost db=openvpn table=user usercolumn=username passwdcolumn=password where=active=1 sqllog=0 crypt=1

account required pam_mysql.so user=openvpn passwd=******** host=localhost db=openvpn table=user usercolumn=username passwdcolumn=password where=active=1 sqllog=0 crypt=1

其中数据库、用户名、密码按照自己的实际情况设置。

crypt 表示密码在数据库中加密存储的方式,含义如下:
0 (or “plain”):不加密,明文存储。不推荐使用。
1 (or “Y”):使用crypt(3)函数,相当于MySQL 中的ENCRYPT()函数。
2 (or “mysql”):使用MySQL 的PASSWORD()函数。PAM 可能与MySQL 的函数不同,不推荐使用。
3 (or “md5″):使用MD5。
4 (or “sha1″):使用SHA1。

编辑/etc/default/saslauthd

nano /etc/default/saslauthd

START=no改成START=yes

重新启动saslauthd。

/etc/init.d/saslauthd restart

先测试一下配置是否正确,先添加在mysql里面添加一个test用户,密码也是test。

mysql -uopenvpn -p
mysql>

USE openvpn;
INSERT INTO user(username, password) VALUES('test', ENCRYPT('test'));
exit

退出以后,运行

testsaslauthd -u test -p test -s openvpn
如果提示

0: OK "Success."

说明验证通过,如果验证没通过的话,检查一下_var_log/auth.log,看看是什么原因导致的错误。

配置pam验证模块

复制Openvpn的pam验证模块到Openvpn目录:

cp /usr/lib/openvpn/openvpn-plugin-auth-pam.so /etc/openvpn/

重新编辑server.conf

#增加这个配置

# user/password auth from mysql
plugin /etc/openvpn/openvpn-plugin-auth-pam.so openvpn
username-as-common-name
;client-to-client


# record in database,这两行主要做用户登陆记录和流量管控,我们这里不做流量管控,可以修改一下。
script-security 2
client-connect ./connect.sh
client-disconnect ./disconnect.sh

在disconnect里面在端口之后会记录相应的VPN流量。

流量记录

新建一个/etc/openvpn/connect.sh文件。

nano /etc/openvpn/connect.sh

输入以下内容:

#!/bin/bash

DB='openvpn'
DBADMIN='openvpn'
DBPASSWD='password'

mysql -u$DBADMIN -p$DBPASSWD -e "INSERT INTO log(username,start_time,trusted_ip,trusted_port,protocol,remote_ip,remote_netmask,status) VALUES('$common_name',now(),'$trusted_ip',$trusted_port,'$proto_1','$ifconfig_pool_remote_ip','$route_netmask_1',1)" $DB

新建/etc/openvpn/disconnect.sh文件。

nano /etc/openvpn/disconnect.sh

输入以下内容:

#!/bin/bash

DB='openvpn'
DBADMIN='openvpn'
DBPASSWD='password'

mysql -u$DBADMIN -p$DBPASSWD -e "UPDATE log SET end_time=now(),bytes_received=$bytes_received,bytes_sent=$bytes_sent,status=0 WHERE trusted_ip='$trusted_ip' AND trusted_port=$trusted_port AND remote_ip='$ifconfig_pool_remote_ip' AND username='$common_name' AND status=1" $DB

mysql -u$DBADMIN -p$DBPASSWD -e "UPDATE user SET active=0 WHERE user.username IN (SELECT username FROM (SELECT log.username AS username, quota_bytes FROM user, log WHERE log.username='$common_name' AND log.username=user.username AND log.status=0 AND TO_DAYS(NOW())-TO_DAYS(start_time)< =quota_cycle GROUP BY log.username HAVING SUM(bytes_received)+SUM(bytes_sent)>=quota_bytes) AS u);" $DB

上面的数据库用户名密码替换成你设置的数据库用户名密码。

赋予文件可执行的权限。

chmod +x /etc/openvpn/connect.sh
chmod +x /etc/openvpn/disconnect.sh

其主要作用是:在用户连接时,在数据库log 表中新建一条记录,记录用户的IP 地址、端口号、连接时间等信息。在用户断开连接时,更新刚才添加的记录,记下用户的断开连接时间、发送数据量、接收数据量等。然后,对用户的流量进行判断,若超过配额,则将用户锁定(active=0)。

user 表中的quota_cycle 是用户的流量计算周期,quota_bytes 是用户每个周期内最多允许的流量。connect.sh 和disconnect.sh 脚本文件中调用了OpenVPN 的环境变量。OpenVPN 在执行脚本时,自动各种设置了环境变量,供脚本使用。

使用cron 每天对用户进行检查
以上操作在用户超过流量时自动将用户锁定。每天还应该执行一次检查,把已经恢复流量的用户解锁。可以通过cron实现此功能。

建立文件/etc/cron.daily/openvpn

nano /etc/cron.daily/openvpn

内容如下:

#!/bin/bash
DB='openvpn'
DBADMIN='openvpn'
DBPASSWD='password'
mysql -u$DBADMIN -p$DBPASSWD -e "UPDATE user SET active=1" $DB
mysql -u$DBADMIN -p$DBPASSWD -e "UPDATE user SET active=0 WHERE user.username IN (SELECT username FROM (SELECT log.username AS username, quota_bytes FROM user, log WHERE log.username=user.username AND log.status=0 AND TO_DAYS(NOW())-TO_DAYS(start_time)< =quota_cycle GROUP BY log.username HAVING SUM(bytes_received)+SUM(bytes_sent)>=quota_bytes) AS u);" $DB
mysql -u$DBADMIN -p$DBPASSWD -e "UPDATE user SET active=0 WHERE enabled=0" $DB

同样把上面的数据库用户名密码替换成你设置的数据库用户名密码。

其思路是:先默认将所有用户解锁,然后将超过流量的用户锁定。同时,管理员可以通过user 表中的enabled 字段手工禁用用户。

赋予文件可执行权限:

chmod +x /etc/cron.daily/openvpn

修改saslauthd 的缓存时间。

saslauthd 默认有一段较长的缓存时间,在用户通过认证后的一段时间里,可以再次通过认证而不需要重新查询数据库。这样不利于实现对超流量用户的立即锁定。saslauthd 启动时有一个-t 参数,可以设置其超时时间。

修改/etc/default/saslauthd文件

nano /etc/default/saslauthd

saslauthd 启动时有一个-t 参数,可以设置其超时时间,最后一行的OPTIONS,添加-t 60。

OPTIONS="-c -m /var/run/saslauthd -t 60"

客户端的安装

Windows用户直接下载Windows Installer即可,安装按默认安装就可以了。

接下来在服务器上拷贝三个证书文件下来,分别是ca.crt,client1.key,client1.crt,放到C:\Program Files\OpenVPN\config\目录下,新建一个myvpn.ovpn文件,用记事本打开

client
dev tun
proto udp
remote 服务器ip 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert client1.crt
key client1.key
#这里需要一定要增加,否则无法访问
auth-user-pass

push "dhcp-option DNS 208.67.222.222"
push "dhcp-option DNS 208.67.220.220"

ns-cert-type server
redirect-gateway
keepalive 20 60
comp-lzo
verb 3
mute 20
route-method exe
route-delay 2

非流量监控管理

在disconnect.sh 中去掉相应字段即可

#!/bin/bash

DB='openvpn'
DBADMIN='openvpn'
DBPASSWD='password'

mysql -u$DBADMIN -p$DBPASSWD -e "UPDATE log SET end_time=now(),bytes_received=$bytes_received,bytes_sent=$bytes_sent,status=0 WHERE trusted_ip='$trusted_ip' AND trusted_port=$trusted_port AND remote_ip='$ifconfig_pool_remote_ip' AND username='$common_name' AND status=1" $DB

#mysql -u$DBADMIN -p$DBPASSWD -e "UPDATE user SET active=0 WHERE user.username IN (SELECT username FROM (SELECT log.username AS username, quota_bytes FROM user, log WHERE log.username='$common_name' AND log.username=user.username AND log.status=0 AND TO_DAYS(NOW())-TO_DAYS(start_time)< =quota_cycle GROUP BY log.username HAVING SUM(bytes_received)+SUM(bytes_sent)>=quota_bytes) AS u);" $DB

将最下面的定期清理相应的超过流量的客户

tips: 这里面应该有个小bug,可以留到后面进行修改,在用户disconnect的时候,仅搜索了4个字段,用户的ip、端口、远程ip、用户名。但是可能出现跨天的情况,而update找到的是第一个,可能日志状态后续会混乱。这里后面还是应该加上相应的时间,至少需要保持更新用户几天之内的。

证书管理

用上面的方法,通过mysql连接的时候,依然需要客户端证书,才能进行登录。

所以针对安全考虑,可以分发不同的证书给不同的组织,然后针对某些组织,再分配相应的账号密码进行安全验证。

证书有效期

默认的OpenVPN配置,客户端证书有效期是10年。如何自定义客户端证书的时间呢?其实比较简单,编辑vars文件,找到export KEY_EXPIRE=3650这一行,把默认的3650,改为你想设置的天数即可。编辑后保存,运行一次vars,设置好环境变量,再用build-key生成客户端证书,即可。这样一来,客户端证书的有效期,就是你所设置的有效期了。

给客户的一些证书可以修改为30天过期,过期之后可以删除再重新生成新的证书

吊销证书

和PPTP VPN不一样,PPTP VPN直接删除客户端帐号,就可以了。在OpenVPN中,是通过revoke操作,吊销客户端证书,来实现禁止客户端连接OpenVPN的。
具体的方法如下:

#进入OpenVPN配置文件所在目录
#执行vars,初始化环境
. vars
#使用revoke-full命令,吊销客户端证书
./revoke-full clientName
#clientName是被吊销的客户端证书名称

命令执行后,我们能在keys目录中找到一个文件,名叫:crl.pem ,这个文件中包含了吊销证书的名单。然后,在服务端配置文件中,加入如下一行:

crl-verify /etc/openvpn/easy-rsa/keys/crl.pem

注意这里路径要对,要么是相对路径,否则openvpn server会起不起来

最后一步,重启OpenVPN服务,即可。

制作客户端说明文档

[[OpenVPN 客户端说明文档]]

制作一个给外部的客户端和用户名密码

生成客户端证书

cd /etc/openvpn/easy-rsa/
./build-key extraclient

将 client文件拷贝出

将 client替换到文件中,修改相关内容

2017/3/26 posted in  linux

Linux 调试三剑客——strace,lsof,tcpdump

Brendan D. Gregg 专注 Linux performance & tuning 许多年,其博客 brendangregg.com 里关于分析和调优的干货琳琅满目。一篇名为 Linux Performance 文章全面而详细的整理了常用工具,覆盖了硬件、存储、网络乃至应用,如下图:

linux_observability_tools

能掌握上图的十八般武艺固然最好,从定位分析的角度来说,我认为三个高级而常用的命令是 strace, lsof 和 tcpdump。

strace

strace - trace system calls and signals

据说,对一个经验丰富的 Linux C/C++ 工程师,他通过 strace 即可分析多数软件的大致实现方式。Linux 进程空间可分为用户空间和内核空间,程序通常运行在用户态,它需要通过 系统调用 访问内核空间。系统调用的重要性不言而喻,凡是涉及到进程、文件管理、设备管理和通信等的操作都必须依赖系统调用完成,如下:

  • Process Control: load_execute_end_abort_create_terminate process, get_set process attributes, wait for time_event_signal, allocate/free memory
  • File management: create_delete_open_read_write_reposition file, get_set file attributes
  • Device Management: request_release_attach_detach device,read_write_reposition, get_set device attributes
  • Communication: create_delete connection, send_receive messages, transfer status information

strace 追踪进程产生的所有系统调用,包括参数、返回值和执行消耗的时间,很多是涉及到内核和资源层面的操作都需要系统调用完成,所以 strace 在诊断以下场景非常有效:

strace 的通常使用方式如下:

strace -f -F -T -tt -o output.txt straced_cmd -f 跟踪 fork 产生的子进程
-F 跟踪 vfork 产生的子进程
-tt 在输出中的每一行前加上时间信息,微秒级
-T 显示每一个调用所耗的时间
-o 输出到指定文件 output.txt

例如:

$ strace -T -tt -f -F ls
14:17:18.096447 execve("/bin/ls", ["ls"], [/* 31 vars */]) = 0 <0.000191>
14:17:18.097156 brk(0) = 0x1852000 <0.000196>
14:17:18.097554 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) <0.000088>
14:17:18.097836 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f6056b52000 <0.000186>
14:17:18.098242 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) <0.000097>
14:17:18.101519 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 <0.000131>

对于守护进程,strace 的使用为:

strace -T -tt -e trace=all -o output.txt -p daemon_pid

lsof

Unix philosophy: everything is a file.

Linux/Unix 的 文件类型 有以下 7 种:

  • Regular file
  • Directory
  • Symbolic link
  • Named pipe
  • Socket
  • Device file
  • Door

lsof 用于查看进程打开的文件,使用方式如下:

# 查看某个进程打开的文件
lsof -p pid # 查看某个文件被哪些进程打开
lsof file_name

例如:

# 1250 为 nova-api 的 pid
$ lsof -p 1250
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nova-api 1250 nova cwd DIR 252,0 4096 133223 /var/lib/nova
nova-api 1250 nova rtd DIR 252,0 4096 2 /
nova-api 1250 nova txt REG 252,0 3345416 274069 /usr/bin/python2.7
nova-api 1250 nova mem REG 252,0 31720 407980 /usr/lib/python2.7/dist-packages/Crypto/Cipher/_AES.x86_64-linux-gnu.so
......
nova-api 1250 nova 5w FIFO 0,9 0t0 12796 pipe
nova-api 1250 nova 6u IPv4 12864 0t0 TCP *:8773 (LISTEN)
nova-api 1250 nova 7u IPv4 12891 0t0 TCP *:8774 (LISTEN)
nova-api 1250 nova 8r CHR 1,9 0t0 6683 /dev/urandom
nova-api 1250 nova 9u IPv4 12986 0t0 TCP *:8775 (LISTEN)
nova-api 1250 nova 17u 0000 0,10 0 6631 anon_inode~ bash

又如,查询 _var_log_nova_nova-api 被哪些进程打开:

$ lsof /var/log/nova/nova-api.log
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nova-api 1250 nova 3w REG 252,0 2086779 133272 /var/log/nova/nova-api.log
nova-api 2235 nova 3w REG 252,0 2086779 133272 /var/log/nova/nova-api.log
nova-api 2247 nova 3w REG 252,0 2086779 133272 /var/log/nova/nova-api.log
nova-api 2255 nova 3w REG 252,0 2086779 133272 /var/log/nova/nova-api.log

tcpdump

tcpdumpwireshark 类似,都是抓包工具,windows 用户多用 wireshark,linux 用户多用 tcpdump。tcpdump 允许用户拦截和显示发送或收到过网络连接到该计算机的TCP/IP和其他数据包,从数据链路层、网络层、传输层乃至应用层,覆盖了多种常用协议,并提供了丰富的过滤功能,使用如下:

过滤网卡:

过滤 IP:

tcpdump net 10.10.10.1
tcpdump src net 10.10.10.1
tcpdump dst net 10.10.10.2

过滤 port:

tcpdump port 80
tcpdump src port 80
tcpdump dst port 80

过滤 protocol:

tcpdump arp
tcpdump icmp
tcpdump ip
tcpdump udp
tcpdump tcp

常用表达试:

& or 'and'
|| or 'or'
! or 'not'

抓取所有经过 eth0,目的地址是 10.10.10.1:80 的 TCP 数据:

$ tcpdump -i eth0 (tcp) and (dst port 80) and (dst net 10.10.10.1)

Linux 调试三剑客——strace,lsof,tcpdump

2017/3/10 posted in  linux

CentOS 改变默认的磁盘配置

  • release

CentOS 默认情况安装会把所有的磁盘都安装到home的目录下,导致根目录十分小,需要重新划分一下磁盘大小,否则过一段时间以后磁盘就会占满。

基本流程

所以下面要做的步骤大概为:(最好能root用户登录系统,本机或者ssh root过去,免得不必要的麻烦)

  1. 备份_home_用户文件,要是没啥内容则忽略这步(为什么非要这个/home,删掉直接用root?还是保留它,它存在也有道理的,再说生产环境还是不要只用root)
  2. umount /home 卸载并lvremove删除这个home逻辑卷,释放它的空间
  3. lvcreate新建一个小的卷,并在其上mkfs建立xfs文件系统,分配挂载到/home,拷贝回来之前的内容
    (这个时候空余的空间随便你分配,可以再建立别的逻辑卷,或者直接空闲下来以后使用,也可以直奔主题的走下面的第四步)
  4. 把之前的home逻辑卷释放并分配新卷home之后剩下的空间,lvextend分配给root卷,并用命令xfs_growfs扩展它的文件系统空间

查看磁盘占用情况

首先看看当前默认的磁盘使用及挂载情况,home占用的空间真的太大而根目录太小,其中的逻辑卷的挂载格式为_dev_mapper/VolumeGroupName-LogicalVolumeName

使用df -h 查看当前磁盘占用情况

# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/mapper/vg_hansapdb-lv_root
                       50G   43G  4.1G  92% /
tmpfs                 7.8G     0  7.8G   0% /dev/shm
/dev/sda1             477M   33M  419M   8% /boot
/dev/mapper/vg_hansapdb-lv_home
                      238G  1.3G  225G   1% /home

查看当前磁盘格式

查看 _etc_fstatb 来查看当前各个盘符的问题

# cat /etc/fstab

#
# /etc/fstab
# Created by anaconda on Wed Jan 13 10:20:24 2016
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/vg_hansapdb-lv_root /                       ext4    defaults        1 1
UUID=60c8ed49-535a-4b0d-9e42-a73f61f7b2f0 /boot                   ext4    defaults        1 2
/dev/mapper/vg_hansapdb-lv_home /home                   ext4    defaults        1 2
/dev/mapper/vg_hansapdb-lv_swap swap                    swap    defaults        0 0
tmpfs                   /dev/shm                tmpfs   defaults        0 0
devpts                  /dev/pts                devpts  gid=5,mode=620  0 0
sysfs                   /sys                    sysfs   defaults        0 0
proc                    /proc                   proc    defaults        0 0

查看 当前逻辑卷组和逻辑卷的情况

使用vgdisplay查询磁盘组

vgdisplay
  --- Volume group ---
  VG Name               vg_hansapdb
  System ID
  Format                lvm2
  Metadata Areas        1
  Metadata Sequence No  4
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                3
  Open LV               3
  Max PV                0
  Cur PV                1
  Act PV                1
  VG Size               299.51 GiB
  PE Size               4.00 MiB
  Total PE              76674
  Alloc PE / Size       76674 / 299.51 GiB
  Free  PE / Size       0 / 0
  VG UUID               8lXkCf-vbGm-QXpu-avsd-6aRo-75RY-iOwEoG

使用lvdisplay查询逻辑磁盘

lvdisplay
  --- Logical volume ---
  LV Path                /dev/vg_hansapdb/lv_root
  LV Name                lv_root
  VG Name                vg_hansapdb
  LV UUID                yJ5F91-atmr-NYb8-mgtd-bG1R-H6Ot-zLGxQg
  LV Write Access        read/write
  LV Creation host, time hansapdb, 2016-01-13 10:16:37 +0800
  LV Status              available
  # open                 1
  LV Size                50.00 GiB
  Current LE             12800
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           253:0

  --- Logical volume ---
  LV Path                /dev/vg_hansapdb/lv_home
  LV Name                lv_home
  VG Name                vg_hansapdb
  LV UUID                vPxjPg-JiMb-RqoF-gI4r-Jkdy-MSIt-nwWARx
  LV Write Access        read/write
  LV Creation host, time hansapdb, 2016-01-13 10:17:03 +0800
  LV Status              available
  # open                 1
  LV Size                241.68 GiB
  Current LE             61870
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           253:2

  --- Logical volume ---
  LV Path                /dev/vg_hansapdb/lv_swap
  LV Name                lv_swap
  VG Name                vg_hansapdb
  LV UUID                IawfNu-JEkc-SnXw-V1cl-isWv-MlGo-YjPlix
  LV Write Access        read/write
  LV Creation host, time hansapdb, 2016-01-13 10:18:41 +0800
  LV Status              available
  # open                 1
  LV Size                7.83 GiB
  Current LE             2004
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           253:1

配置流程

备份/home目录数据

有数据的话还是尽量的对数据进行一个备份,否则后面可能会把数据删掉

卸载这个/home并删除这个逻辑卷home

unmount /home

如果无法删除,则可以采用fuser 来强制删除

# umount /home
umount: /home: device is busy.
        (In some cases useful info about processes that use
         the device is found by lsof(8) or fuser(1))
[root@hansapdb /]# fuser -m /home
/home:               15798c

3.删除_dev_mapper/centos-home这个逻辑卷

lvremove /dev/mapper/centos-home
Do you really want to remove active logical volume home? [y/n]: y  
  Logical volume "home" successfully removed

新建卷

新建一个卷home,fdisk格式化为8e格式,文件系统还是搞为xfs,同时分配挂载到home

L表示大小,默认单位为M;n表示卷名;这里的centos是CentOS7安装系统的时候就默认建立好的卷组名

lvcreate -L 50G -n home centos
 WARNING: xfs signature detected on /dev/centos/home at offset 0. Wipe it? [y/n]: y  
  Wiping xfs signature on /dev/centos/home.  
  Logical volume "home" created.

激活卷组centos,使得这个新建的home逻辑卷生效(用vgchange而不用lvchange)

vgchange -ay centos

在新建的逻辑卷home上建立ext4文件系统

# mkfs.ext4 /dev/vg_hansapdb/lv_home
mke2fs 1.41.12 (17-May-2010)
文件系统标签=
操作系统:Linux
块大小=4096 (log=2)
分块大小=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
3276800 inodes, 13107200 blocks
655360 blocks (5.00%) reserved for the super user
第一个数据块=0
Maximum filesystem blocks=4294967296
400 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks:
    32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
    4096000, 7962624, 11239424

正在写入inode表: 完成
Creating journal (32768 blocks): 完成
Writing superblocks and filesystem accounting information: 完成

This filesystem will be automatically checked every 35 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.

把这个新逻辑卷home挂到之前的文件夹/home中去

mount /dev/vg_hansapweb/lv_home /home/

5.最后再把释放出来多余的空间分配给root卷并xfs_growfs扩展文件系统

lvextend -L +150G /dev/vg_hansapweb/lv_root

再次激活下卷组centos

resize2fs -p /dev/vg_hansapweb/lv_home

方法二,改变大小(可参考使用)

1.首先查看磁盘使用情况
[root@localhost ~]# df -h
文件系统 容量 已用 可用 已用% 挂载点
Filesystem Size Used Avail Use% Mounted on

_dev_mapper/VolGroup-lv_root 154G 7.9G 139G 6% /
tmpfs 1.9G 100K 1.9G 1% _dev_shm
_dev_sda1 485M 69M 391M 15% /boot
_dev_mapper/VolGroup-lv_home 299G 984M 283G 1% /home

2、卸载/home
[root@localhost ~]# umount /home
umount _home 如果提示无法卸载,则是有进程占用_home,使用如下命令来终止占用进程:
[root@localhost ~]# fuser -m /home

如果还是无法卸载,执行umount -l /home
3、调整分区大小
[root@localhost ~]# resize2fs -p _dev_mapper/VolGroup-lv_home 20G
如果提示运行“e2fsck -f _dev_mapper/VolGroup-lv_home”,则执行相关命令:
[root@localhost ~]# e2fsck -f _dev_mapper/VolGroup-lv_home 然后重新执行命令:
[root@localhost ~]# resize2fs -p _dev_mapper/VolGroup-lv_home 20G
注:resize2fs 为重新设定磁盘大小,只是重新指定一下大小,并不对结果有影响,需要下面lvreduce的配合

4、挂载上/home,查看磁盘使用情况
[root@localhost ~]# mount /home
[root@localhost ~]# df -h

5、设置空闲空间
使用lvreduce指令用于减少LVM逻辑卷占用的空间大小。可能会删除逻辑卷上已有的数据,所以在操作前必须进行确认。记得输入 “y”
[root@localhost ~]# lvreduce -L 20G _dev_mapper/VolGroup-lv_home
注:lvreduce -L 20G的意思为设置当前文件系统为20G,如果lvreduce -l 20G是指从当前文件系统上减少20G
使用lvreduce减小逻辑卷的大小。注意:减小后的大小不能小于文件的大小,否则会丢失数据。

可以使用vgdisplay命令等查看一下可以操作的大小。也可以是用fdisk -l命令查看详细信息。
[root@localhost ~]# vgdisplay
查看“Free PE / Size”剩余空间
Free PE / Size 265598 / 283G
注:vgdisplay为显示LVM卷组的元数据信息

6.把闲置空间挂在到根目录下
[root@localhost ~]# lvextend -L +283G _dev_mapper/VolGroup-lv_root
注:lvextend -L +283G为在文件系统上增加283G 这里的283G容量为上一步查看的剩余空间,就是红色部分
[root@localhost ~]# resize2fs -p _dev_mapper/VolGroup-lv_root
这一步比较慢,耐心等待。

7、检查调整结果
[root@localhost ~]# df -h

2017/3/10 posted in  linux