[Flask教程] 3.render_template渲染模板及jinja2

我们之前的视图函数,返回的都是简单的’Hello Wolrd’之类的字符串,怎么返回一个html呢?首先我们在templates文件夹建立一个html文件,内容随便写一点如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Index</title>
</head>
<body>
<h1>This is index page</h1>
</body>
</html>

我们可以使用Flask对象app的send_static_file方法,使视图函数返回一个静态的html文件,但现在我们不使用这种方法,而是使用flask的render_template函数,它功能更强大。
从flask中导入render_template,整体代码如下:

from flask import Flask, render_template
import config

app = Flask(__name__)
app.config.from_object(config)


@app.route('/')
def index():
    return render_template('index.html')

if __name__ == '__main__':
    app.run()

render_template函数会自动在templates文件夹中找到对应的html,因此我们不用写完整的html文件路径。用浏览器访问’/’这个地址,显示结果如下:

未分类

那么为何称之为模板呢?因为render_template不仅能渲染静态的html文件,也能传递参数给html,使一个html模板根据参数的不同显示不同的内容,这是因为flask使用了jinja2这个模板引擎。要使用模板,在render_template参数中以key=value形式传入变量,在html中使用{{key}}来显示传入的变量,例如:

# 视图函数
@app.route('/')
def index():
    return render_template('index.html', contents='This is index page')

# html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Index</title>
</head>
<body>
<h1>{{ contents }}</h1>
</body>
</html>    

浏览器显示的结果与上文是一样的。我们还可以直接把一个类的实例传递过去,并在模板中访问类的属性,例如假设一个类对象obj有a和b属性,关键部分的代码如下:

# 视图函数中
return render_template('index.html', object=obj)

...
# html中
<p>a: {{ object.a }}</p>
<p>b: {{ object.b }}</p>

传入一个字典也可以,并且在模板中既可以用dict[key],也可以用dict.key。

使用过滤器,可以在html中对传入的变量进行处理,其格式是{{ 变量 | 过滤器 }},例如将前文的{{ contents }}修改为{{ contents | upper}},浏览器显示的内容就变成了:

未分类

所以我们可以很容易就理解,过滤器其实就是以变量为参数的函数,返回处理后的结果,在后端一样可以先用字符串对象的upper()函数处理好再传递给模板,效果是完全一样的。jinja2自带了一些过滤器,例如length/reverse/lower等等 ,并且我们也可以自己按照需求自定义过滤器,模板还支持{{ 变量 | 过滤器1 | 过滤器2 | … }}这样的操作。想要深入了解的话,可以搜索jinja2过滤器去进一步学习。

模板中还可以使用if else和for in控制语句,与变量使用{{ }}不同,控制语句要放在{% %}里,例如前文的contents传入一个list:

contents=[i for i in range(10)]

html中代码如下:

<h1>
    {% for i in contents %}
        {{ i }}{# 注意i也要用两个大括号 #}
    {% endfor %}
</h1>

使用for遍历contents的内容,并用{{ i }}显示出来,同时还用{# #}加了一个注释,还要注意需要使用{% endfor %}来提示循环区域的结束,因为html不像python那样通过缩进来判断循环的区域,if也是同理。浏览器显示结果:

未分类

最后for和if结合使用:

<h1>header</h1>
    {% for i in contents %}
        <p>
        {% if i%2 == 0 %}
            {{ i }}是偶数{# 注意i也要用两个大括号 #}
        {% else %}
            {{ i }}是奇数
        {% endif %}
        </p>
    {% endfor %}

结果如下(只是演示一下,不要吐槽排版和美观):

未分类

[Flask教程] 2.反转函数url_for与重定向redirect

在flask中,我们导入url_for和redirect两个函数。

from flask import Flask, url_for, redirect   

首先看url_for,简单来说,这个函数接受视图函数的名字(字符串形式)作为参数,返回视图函数对应的url,例如:

@app.route('/')
def hello_world():
    print(url_for('index'))
    return 'Hello World'

@app.route('/index/')
def index():
    return 'index'

在hello_world函数中使用print(url_for(‘index’)),将会打印出/index/。
有传参的视图函数怎么办?同样将函数名字符串作为第一个参数,将参数以key=value的形式写在后面,如:

@app.route('/')
def hello_world():
    print(url_for('hello',name='harp'))
    return 'Hello World'

@app.route('/<name>/')
def hello(name):
    return 'Hello %s' % name

打印结果为/harp/。

redirect则更简单,功能就是跳转到指定的url,大部分情况下,我们都是和url_for一起使用的,例如:

@app.route('/')
def hello_world():
    return 'Hello World'


@app.route('/<name>/')
def hello(name):
    if name == 'Harp':
        return 'Hello %s' % name
    else:
        return redirect(url_for('hello_world'))

在hello这个视图函数中,如果url传入的参数是Harp(即请求的网址是http://127.0.0.1:5000/Harp/),则返回’Hello Harp’,其他情况则重定向到hello_world这个视图函数对应的网址’/’。

[Flask教程] 1.第一个Flask程序、DEBUG模式及URL传参

–引言请见我的简书https://www.jianshu.com/p/e27…

我们打开PyCharm,新建一个Project,在左侧选择Flask,右侧Location可选择项目存放的位置,Project Interpreter选择使用的编译器,我们当然可以选择已经安装在电脑上的python 3.6,但我建议选择使用Virtualenv来建立一个虚拟的环境,这样在虚拟环境里安装包之类的,不会影响电脑上本身已经装的,并且后续如果项目较多的话也便于区分和管理。

未分类

点击Create,创建好之后,pycharm自动在项目的文件夹下建立了static/templates文件夹和HarpQA.py,此外还有一个venv文件夹,是虚拟环境用的,我们可以暂时不用管它。(如果你的PyCharm是社区版的,那么无法像专业版那样建立Flask项目,对应的文件夹需要自己手动建立。)HarpQA.py中的代码如下:

from flask import Flask

app = Flask(__name__)


@app.route('/')

def hello_world(): 

    return 'Hello World!'


if __name__ == '__main__':

    app.run()

首先从flask导入Flask,(我并没有pip install flask,为何能导入呢?我理解是建立flask项目的时候PyCharm自动帮我们做了这个事情),然后初始化一个Flask对象app,参数是namename代表的是本身这个模块的名字,我们暂时不用理解为何要传入这个参数。接下来是一个hello world函数,并且有一个装饰器@app.route(‘/’),意思是说,当接收到’/’这个网址的请求时,执行hello world这个函数,即返回字符串’Hello World!’(add_url_rule()也可以实现和@app.route一样的功能 ,但使用装饰器应该更pythonic吧),最后使用app.run()运行。运行脚本后,提示Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
我们在浏览器中输入http://127.0.0.1:5000/,就可以在网页中看到’Hello World!’了。

未分类

我们还可以使用debug模式来运行flask的服务端,开启debug模式后,修改代码不需要关闭程序,可以实时生效。有多种方法来开启debug模式:

  1. 在app.run()中添加参数app.run(debug=True);
  2. 在run之前增加app.debug = True;
  3. 新建config文件,在config文件中添加DEBUG = True,然后在程序中引入app.config.from_object(config);
  4. 在run之前增加app.config[‘DEBUG’] = True;

我们使用第3种方法,新建一个独立的文件来保存各种参数,以后项目增大的时候参数增多,便于管理。同样在项目文件夹下新建config.py文件,添加DEBUG = True,DEBUG需大写。在HarpQA.py中import config并添加app.config.from_object(config),再次运行HarpQA.py,提示:

 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 229-291-890
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

说明Debug模式已经打开,我们可以直接修改代码,例如把’Hello World!’
修改成’Hello’并保存,显示提示:

 * Detected change in 'D:\Flask\HarpQA\HarpQA.py', reloading
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 229-291-890
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

说明DEBUG模式检测到了代码的变化并自动重载了,这时候刷新网页,结果也变成了只显示’Hello’。

如果我们要处理很多URL,可以一个一个去给他们写对应的视图函数,这有时候是不切实际的,我们有更高效的做法,如以下代码:

@app.route('/<name>/')
def hello(name):
    return 'Hello %s' % name

@app.route中装饰的地址是’//’,注意name外面用了尖括号,代表name是一个参数,例如我们请求http://127.0.0.1:5000/Harp/这个网址,其中的name就是Harp,这个参数会传递给视图函数hello,最终会返回’Hello Harp’。我们可以给将写成,表示传入的参数是字符串类型的,其他的类型还有int,float,path,几种类型的区别可以在网上搜索对比一下,例如path可以将参数里的’/’也传递过来。

supervisor集中化管理web工具cesi

linux进程管理器supervisor是会经常被用到的,但服务器多了之后,每个服务器的进程也不方便管理。同时,supervisor自带的web界面比较简陋,所以尝试了一下官网推荐的一些第三方开源软件,推荐一下这个cesi。

最终效果如下:

未分类

未分类

1. 首先是关于supervisor

通过apt或pip安装都可以

apt-get install supervisor
#pip install supervisor
echo_supervisord_conf > /etc/supervisor/supervisord.conf

关于supervisor配置文件

[unix_http_server]
#这里配置是否用unix socket通信来让supervisor与supervisorctl做通信

[inet_http_server]
#这里是用的http的方式做通信

[supervisorctl]
#这里选择supervisorctl到底用以上两种中的哪种方式来与supervisor通信,选择一种即可,记得填写密码

[program:pro_name]
stdout_logfile = {path}
redirect_stderr = true  ;让stderr也写入stdout中

常用操作

supervisorctl reload #重启加载supervisor配置文件
supervisorctl update #只增加新增的配置文件

2. 关于cesi

项目地址:https://github.com/Gamegos/cesi

安装cesi

apt-get install sqlite3 python python-flask
git clone https://github.com/Gamegos/cesi
cd cesi
sqlite3 ./userinfo.db < userinfo.sql
cp cesi.conf /etc/cesi.conf

配置cesi.conf,我的配置如下,一看就懂了

[node:118]
username = ***
password = ***
host = 127.0.0.1
port = 9001

[node:calmkart]
username = ***
password = ***
host = 45.76.71.69
port = 9001

[node:121]
username = ***
password = ***
host = *.*.*.121
port = 9001

[environment:my_env]
members = 118,calmkart,121

[cesi]
database = /root/cesi/userinfo.db
activity_log = /var/log/cesi.log
host = 0.0.0.0

用supervisor运行cesi,配置文件如下

[program:cesi]
directory = /root/cesi/cesi/
command = python web.py
autostart = true
startsecs = 5
autorestart = true
startretries = 3
user = root
redirect_stderr = true
stdout_logfile = /var/log/cesi1.log

开启任务

supervisorctl start cesi

默认账号密码:admin,admin
端口需要改的自己去web.py里面改

you get it

本测试服地址:
http://cesi.calmkart.com

此外,其他常用的supervisor相关第三方工具还有

  • suponoff
  • gosuv

python编程(webpy + gunicorn + nginx部署)

之前虽然也用nginx + uwsgi + webpy的方法部署过网站,但是用了gunicorn之后,发现用这种方法部署网站更为简单。下面我详细描述一下如何用这种方法进行网站部署。

1、准备server.py

和uwsgi部署的时候一样,这里仅仅需要设置一个application就可以了。

#!/usr/bin/python
import web

urls = ('/', 'Hello')

class Hello(object):
    def GET(self):
        return 'Hello world'

app = web.application(urls, globals())  
application = app.wsgifunc()

2、安装gunicorn

安装gunicorn的方法非常简单,在ubuntu下面一条命令就可以解决,

sudo apt-get install gunicorn

3、用gunicorn启动server.py文件

启动的时候注意,最后一个选项是由文件名+wsgifunc组成的。同时,我们在选项中添加了gevent的属性,gunicorn本身支持gevent机制,可以有效提高server的性能。

gnicorn -b 127.0.0.1:8080 --worker-class gevent server:application

4、用浏览器做测试

这个时候不出意外,你已经可以用127.0.0.1:8080访问我们的网站了。

5、准备nginx.conf文件

通常为了利用nginx做static文件加速,或者利用nginx做均衡负载,我们常常需要另外安装一下nginx软件。因此,此时nginx.conf必须准备好。当然,为了简单起见,我们这里只做一个代理就可以了,整个conf文件内容如下,

worker_processes 1;

events{
    worker_connections 1024;
}

http{

    sendfile on;
    keepalive_timeout 65;

    server {
        listen       80;
        server_name  localhost;

        location / {

            proxy_pass http://127.0.0.1:8080;
        } 
    }

}

6、重启启动nginx

nginx.conf准备好后,这个时候先将它copy到/etc/nginx目录下。接下来,我们需要重新启动nginx软件,一个命令就可以了,

service nginx restart

7、用浏览器测试80端口

有了nginx做代理,这个时候就可以用浏览器访问127.0.0.1了,因为一般网站默认用80做端口,所以没有意外的话,这个时候你就可以看到webpy给出的打印消息了。

supervisor 和gunicorn部署django项目

安装使用到的基本软件nginx、supervisor、gunicorn

vi /etc/supervisor/conf.d/django_project.conf
[program:django_project]
command=gunicorn xxx.wsgi:application -b 127.0.0.1:8080 -w 8
user=user #当前用户
directory=/home/user/django_project
stdout_logfile=/tmp/var/logs/supervisor/%(program_name)s-stdout.log
stderr_logfile=/tmp/var/logs/supervisor/%(program_name)s-stderr.log
killasgroup=true
stopasgroup=true
autorstart=true
autorestart=true

# rq队列的配置

[program:rqworker]
command=python manage.py rqworker default low
user=user
directory=/home/django_project/platform
stdout_logfile=/tmp/var/logs/supervisor/%(program_name)s-stdout.log
stderr_logfile=/tmp/var/logs/supervisor/%(program_name)s-stderr.log
killasgroup=true
stopasgroup=true
autorstart=true
autorestart=true```

再在nginx配置中的location,添加

proxy_pass http://127.0.0.1:8080;

另外静态文件的代理可以添加下面的配置

location /static/ {

alias /django_project/statics/;

}

PostgreSQL共享缓存区管理

一、共享缓冲区

KingbaseES中的buffer主要是用来将外存中的数据内容读入到内存中,加速运算过程中对数据的访问速度,同时将数据的修改进行缓存,在必要时再将其写出到外存,避免频繁的I/O,以提高效率。
Buffer的种类有很多如Audit buffers、Clog buffers、Data buffers和Xlog buffers,此处所介绍的buffer管理是针对Data buffers而言的。

二、数据结构

  • BufferTag
  • BufferDesc
  • BufferStrategyControl

1、BufferTag

typedef struct buftag
{
    Oid dbid;            /* database identifier */
    FileBlock blockNum;  /* file and blocknumber */
} BufferTag;

2、BufferDesc

typedef struct sbufdesc
{
    BufferTag   tag;              /* ID of page contained in buffer */
    RelFileNode rnode;            /* relation this block belongs to */
    BufFlags    flags;            /* see bit definitions above */
    uint16      usage_count;      /* usage counter for clock sweep code */
    unsigned    refcount;         /* # of backends holding pins on buffer */
    int         wait_backend_pid; /* backend PID of pin-count waiter */
    slock_t     buf_hdr_lock;     /* protects the above fields */
    int         buf_id;           /* buffer's index number (from 0) */
    int         freeNext;         /* link in freelist chain */
    LWLockId    io_in_progress_lock; /* to wait for I/O to complete */
    LWLockId    content_lock;     /* to lock access to buffer contents */
} BufferDesc;

3、引用计数(BufferDesc.refcount)

引用计数(refcount)用于跟踪访问buffer的后台数量,防止错误的将正在被使用的Buffer淘汰。当使用Buffer时,需要将其引用计数(refcount)加1(PinBuffer)。当Buffer不再使用,需要将其引用计数(refcount)减1(UnpinBuffer)。这里需要注意,由于一个后台可以多次访问同一个Buffer,因此后台通过PrivateRefCount来记录自己的引用次数,只有当自己对一个Buffer的引用减少到0,才会真正去修改refcount。PrivateRefCount在后台PinBuffer时将其值加1,UnpinBuffer时将其值减1。

4、使用计数(BufferDesc.usage_count)

usage_count用来标记Buffer被使用的次数,usage_count值越大,说明该Buffer经常被使用,那么在未来的一段时间里被使用的可能就比较大,所以这样的Buffer不能作为被替换的对象;相反,usage_count值越小,说明经常不被使用,可以作为替换的对象。在KingbaseES中,只有当usage_count为0时,才可能作为替换的对象。
usage_count是在一个后台不再使用该Buffer即UnpinBuffer将后台的PrivateRefCount减少为0的时候将其值加1,以表示该Buffer最近被一个后台使用了。对VACUUN操作来说,不会修改usage_count的值,且如果refcount和usage_count的值都为0,则将buffer放入到FreeList的尾部。

5、BufferStrategyControl

typedef struct
{
    int    nextVictimBuffer; // 指向下一Buffer
    int    firstFreeBuffer;  // 第一个空闲缓冲块id
    int    lastFreeBuffer;   // 最后一个空闲缓冲块id
} BufferStrategyControl;
/* Pointers to shared state */
static MT_LOCAL BufferStrategyControl
    *StrategyControl = NULL;

6、Buffer Descriptors

未分类

三、主要函数

  • InitBufferPool
  • BufferAlloc
  • StrategyGetBuffer
  • FlushBuffer
  • PinBuffer
  • UnpinBuffer

1、InitBufferPool流程

未分类

2、BufferAlloc流程

未分类

四、缓冲区替换策略

  • FreeList
  • Clock-sweep
  • buffer-ring

1、FreeList

当执行DROP TABLE时,可以确定该表的所有buffer都会失效,因此将此表的所有buffer都放入到Freelist的头部,这样可以在下一次分配buffer时,直接从Freelist中得到buffer,而不需要执行Clock Sweep算法。

2、Clock-sweep

当Buffer的refcount计数变成0的时候,代表当前系统没有后台引用此数据块。在KingbaseES中,为了能够减低锁的粒度、提高并发性,引用计数等于0的的Buffer并没有被放入Freelist中。在随机访问大量磁盘块、并且没有VACUUM的干扰下,Freelist几乎是空的(除了刚刚启动时)。这里的策略主要是为了避免不必要的持有操作Freelist的互斥锁。
由于大部分时候Buffer不会立即被放入到Freelist中,因此使用了一种被称为Clock Sweep的算法来分配Buffer。此算法类似教科书中时钟算法,每当需要使用Clock Sweep算法选择一个Buffer时,就从上次分配的Buffer的下一个位置开始,搜索引用计数为0(既没有被pin的Buffer)且usage_count为0的Buffer。如果该Buffer不满足上述条件,就将usage_count减1。

3、Clock-sweep

未分类

在上图中Clock Sweep算法从4号buffer开始查找(记录在StrategyControl结构体中)可用的buffer。4号buffer因为引用计数大于0,因此不能被替换。5号buffer虽然没有人引用,但是其usage_count大于0,因此表示此buffer使用频率较高,因此将usage_count减1,并查看6号buffer。6号buffer的引用计数和usage_count都为0,因此选择将6号buffer淘汰。记录下一次搜索的位置是7号,并退出选择算法。

4、buffer-ring

批量读或者vacuum等操作可能会需要占据大量的buffer,影响其他正常业务。buffer-ring机制在批量读等占用的buffer数量达到某个程度(比如总buffer的1/4)时,分配给该操作固定的buffer数量,之后只能使用为其分配的buffer,而不能替换其他buffer。

Linux系统,Centos7版本下搭建postfix服务器及其相关配置应用

实验报告

一、 实验名称:邮件服务器的搭建和相关使用功能的配置

二、 实验环境与要求:Linux系统 centos7版本

搭建邮件服务器实现发信收信基本功能
实现发信认证功能
搭建好LAMP环境,配置squirrelmail收发邮件

三、 实验内容:

1、 检查版信息,postfix安装情况与支持的功能,启动运行;
2、 搭建与之相关的DNS服务器,配置DNS解析功能;
3、 配置postfix基本发信功能,进行测试;
4、 安装dovecot提供收信服务,进行测试;
5、 客户端利用邮箱软件配置测试服务器功能;
6、 进行发信认证配置;
7、 搭建LAMP环境,配置squirrelmail收发邮件

实验步骤

第一步

cat /etc/redhat-release //检查版本信息

未分类

※安装postfix(版本自带) centos7版本即使用最小化安装仍自带此功能

postconf -a // 验证是否支持cyrus dovecot功能

未分类

启动服务器systemctl start postfix

netstat -anpt | grep 25 //查看监听端口号

未分类

第二步

※搭建与之相关的DNS服务器,配置DNS解析功能

yum install bind //安装服务器程序
vi /etc/named.conf //编辑主配置文件

未分类

未分类

※以下进行区域文件配置:

cd /var/named/ 进入文件目录下

复制配置文件的模板进行修改:

cp -p named.localhost yyf.com.zone
cp -p named.localhost yyf.com.local
vi /var/named/yyf.com.zone 编辑正向区文件

如图:

未分类

vi /var/named/yyf.com.local 编辑反向区文件

如图:

未分类

以上基本配置编辑完成

systemctl start named //启动服务器
netstat -anpu | grep name //检测到UDP 53端口在监听 服务器正常工作。

进行DNS验证

vi /etc/resolv.conf
nameserver 192.168.80.18 //指向DNS服务器地址

rpm -ivh /mnt/Packages/bind-utils-9.9.4-50.el7.x86_64.rpm //安装检测命令nslookup

解析如图:

~nslookup mail.yyf.com //正向解析 

未分类

~nslookup 192.168.80.18 //反向解析

未分类

解析成功!

第三步

—–配置postfix基本发信功能

vi /etc/postfix/main.cf 编辑配置文件 修改项如下:

myhostname = mail.aa.com //本机系统主机名
mydomain = aa.com //主机域名
myorigin = $mydomain //根源、起点
inet_interfaces = 192.168.80.18, 127.0.0.1 //接口地址
inet_protocols = ipv4
mydestination = $myhostname, $mydomain //预定、指定范围
home_mailbox = Maildir/ //信箱家目录

完成后保存退出,用postfix check命令检查是否存在语法错误:

service postfix restart //重启邮件服务器

※要测试发信功能是否生效,我们需要添加用户并加入同一组管理:
—–增加邮件测试账号

groupadd mailusers //增加组账号
useradd -g mailusers -s /sbin/nologin jack //建用户jack 加入mailusers组且不可登陆系统
passwd jack(密码随便设置123)
useradd -g mailusers -s /sbin/nologin tom //建用户tom 加入mailusers组且不可登陆系统
passwd tom(密码随便设置123)

测试准备:安装yum install telnet
开始测试:连接服务器的25端口进行简单发信测试
telnet mail.yyf.com 25

依次输入以下内容:

如图:

未分类

由于目前未安装收件服务,所以只能通过root超级管理员来查看邮件是否发送成功

使用root查看tom用户是否收到测试邮件:

ls -l /home/tom/Maildir/new/ 在此目录下应该会有刚才发的邮件

未分类

可用cat命令查看内容

邮件发送功能测试成功!

第四步

※安装dovecot提供收信服务

yum install dovecot //安装系统程序
vi /etc/dovecot/dovecot.conf //配置程序文件

※修改项如下:

protocols = imap pop3 lmtp
listen = //监听 所有端口
!include conf.d/10-auth.conf //此处* 必须替换

※手动增加以下内容:

ssl = no
disable_plaintext_auth = no
mail_location = maildir:~/Maildir

※以上基本配置完成

service dovecot start //启动服务
netstat -anpt | grep dovecot // 110 143端口需要监听

如图:

未分类

服务启动成功,正常工作

※现在可以用户进行测试收信了(以前是用root,现在可以用账户)
测试开始:telnet mail.yyf.com 110

如图:

未分类

我们来读取第一份邮件看看

显示如图:

未分类

用quit 可以退出
测试结构说明收件系统工作正常

鉴于目前的收信发信方式太不友好,安装MUA软件连接服务器收发邮件

※客户端装测设软件:

未分类

用此软件进行测试,看服务器是否正常工作
基本设置如图所示:

未分类

未分类

登陆后收件:

未分类

邮件接受正常
服务器工作正常

第五步

以下进行发信认证配置

yum install cyrus-sasl* 安装相关软件包

vi /etc/sasl2/smtpd.conf 开始编辑配置文件,内容如下:

pwcheck_method: saslauthd
mech_list: plain login
log_level:3 //设置日志级别为3
vi /etc/sysconfig/saslauthd //编辑认证系统配置文件
MECH=shadow

service saslauthd start //开启认证功能服务器
vi /etc/postfix/main.cf //编辑配置文件
在末尾新增
smtpd_sasl_auth_enable = yes //开启认证
smtpd_sasl_security_options = noanonymous //不允许匿名发信
mynetworks = 127.0.0.0/8 //允许的网段,如果增加本机所在网段就会出现允许 不验证也能向外域发信
smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject_unauth_destination //允许本地域以及认证成功的发信,拒绝认证失败的发信

postfix check //检查语法
service postfix restart //重启服务器

※测试普通发信

telnet mail.yyf.com 25

如图:

未分类

向未认证区域发件失败说明认证系统是生效的
quit 退出

※下面用系统账户进行发信测试

将用户名与密码生成密文加密:

printf "jack" | openssl base64 //生成密文
amFjaw== (密文)
printf "123" | openssl base64 //生成密文
MTIz (密文)

※开始用字符终端测试认证发信:

telnet mail.aa.com 25

如图:

未分类

未分类

若在真机用邮箱软件测试,只需做如下操作:

未分类

将高级设置中的选项勾选即可验证

第六步

—-以下是配置squirrelmail收发邮件内容
需要搭建好LAMP环境

--------安装LAMP---------
yum install -y 
httpd 
mariadb-server mariadb 
php 
php-mysql 
php-gd 
libjpeg* 
php-ldap 
php-odbc 
php-pear 
php-xml 
php-xmlrpc 

php-mhash 注: 安装相关软件包,其中表示强制换行操作

vi /etc/httpd/conf/httpd.conf //编辑配置文件

需要修改的内容:

ServerName www.aa.com ///服务器名称
DirectoryIndex index.html index.php ///支持静态与动态网页
vi /etc/php.ini //编辑此配置文件
date.timezone = PRC //设置时区

提醒:系统中的防火墙与安全Linux要确认关闭,否则影响实验

systemctl stop firewalld.service
setenforce 0

systemctl start httpd.service 网页系统启动
systemctl start mariadb.service 数据库系统启动

netstat -anpt | grep 80
netstat -anpt | grep 3306 //端口在监听,说明服务器启动正常

未分类

未分类

※mysql_secure_installation 进行安全校验,也可不设置

接下来

vi /var/www/html/index.php 编辑数据库文件

在里面写入脚本如下:

<?php
phpinfo();
?>

用真机浏览器测试:

http://192.168.80.18 将出现如下页面,说明设置成功

未分类

※进入数据库,建立授权账号

mysql -u root -p

进数据库时设置一下密码:123456

CREATE DATABASE bcd; //建立数据库名字bcd
GRANT all ON bcd.* TO 'mail'@'%' IDENTIFIED BY '123456'; 
flush privileges; //刷新一下权限

下面测试数据库工作是否正常

vi /var/www/html/index.php //编辑配置文件,该文件为数据库工作目录

删除以前内容,写入如下内容:

<?php
$link=mysql_connect('192.168.80.18','mail','123456'); //说明地址与密码
if($link) echo "<h1>Success!!</h1>"; //如果连接成功则会显示Success!!
else echo "Fail!!"; //如果连接失败则显示Fail!!
mysql_close();
?>

保存退出

测试:

未分类

连接成功!

到下面网址下载小松鼠包与汉化语言包

http://www.squirrelmail.org/download.php

1、squirrelmail-webmail-1.4.22.tar.gz
2、all_locales-1.4.18-20090526.tar.gz

将安装包上传到Linux系统中进行解压

tar xzvf squirrelmail-webmail-1.4.22.tar.gz
tar xzvf all_locales-1.4.18-20090526.tar.gz -C squirrelmail-webmail-1.4.22 //-C表示将语言包解压到后续包中

cp -rv squirrelmail-webmail-1.4.22 /var/www/html/mail //将解压完成的包拷贝到/var/www/html/mail(网页工作目录)

cd /var/www/html/mail // cd到php工作目录下
mkdir attach //建立附件文件目录
chown -R apache:apache attach/ data/ //修改权限

cd config //到squirrelmail配置文件下
cp config_default.php config.php // 拷贝模板
vi config.php //开始编辑

修改内容如下:

$domain = 'aa.com'; //域名
$imap_server_type = 'dovecot'; //imap服务类型为dovecot
$data_dir = '/var/www/html/mail/data'; //原件存放地址
$attachment_dir = '/var/www/html/mail/attach/'; //附件存放地址
$squirrelmail_default_language = 'zh_CN'; //网页显示语言为中文
$default_charset = 'zh_CN.UTF-8'; //中文字符编码

用真机浏览器登陆测试:

http://192.168.80.181/mail

出现登录界面,如图:

未分类

输入账户登陆:
显示如下:

未分类

成功进入并且可正常操作使用,服务器工作正常。

第七步

※以下设置邮件组

vi /etc/aliases 编辑配置文件

增加组名:student:jack,tom

newaliases //生成hash数据库文件
systemctl restart postfix //重启邮件服务器br/>测试向[email protected]发信的时候jack,tom都会收到。

测试如下:

※用tom向组邮箱发送组邮件

未分类

检查收件情况:

未分类

未分类

测试结果符合要求

※以下设置邮件大小

vi /etc/postfix/main.cf //编辑配置文件

手动写入:

message_size_limit = 5120000 //单位是Byte

保存后退出!

systemctl restart postfix //重启邮件服务器

通过增加大附件测试效果

未分类

未分类

※以下通过配置用户磁盘配额实现限制用户邮箱空间
邮件存放目录在home下,挂载于/dev/sda5盘上

未分类

[root@yyf ~]# umount /home
[root@yyf ~]# mount -o usrquota,grpquota /dev/sda5
[root@yyf ~]# vi /etc/fstab

最后一行加上:

未分类

未分类

开启磁盘配额:

edquota -u jack

配额硬性为20M 如图:

未分类

用户系统中检测磁盘配额是否生效:

未分类

超出配额,已生效。
用客户端软件测试:

发送大小为6.6M的邮件,已成功发送两个(已取消单个邮件不得大于5M的配置)

未分类

第三份发送失败

未分类

查看目录剩余空间,限额20M的情况下,已不足6.6M的空间,故第三份发送必然失败

未分类

所以对jack用户做的磁盘配额生效。

yarn使用cgroup隔离资源

yarn默认只管理内存资源,虽然也可以申请cpu资源,但是在没有cpu资源隔离的情况下效果并不是太好.在集群规模大,任务多时资源竞争的问题尤为严重.
还好yarn提供的LinuxContainerExecutor可以通过cgroup来隔离cpu资源

cgroup

cgroup是系统提供的资源隔离功能,可以隔离系统的多种类型的资源,yarn只用来隔离cpu资源

安装cgroup

默认系统已经安装了cgroup了,如果没有安装可以通过命令安装

CentOS 6

yum install -y libcgroup

CentOS 7

yum install -y libcgroup-tools

然后通过命令启动

CentOS 6

/etc/init.d/cgconfig start

CentOS 7

systemctl start cgconfig.service

查看/cgroup目录,可以看到里面已经创建了一些目录,这些目录就是可以隔离的资源

drwxr-xr-x 2 root root 0 3月  19 20:56 blkio
drwxr-xr-x 3 root root 0 3月  19 20:56 cpu
drwxr-xr-x 2 root root 0 3月  19 20:56 cpuacct
drwxr-xr-x 2 root root 0 3月  19 20:56 cpuset
drwxr-xr-x 2 root root 0 3月  19 20:56 devices
drwxr-xr-x 2 root root 0 3月  19 20:56 freezer
drwxr-xr-x 2 root root 0 3月  19 20:56 memory
drwxr-xr-x 2 root root 0 3月  19 20:56 net_cls

如果目录没有创建可以执行

cd /
mkdir cgroup
mount -t tmpfs cgroup_root ./cgroup
mkdir cgroup/cpuset
mount -t cgroup -ocpuset cpuset ./cgroup/cpuset/
mkdir cgroup/cpu
mount -t cgroup -ocpu cpu ./cgroup/cpu/
mkdir cgroup/memory
mount -t cgroup -omemory memory ./cgroup/memory/

通过cgroup隔离cpu资源的步骤为

1、在cpu目录创建分组

cgroup以组为单位隔离资源,同一个组可以使用的资源相同
一个组在cgroup里面体现为一个文件夹,创建分组直接使用mkdir命令即可.
组下面还可以创建下级组.最终可以形成一个树形结构来完成复杂的资源隔离方案.
每当创建了一个组,系统会自动在目录立即创建一些文件,资源控制主要就是通过配置这些文件来完成

--w--w--w- 1 root root 0 3月  19 21:09 cgroup.event_control
-rw-r--r-- 1 root root 0 3月  19 21:09 cgroup.procs
-rw-r--r-- 1 root root 0 3月  19 21:09 cpu.cfs_period_us
-rw-r--r-- 1 root root 0 3月  19 21:09 cpu.cfs_quota_us
-rw-r--r-- 1 root root 0 3月  19 21:09 cpu.rt_period_us
-rw-r--r-- 1 root root 0 3月  19 21:09 cpu.rt_runtime_us
-rw-r--r-- 1 root root 0 3月  19 21:09 cpu.shares
-r--r--r-- 1 root root 0 3月  19 21:09 cpu.stat
-rw-r--r-- 1 root root 0 3月  19 21:09 notify_on_release
-rw-r--r-- 1 root root 0 3月  19 21:09 tasks

yarn默认使用hadoop-yarn组作为最上层,任务运行时yarn会为每个container在hadoop-yarn里面创建一个组
yarn主要使用cpu.cfs_quota_us cpu.cfs_period_us cpu.shares3个文件
yarn使用cgroup的两种方式来控制cpu资源分配

  • 严格按核数隔离资源
    可使用核数 = cpu.cfs_quota_us/cpu.cfs_period_us
    在yarn中cpu.cfs_quota_us被直接设置为1000000(这个参数可以设置的最大值)
    然后根据任务申请的core来计算出cpu.cfs_period_us

  • 按比例隔离资源
    按每个分组里面cpu.shares的比率来分配cpu
    比如A B C三个分组,cpu.shares分别设置为1024 1024 2048,那么他们可以使用的cpu比率为1:1:2

2、将进程id添加到指定组的tasks文件
创建完分组后只需要将要限制的进程的id写入tasks文件即可,如果需要解除限制,在tasks文件删除即可

yarn配置

启动cgroup需要配置几个配置文件

etc/hadoop/yarn-site.xml配置

可以参考http://hadoop.apache.org/docs/current/hadoop-yarn/hadoop-yarn-site/NodeManagerCgroups.html 配置
这些配置大部分都是固定配置

<property>
    <name>yarn.nodemanager.container-executor.class</name>
  <value>org.apache.hadoop.yarn.server.nodemanager.LinuxContainerExecutor</value>
</property>
<property>
    <name>yarn.nodemanager.linux-container-executor.resources-handler.class</name>
    <value>org.apache.hadoop.yarn.server.nodemanager.util.CgroupsLCEResourcesHandler</value>
</property>
<property>
    <description>yarn使用的cgroup组,默认为/hadoop-yarn</description>
    <name>yarn.nodemanager.linux-container-executor.cgroups.hierarchy</name>
    <value>/hadoop-yarn</value>
</property>
<property>
    <description>是否自动挂载cgroup</description>
    <name>yarn.nodemanager.linux-container-executor.cgroups.mount</name>
    <value>true</value>
</property>
<property>
    <description>cgroup挂载目录, /sys/fs/cgroup 或者是 /cgroup,目录和系统有关</description>
    <name>yarn.nodemanager.linux-container-executor.cgroups.mount-path</name>
    <value>/cgroup</value>
</property>
<property>
    <name>yarn.nodemanager.linux-container-executor.group</name>
    <value>hadoop</value>
</property>
<property>
    <description>配置nodemanager使用多少物理cpu资源,比如24核服务器配置90的话,最近使用21.6核</description>
    <name>yarn.nodemanager.resource.percentage-physical-cpu-limit</name>
    <value>90</value>
</property>
<property>
    <description>是控制是否严格限制cpu,即按任务申请的core限制,还是非严格限制,即按core的比率限制</description>
    <name>yarn.nodemanager.linux-container-executor.cgroups.strict-resource-usage</name>
    <value>true</value>
</property>
<property>
    <description>非安全模式将会以这里设置的用户运行container,比如配置hadoop用户则以hadoop运行container</description>
    <name>yarn.nodemanager.linux-container-executor.nonsecure-mode.local-user</name>
    <value>hadoop</value>
</property>

etc/hadoop/container-executor.cfg配置

这个配置文件每项都需要填,要不然会报错

yarn.nodemanager.linux-container-executor.group=hadoop
banned.users=root
min.user.id=1000
allowed.system.users=hadoop

权限设置

在配置中文件的权限有特殊要求

chown root:hadoop bin/container-executor
chmod 6050 bin/container-executor

系统还要求etc/hadoop/container-executor.cfg 的所有父目录(一直到/ 目录) owner 都为 root
这个路径是默认${HADOOP_HOME}/etc/hadoop/container-executor.cfg,如果不方便修改所有父级目录为root权限,可以重新编译代码到其他目录,比如/etc/hadoop/目录

mvn clean package -Dcontainer-executor.conf.dir=/etc/hadoop/ -DskipTests -Pnative

配置好以后检测是否配置成功

./bin/container-executor --checksetup

如果没有任何输出表示配置成功
如果一切顺利就可以启动集群了

测试cgroup

可以运行测试脚本测试系统

./bin/spark-submit   
--class org.apache.spark.examples.SparkPi   
--master yarn-cluster   
--deploy-mode cluster   
--num-executors 5 
--executor-cores 3 
--executor-memory 4G 
--driver-memory 4G 
--driver-cores 2 
lib/spark-examples-1.6.0-hadoop2.6.0.jar   10000

查看系统是否生效只能登录到服务器查看
通过top查看信息

未分类

查看是否创建了cgroup分组,ll /cgroup/hadoop-yarn/

--w--w--w- 1 root root 0 3月  17 15:44 cgroup.event_control
-rw-r--r-- 1 root root 0 3月  17 15:44 cgroup.procs
drwxr-xr-x 2 root root 0 3月  17 16:06 container_1489736876249_0003_01_000011
drwxr-xr-x 2 root root 0 3月  17 16:06 container_1489736876249_0003_01_000026
drwxr-xr-x 2 root root 0 3月  17 16:06 container_1489736876249_0003_01_000051
drwxr-xr-x 2 root root 0 3月  17 16:06 container_1489736876249_0003_01_000076
drwxr-xr-x 2 root root 0 3月  17 16:06 container_1489736876249_0003_01_000101
drwxr-xr-x 2 root root 0 3月  17 16:06 container_1489736876249_0003_01_000123
drwxr-xr-x 2 root root 0 3月  17 16:06 container_1489736876249_0003_01_000136
drwxr-xr-x 2 root root 0 3月  17 16:06 container_1489736876249_0003_01_000155
drwxr-xr-x 2 root root 0 3月  17 16:30 container_1489736876249_0004_01_000008
-rw-r--r-- 1 root root 0 3月  17 15:47 cpu.cfs_period_us
-rw-r--r-- 1 root root 0 3月  17 15:47 cpu.cfs_quota_us
-rw-r--r-- 1 root root 0 3月  17 15:44 cpu.rt_period_us
-rw-r--r-- 1 root root 0 3月  17 15:44 cpu.rt_runtime_us
-rw-r--r-- 1 root root 0 3月  17 15:44 cpu.shares
-r--r--r-- 1 root root 0 3月  17 15:44 cpu.stat
-rw-r--r-- 1 root root 0 3月  17 15:44 notify_on_release
-rw-r--r-- 1 root root 0 3月  17 15:44 tasks

查看container_*目录下 cpu.cfs_period_us,计算cpu.cfs_quota_us/cpu.cfs_period_us即可知道分配的核数

[root@- ~]# cat /cgroup/cpu/hadoop-yarn/container*/cpu.cfs_period_us
462962
462962
462962
462962
462962
462962
462962
462962
308641

问题处理

配置的过程中免不了会碰上一些问题,以下是我碰到的问题

spark任务申请了core,node manager分配不正确,都是分配1个核

这个是由于目前使用的capacity scheduler的资源计算方式只考虑了内存,没有考虑CPU
这种方式会导致资源使用情况统计不准确,比如一个saprk程序启动命令资源参数如下

--num-executors 1 --executor-cores 3 --executor-memory 4G --driver-memory 4G --driver-cores 1

DefaultResourceCalculator 统计占2核
DominantResourceCalculator 统计占4核
修改配置文件即可解决

  <property>
    <name>yarn.scheduler.capacity.resource-calculator</name>
    <value>org.apache.hadoop.yarn.util.resource.DominantResourceCalculator</value>
    <description>
      The ResourceCalculator implementation to be used to compare
      Resources in the scheduler.
      The default i.e. DefaultResourceCalculator only uses Memory while
      DominantResourceCalculator uses dominant-resource to compare
      multi-dimensional resources such as Memory, CPU etc.
    </description>
  </property>

container-executor运行时报缺少GLIBC_2.14库

container-executor: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by bin/container-executor)

这个和系统版本有关,只能通过重新编译container-executor来解决

mvn clean package -Dcontainer-executor.conf.dir=/etc/hadoop/ -DskipTests -Pnative

centos 7系统container启动报错,不能写入/cgroup/cpu

这个是yarn在centos 7下的一个bug,hadoop 2.8以后的版本才会解决
这个bug主要是因为centos 7下cgroup的目录和centos 6不一致导致,centos 7 cpu目录合并成cpu,cpuacct, 这个,导致的错误,需要打补丁后编译https://issues.apache.org/jira/browse/YARN-2194

 private String findControllerInMtab(String controller,
                                      Map<String, List<String>> entries) {
    for (Entry<String, List<String>> e : entries.entrySet()) {
//      if (e.getValue().contains(controller))
//        return e.getKey();

      if (e.getValue().contains(controller)) {
        String controllerKey = e.getKey();
        // In Redhat7, the controller is called "/sys/fs/cgroup/cpu,cpuacct"
        controllerKey = controllerKey.replace("cpu,cpuacct", "cpu");
        if (new File(controllerKey).exists()) {
          return controllerKey;
        }
      }
    }

    return null;
  }

升级的风险

由于改变了资源的隔离方式,升级可能有几个方面的影响

任务资源分配问题

升级cgroup后单个任务如果以前资源分配不合理可能会出现计算延时情况,出现资源问题时需要调整任务资源
在集群规模小的时候可能没有资源可以调整,那么可以修改为非严格模式,非严格模式不能按配置限制资源,只能保证资源不被少数进程全部占用

<property>
    <name>yarn.nodemanager.linux-container-executor.cgroups.strict-resource-usage</name>
    <value>false</value>
</property

spark driver资源问题

spark任务的driver在集群模式deploy-mode cluster时,如果没有配置driver-cores的话默认分配1核,1核在任务规模大时有可能资源会紧张.采用deploy-mode client模式的不受cgroup限制

CentOS 7安装bbr教程

未分类

Google 开源了其 TCP BBR 拥塞控制算法,并提交到了 Linux 内核,从 4.9 开始,Linux 内核已经用上了该算法。根据以往的传统,Google 总是先在自家的生产环境上线运用后,才会将代码开源,此次也不例外。
根据实地测试,在部署了最新版内核并开启了 TCP BBR 的机器上,网速甚至可以提升好几个数量级。

安装

CentOS 7.3

1、yum系统更新(更新到CentOS 7.3)

yum update

2、查看系统版本

cat /etc/redhat-release

输出如下(release数值大于7.3即可),则表示已升级到7.3

CentOS Linux release 7.3.1611 (Core)

3、安装elrepo并升级内核

rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm
yum --enablerepo=elrepo-kernel install kernel-ml -y

正常情况下将输出如下信息:

Transaction Summary
================================================================================
Install  1 Package
Total download size: 39 M
Installed size: 169 M
Downloading packages:
kernel-ml-4.9.0-1.el7.elrepo.x86_64.rpm                    |  39 MB   00:00
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Warning: RPMDB altered outside of yum.
  Installing : kernel-ml-4.9.0-1.el7.elrepo.x86_64                          1/1
  Verifying  : kernel-ml-4.9.0-1.el7.elrepo.x86_64                          1/1
Installed:
  kernel-ml.x86_64 0:4.9.0-1.el7.elrepo
Complete!

4、更新grub文件并重启(reboot后,ssh会断开,稍等一会儿重新连接)

egrep ^menuentry /etc/grub2.cfg | cut -f 2 -d '
grub2-set-default 0
reboot

5、开机后查看内核是否已更换为4.9

uname -r

输出如下内容则表示内核4.9已经启动了(数值大于4.9即可)

4.9.0-1.el7.elrepo.x86_64

CentOS 7.4

导入 elrepo 软件源的 GPG 公钥

rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org

导入 elrepo 软件源

说明:该地址可以自动下载该源的最新的软件列表,无需修改地址。

rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm

下载并安装新的内核

启用软件源并下载安装最新稳定版内核

yum -y --enablerepo=elrepo-kernel install kernel-ml

设定 Grub 默认启动新内核

说明:如果手动修改过 Grub 的配置文件,以下命令可能无法执行成功。请自行修改 Grub 配置文件。

grub2-set-default 0

使用新的内核重启

reboot

检查设置 & 删除旧的内核

查看当前系统的内核版本号

uname -r

如果输出是 4.10 以上的版本,说明安装成功。

4.14.13-1.el7.elrepo.x86_64

删除旧内核

说明:删除旧内核的目的是为了防止 yum 更新旧版内核之后覆盖了 grub 默认启动项

yum -y remove kernel kernel-tools

开启bbr

vim /etc/sysctl.conf

添加如下内容

net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr

加载系统参数(正常情况下会输出我们之前加入的内容)

sysctl -p

验证bbr是否已经开启

a.若

sysctl net.ipv4.tcp_available_congestion_control

返回

net.ipv4.tcp_available_congestion_control = bbr cubic reno

则成功

b.若

lsmod | grep bbr

返回形如如下形式的信息即成功。

tcp_bbr                16384  1
tcp_bbr                20480  0