完美解决 MacOS 下不能 ping Docker 容器的问题 | MacOS 使用 ssh 链接

今天下午从docker hubpullCentOS。跑起来后装了ssh,然后在宿主机上ping不通CentOScontainer…..这是多么囧的事情…

  • 对于docker for mac不能ping容器官网给的解释是
    ….
    对于以上解释通过端口映射可以解决docker for mac连接容器的问题,但是有些情况下是不需要端口的怎么办?以上说法对我毫无卵用。带着问题,Google了下据说有个openVPN可以解决这个问题。
  • 解决问题
    搜了好一阵子,大多都没有详细说明,最后在GitHub上搜到一个叫 docker-mac-network 的项目。嗯,很是牛逼。

项目README大致翻译

使用OpenVPN来搞定。让你从macOS访问docker for mac

Quickstart

访问docker网络:

安装Tunnelblick  这个软件是OpenVPNmacOS的客户端。

  • 运行 docker-compose up 因为该项目需要生成一些keys,所以第一次启动会耗费点时间。
  • 双击生成的 docker-for-mac.ovpn 文件,或者直接在你的终端运行该文件把它添加到Tunnelblick。 该文件会在项目根目录生成。
  • 使用Tunnelblick链接你新添加的docker-for-mac

现在你可以从你的macOS访问doker里面的网络了。

Implementation notes

该配置由两个服务组成,它们都是基于Alpine

openvpn

使用OpenVPN docker镜像 kylemanna/openvpn.

服务端和客户端配置文件都自动的由helpers/run.sh来生成, 该脚本运行在镜像中,只能通过调整该脚本的配置来访问你docker for mac的网络。

该服务使用网络在TCP 1194端口上跑着,这说明它可以在vm上访问所有的docker网络。

只有172.16.0.0/20 私有网络被配置生成器路由到了Docker for Mac。主机上没有设置DNS服务。

镜像OpenVPN的配置在目录 (/etc/openvpn/*)中,对应宿主的文件系统的./config/,这样便于自定义。

proxy

自打有docker for mac开始,宿主机就不能访问容器的网络。我们使用TCP代理。此镜像使用socat将端口13194转发到OpenVPN容器上。

使用过程

  1. 把项目从GitHubClone下来,放到某个文件夹中。
  2. 修改run.sh脚本
#!/bin/shdest=${dest:-docker.ovpn}if [ ! -f "/local/$dest" ]; then
    echo "*** REGENERATING ALL CONFIGS ***"
    set -ex    #rm -rf /etc/openvpn/*
    ovpn_genconfig -u tcp://localhost
    sed -i 's|^push|#push|' /etc/openvpn/openvpn.conf    echo localhost | ovpn_initpki nopass
    easyrsa build-client-full host nopass
    ovpn_getclient host | sed '
        s|localhost 1194|localhost 13194|;
    s|redirect-gateway.*|route 172.17.0.0 255.255.0.0|; # 这里要配置你container的ip和子网掩码
    ' > "/local/$dest"fi# Workaround for https://github.com/wojas/docker-mac-network/issues/6/sbin/iptables -I FORWARD 1 -i tun+ -j ACCEPTexec ovpn_run
  1. 运行docker-compose.yml。打开终端cd到项目的根目录。输入docker-compose up
    运行后自动创建两个容器,一个为代理容器一个为openvpn服务端容器
  2. 查看项目根目录,会发现有生成的docker-for-mac.ovpn文件
    docker-for-mac.ovpn
  3. 编辑docker-for-mac.ovpn文件,这里是个坑,需要加一个comp-lzo yes属性。
client
nobind
dev tun
remote-cert-tls server

remote localhost 13194 tcp<key>-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6AzE2XEmBxBkX
0PajWJQkLOFTb6pgydCrzpV5/9wSL1mgOGg7X2pA080LgGB8GVoSj+hyOdnPc5SQ
P/JKuEqHDeGmNR3mdROXPBJzEheFtpQP+01bmQgTi8aEFllof+M8N6XdZKbWCMIr
Oa6kHFJTM7S5lC7zqZCQ/Pg0yi81EZWdzanCYT/orB90RTvBMa4R8Y/YOFdtKZip
YVPAokNVu/Vb7Lvwmqhu84RBqeJ9BPsAZuFuSLu9l0HsqZZisAzer05aOAld5SgU
6YsaimXLsff+wuOssM2LXohbHdE11bEN286SvOvecDj3/QfYDzLlVMq9OLX3TPep
dQ2WPZ0zAgMBAAECggEAB3NTSEsgApuZKbQL/PTyUhSeHdpuJ5xNyGPo5s8RwIS3
AUzhF+e1eM1C/D/zHWVijzXGaLTafY2ymKiHCukgyxIKRL8B6JYt57PXRVanLIro
mU9GhPG3OhkyJV5DzIS61FGiSiDa8d298T9JOHeN8Jk0lu5Rhx72lGgdhPfINkbh
i+fcPXTuPpeNKxwcOcV7MQdJOCir1gVwRaHoh3b/1/hBfllUMla0IcVDrOByq5j9
NFvFXp3cIwHtpxXi9HIXjYg50tIpKsZVA1My1X7zSgw4Uy3DkYOCtGfTd3ZPkAZg
M49WrkXzwfS4xCGlptYcXKpMuRK+4CGn3DY62/TuwQKBgQDfTcdCSEjp9XBpp15v
qlfWiHCm2w9qqQj30Bu78vflvJRLHEXgAK5jn5i/oKBDn9P65XT5iMG73IilBtDr
ZqLHxf6bii+3giNk1r7Ij8dABea2DZoDAiXw7gBYeWrShwFoEK1sAOQLpXfKyahg
D5Ri73MzWB6X8NgonTSWgMLCEwKBgQDVP5nxiit6w15ztlisHO0OyI4NOXCz8JJP
/psbCLafn/jO9MVUtD+CGzB/LaenPyN2wgFwS2rW1aP0eQ4CblhdBsR2DPyFQn+Q
kFvlfECViPyqctuQ3Vg5whUnd2uB6s/41Kf5SCesDmc+moq0agCYfcPPC26T8YjN
TitLqugcYQKBgQCLHO1Rwa6K8jjB2V7fugNWx1FG4ZnNHNlVaPSeNlNxb/YChO6T
ClmZ/scuOmcdOejZmTEyc5wd6NnH1WM6A4rNYe+n/oKTlCNwosfgMpIytHpyWC7m
SORSIDNe6uU9mpWpuxoO+s8W4lKqps6aaZpLuFjQV8lXZteDFcy5JiYuuQKBgQCL
JfFB1zL/7DPZtYau6EEXgG6Q2oZcJAKVCEIVpd3k0vH7uWR6HRPDxhIjKptXWq+9
cmKV7+BLRySxBbzKgU5PhXb0wQyVuAqdPlV4rVdHPBgC8Oes44IKTkaXdilEoQAM
Eld5Jkgc0Vk1VIplpzW0S3xVwdPp3ZWywesmeOL0gQKBgHVjNnrAM6KnmtcC2ESt
JanCQtU3IHtBE9ReCGBEZ9lR0jCqvFbivv3CNhOr5O+S1V3kgIKQPB76+zmYl/0C
RYwauaLkzOEbi6UunmNT39Mqdcr7PyoaPp2Wk9PD0tM2/ehNu6MLh41MX1w1Fd46
O77pYRHWuGOfZTPdshxOfPgf
-----END PRIVATE KEY-----</key><cert>-----BEGIN CERTIFICATE-----
MIIDQzCCAiugAwIBAgIQMH0suH0s9/Tt3dojdz/UTDANBgkqhkiG9w0BAQsFADAU
MRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMTgwOTE2MTEwMTA3WhcNMjgwOTEzMTEw
MTA3WjAPMQ0wCwYDVQQDDARob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAugMxNlxJgcQZF9D2o1iUJCzhU2+qYMnQq86Vef/cEi9ZoDhoO19qQNPN
C4BgfBlaEo/ocjnZz3OUkD/ySrhKhw3hpjUd5nUTlzwScxIXhbaUD/tNW5kIE4vG
hBZZaH/jPDel3WSm1gjCKzmupBxSUzO0uZQu86mQkPz4NMovNRGVnc2pwmE/6Kwf
dEU7wTGuEfGP2DhXbSmYqWFTwKJDVbv1W+y78JqobvOEQanifQT7AGbhbki7vZdB
7KmWYrAM3q9OWjgJXeUoFOmLGoply7H3/sLjrLDNi16IWx3RNdWxDdvOkrzr3nA4
9/0H2A8y5VTKvTi190z3qXUNlj2dMwIDAQABo4GVMIGSMAkGA1UdEwQCMAAwHQYD
VR0OBBYEFA3QP+B02XYogxyjbFYYGBfhHqj5MEQGA1UdIwQ9MDuAFB8KyCaZfFiQ
aSxHMmMj00QD1kqioRikFjAUMRIwEAYDVQQDDAlsb2NhbGhvc3SCCQCGOlhuj5Vr
KzATBgNVHSUEDDAKBggrBgEFBQcDAjALBgNVHQ8EBAMCB4AwDQYJKoZIhvcNAQEL
BQADggEBALhv25L/dmTOszEwYn0pDtdkTwzIsCoD5tx1bQutlkvWHjG65md32Mfx
B60Sqo5f/Rc7ZwB4+4kKW/3gt0KaqLPbyWGLeH9yJNu/6VDMwvHJC07YxpzhLyHL
taq9VQDWS5FQUkC9oYsEZzxeaadcCQpNp1fdx4586fVYGJ2/dGDeqE52ZqMDNRSF
I1DurZlaKVsbkFdrm0UAlqBWZDDHlSImkd+uKwXwqQdnkxiPzCoW0dpMfw+7DvuV
Muq3759LtYmZbDFh8dUDRZ830WAwGzv9yhPpOg58G0dNyMTQJo59/p2Ea4NHHlBv
TqfXQM1at9leSpR5ZFkqDbIbYoxUuxk=
-----END CERTIFICATE-----</cert><ca>-----BEGIN CERTIFICATE-----
MIIDLzCCAhegAwIBAgIJAIY6WG6PlWsrMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
BAMMCWxvY2FsaG9zdDAeFw0xODA5MTYxMTAwMDhaFw0yODA5MTMxMTAwMDhaMBQx
EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAOvgs+KzBgg5Bz+dALH8uFsfBk2QklaeeK0O5H63qjXqujICy/MGxXAiqdo6
UqLTca9psvhhR0QeXEnZ2daBrw3XuGZ/nw9lmJZ/S/MOfJWTerYaj1ZttPjnlOFS
muWKouNam33mJF2vkGbYUoEdb3qqEoZTd3DBEnRAKLzE0v7evAbv7XW7kh+w7W+D
4RsalXLaUqquP/BYcOAWB733ZBIjpmEglA0u2ZtF9tXK/HT2d3dkxbrdRrF2WLwg
fcE53mb8/ayf3qu7nRj0NaqqYb8R9R5fcQnzMCi5ZZ/Dudbcc5/6NEu5G1PTCyTs
Z9o/FZO1KF3q7TR0FzYMkTMGF20CAwEAAaOBgzCBgDAdBgNVHQ4EFgQUHwrIJpl8
WJBpLEcyYyPTRAPWSqIwRAYDVR0jBD0wO4AUHwrIJpl8WJBpLEcyYyPTRAPWSqKh
GKQWMBQxEjAQBgNVBAMMCWxvY2FsaG9zdIIJAIY6WG6PlWsrMAwGA1UdEwQFMAMB
Af8wCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IBAQC2APlsYTKtque4IF/C
nFRcY5J5Btj7SuyLUjkVp6HxengmwI5pDeubMvv9EeVZ0lAzobQ988P4vGkNGRde
QKGNkwjpsvNj+kyYCWhke8eYuxOXRZCNwp19kJjxhCN/i/adLhff0cXDfrMbX0Zv
W5WNgbrPBlk3TEn5XRHR/yp+UFNwL4e2ZovYFy3hBAuRfIdUF1wdZIdrjsHEMGBe
vHfKSebhvyPgAGAi91vU14M99xERqrvM09pMfMHF9xYhiiQkcZtVzaauZE0d3m+o
VK4HQZg2UjxfLUo5kU1Ou0E3cYHkDx3eEF/X/F5SyoWPTa2FfrK0j5/CE32vhlck
szzU
-----END CERTIFICATE-----</ca>key-direction 1<tls-auth>#
# 2048 bit OpenVPN static key
#
-----BEGIN OpenVPN Static key V1-----
e33646344fdba3b929ea6e07f1558bdb
080136f61bd0a0611bb1a952802d47b2
eb14d5aae9d25c4ab3614d495876e815
3ce7c2f9f67dda2183bec7928dfb792f
003cb36d5a57fd9e0df23c2fd4c7ae05
6a8b1ecb6c3697a78d3c3a67c16b98ad
167258c57aa3dd674c5a735d3df4b5ab
1610a676bd97beaadab10fd82f82c9e7
2b1efe35f96ff237b366e057d20b3a18
cdc095510df43bcfa638853efde91a67
93507615eceb77f2de619d614ca64901
2273a9074153b531dde8ac10f6d2cdd9
f73e8cba9548f2dc853b8c4178beed68
5d15b81da6121f7dc3c0f25c7008955d
5f9c6264d47bac43f6983ad8af8aba5b
8fa4ac4611109613e1a9d876620bdd83
-----END OpenVPN Static key V1-----</tls-auth>comp-lzo yes
route 172.17.0.0 255.255.0.0
  1. 把该文件添加到Tunnelblick,然后连接该网络。
    连接后的样子
  2. 测试
    docker container centos 网络

宿主机,完美搞定



作者:阿波罗程序猿

Python慢,为啥还有大公司用?

Instagram 的视频可以给我们哪些启示呢?

  • Python + Django 的组合完全可以负载用户数以 10 亿记的服务,如果你正准备开始一个项目,放心使用 Python 吧!
  • 完善的单元测试对于复杂项目是非常有必要的。如果没有那『成千上万的单元测试』。很难想象 Instagram 的迁移项目可以成功进行下去。
  • 开发者和同事也是你的产品用户,利用好他们。用他们为你的新特性发布前多一道测试。
  • 完全基于主分支的开发流程,可以给你更快的迭代速度。前提是拥有完善的单元测试和持续部署流程。
  • Python 3 是大势所趋,如果你正准备开始一个新项目,无需迟疑,拥抱 Python 3 吧!

作者:我爱学python
链接:https://www.jianshu.com/p/e18e01ad7ad9
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

composer配置使用代理

composer加速,使用http代理,执行:
export http_proxy=”http://127.0.0.1:1087″
export https_proxy=”http://127.0.0.1:1087″

取消代理:
unset http_proxy

laravel 使用workerman提供http服务

  • 背景

公司项目使用的是laravel框架,开发完后压测一直不过,期间开启过opcache扩展加速(不属于本篇内容,不在此赘述),后决定采用workerman或swoole加速laravel应用,本篇以workerman为例。

首先大家应该知道laravel每次收到请求都会把框架核心代码加载一遍,使用workerman提升性能的关键是把框架核心代码缓存起来,这样就不需要每次重新加载了,以此来提升性能(swoole同理)

  • composer安装workerman
#更改composer源
composer config -g repo.packagist composer https://packagist.phpcomposer.com
#下载workerman包
composer require workerman/workerman
  • 创建启动命令
  1. 生成 WorkermanCommand 文件
php artisan make:command WorkermanCommand

    执行以上命令行会在 app/Console/Commands/ 目录下生成 WorkermanCommand.php 文件,对文件做如下修改。

<?php

namespace App\Console\Commands;

use Workerman\Worker;
use Illuminate\Console\Command;

class WorkermanCommand extends Command
{
    private $server;
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'wk {action}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Start a Workerman server.';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        global $argv;
        $arg = $this->argument('action');
        $argv[1] = $argv[2];
        $argv[2] = isset($argv[3]) ? "-{$argv[3]}" : '';
        switch ($arg) {
            case 'start':
                $this->start();
                break;
            case 'stop':
                break;
            case 'restart':
                break;
            case 'reload':
                break;
            case 'status':
                break;
            case 'connections':
                break;
        }
    }

    private function start()
    {
        // 创建一个Worker监听20002端口,不使用任何应用层协议
        $this->server = new Worker("http://0.0.0.0:1234");
        // 启动4个进程对外提供服务
        $this->server->count = 4;
        $handler = \App::make('handlers\WorkermanHandler');
        // 连接时回调
        $this->server->onConnect = [$handler, 'onConnect'];
        // 收到客户端信息时回调
        $this->server->onMessage = [$handler, 'onMessage'];
        // 进程启动后的回调
        $this->server->onWorkerStart = [$handler, 'onWorkerStart'];
        // 断开时触发的回调
        $this->server->onClose = [$handler, 'onClose'];
        // 运行worker
        Worker::runAll();
    }
}

在这个自定义命令还引用了其他的类文件,如

$handler = \App::make('handlers\WorkermanHandler');

所以,需要创建一个 WorkermanHandler.php 的文件来处理对应的操作

2、创建 WorkermanHandler.php

创建 app/handlers/WorkermanHandler.php

<?php

namespace handlers;


class WorkermanHandler
{
    public function onWorkerStart($worker)
    {
        //加载index文件的内容
        require __DIR__ . '/../../vendor/autoload.php';
        require_once __DIR__ . '/../../bootstrap/app.php';
    }

    // 处理客户端连接
    public function onConnect($connection)
    {
        echo "new connection from ip " . $connection->getRemoteIp() . "\n";
    }

    // 处理客户端消息
    public function onMessage($connection, $data)
    {
        // 向客户端发送hello $data
        //server信息
        if (isset($data->server)) {
            foreach ($data->server as $k => $v) {
                $_SERVER[strtoupper($k)] = $v;
            }
        }

        //header头信息
        if (isset($data->header)) {
            foreach ($data->header as $k => $v) {
                $_SERVER[strtoupper($k)] = $v;
            }
        }

        //get请求
        if (isset($data->get)) {
            foreach ($data->get as $k => $v) {
                $_GET[$k] = $v;
            }
        }

        //post请求
        if (isset($data->post)) {
            foreach ($data->post as $k => $v) {
                $_POST[$k] = $v;
            }
        }

        //文件请求
        if (isset($data->files)) {
            foreach ($data->files as $k => $v) {
                $_FILES[$k] = $v;
            }
        }

        //cookies请求
        if (isset($data->cookie)) {
            foreach ($data->cookie as $k => $v) {
                $_COOKIE[$k] = $v;
            }
        }

        ob_start();//启用缓存区

        //加载laravel请求核心模块
        $kernel = app()->make(\Illuminate\Contracts\Http\Kernel::class);
        $laravelResponse = $kernel->handle(
            $request = \Illuminate\Http\Request::capture()
        );
        $laravelResponse->send();
        $kernel->terminate($request, $laravelResponse);

        $res = ob_get_contents();//获取缓存区的内容
        ob_end_clean();//清除缓存区

        //输出缓存区域的内容
        $connection->send($res);
    }

    // 处理客户端断开
    public function onClose($connection)
    {
        echo "connection closed from ip {$connection->getRemoteIp()}\n";
    }
}

3.使用composer自动加载

        "classmap": [
            "app/Handlers"
        ],

执行

composer dump-autoload -o

至此基本配置写完了,下边试试启动一下

php artisan wk start
----------------------------------------- WORKERMAN -----------------------------------------
Workerman version:3.5.19          PHP version:7.2.11
------------------------------------------ WORKERS ------------------------------------------
proto   user            worker          listen                 processes    status
tcp     xuce            none            http://0.0.0.0:1234    4             [OK]
---------------------------------------------------------------------------------------------

说明启动成功了!!!

linux下postfix配置smtp服务

系统一般都自带了postfix,保险起见,安装下

yum -y install postfix

安装sasldb、saslauthd

#提供smtp的虚拟账户和密码服务 sasldb2包含在saslauthd当中yum -y install cyrus-sasl cyrus-sasl-lib cyrus-sasl-plain  cyrus-sasl-devel#当前mta查看alternatives --display mta#设置mtaalternatives --set mta /usr/sbin/sendmail.postfix#再次查看mtaalternatives --display mta#输出结果最后一行会有类似如下的提示:mta即设置完毕#Current `best' version is /usr/sbin/sendmail.postfix.

postfix开机启动设置,因为采用sasldb2提供postfix的smtp账户和密码,无需saslauthd服务运行,故而saslauthd服务不用启动—看吧,使用sasldb2还减少资源占用:

systemctl enable postfix

postfix配置文件在/etc/postfix目录下,主要修改的配置文件为:/etc/postfix/main.cf,配置说明详见代码段:

vi /etc/postfix/main.cf #vi编辑postfix配置文件#找到如下配置项酌情修改#######postfix主机名,修改成你的域名 此项需要添加A记录并指向postfix所在主机公网IPmyhostname = mail.jjonline.com.cn#域名mydomain = jjonline.com.cn#本机postfix的邮箱域名后最 此项默认值使用myhostname#此处使用了前项mydomain 也就是说本机postfix邮箱后缀为:@jjonline.com.cnmyorigin = $mydomain#指定postfix系统监听的网络接口 此处必须是localhost或127.0.0.1或内网ip#若注释或填入公网ip 服务器的25端口将对公网开放#默认值为all 即监听所有网络接口inet_interfaces = all#网络协议 这里ipv4即可inet_protocols = ipv4#指定postfix接收邮件时收件人的域名,换句话说,也就是你的postfix系统要接收什么样的邮件。#此项配置中$myhostname表示postfix接受@$myhostname为后缀的邮箱的邮件 逗号分割支持指多项#此项默认值使用myhostnamemydestination = $mydomain, localhost.$mydomain, localhost#此项制定接收邮件的规则 可以是hash文件 此项对本次配置无意义 可以直接注释local_recipient_maps =#指定你所在的网络的网络地址mynetworks = 42.121.107.189, 10.200.9.xxx, 127.0.0.1#请依据实际情况修改#指定MUA通过smtp连接postfix时返回的header头信息#原始配置附带有postfix版本号 去掉即可,此项酌情处理,可以先不管smtpd_banner = JJonline.Cn ESMTP Server下面的配置默认是没有的,需要在配置文件最后加上#SMTP Config#指定postfix兼容MUA使用不规则的smtp协议--主要针对老版本的outlook 此项对于本次配置无意义broken_sasl_auth_clients = yes#指定可以向postfix发起SMTP连接的客户端的主机名或ip地址smtpd_client_restrictions = permit_sasl_authenticated#此处permit_sasl_authenticated意思是允许通过sasl认证(也就是smtp链接时通过了账号、密码效验的用户)的所有用户smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, #发件人在执行RCPT TO命令时提供的地址进行限制规则 此处照搬复制即可reject_unauth_destination#指定postfix使用sasl验证 通俗的将就是启用smtp并要求进行账号、密码效验smtpd_sasl_auth_enable = yes#指定SMTP认证的本地域名 本次配置可以使用 smtpd_sasl_local_domain = '' 或干脆注释掉 默认为空smtpd_sasl_local_domain = $mydomain#取消smtp的匿名登录 此项默认值为noanonymous smtp若能匿名登录危害非常大 此项请务必指定为noanonymoussmtpd_sasl_security_options = noanonymous#指定通过postfix发送邮件的体积大小 此处表示5Mmessage_size_limit = 5242880######

查看postfix配置文件的所有配置项:

postconf #不带任何命令参数 即可输出所有postfix配置项以及默认值

五、sasldb2建立smtp用户和密码

某种意义上来讲:smtp的账户密码建立也就是建立邮箱账户(类似jjonline@jjonline.cn的邮箱地址)。

#配置postfix启用sasldb2作为smtp的账号秘密效验方式#编辑通过sasl启用smtp账号密码效验的配置vi /etc/sasl2/smtpd.conf #vi写入或编辑内容如下:#####pwcheck_method: auxpropauxprop_plugin: sasldbmech_list: plain login CRAM-MD5 DIGEST-MD5######这里需要注意的是:这个配置文件的位置是64位机器上的,32位机器应该在:/usr/lib/sasl2/smtpd.conf#创建smtp账号saslpasswd2 -c -u `postconf -h mydomain` test #回车会要求输入密码,连续两次#表示创建test@$mydomain的邮箱账号(也是smtp的账号)和密码#本例就是创建test@jjonline.com.cn账号和密码#此处注意的是smtp登录用的账号并不是单纯的用户名 而是整个邮箱地址字符串#假设此处设置的smtp账号test@jjonline.com.cn密码为test123 下方测试时要用到#查看sasldb2的用户和密码sasldblistusers2#此命令进用户查看sasldb的用户情况#此命令回车后会输出诸如这样的内容:test@jjonline.com.cn: userPassword#每次添加smtp用户完毕之后需重启postfix或reload

测试postfix配置文件并启动postfix

#没有问题的话会返回着色[ok]字样#启动postfixsystemctl restart postfix #更改sasldb2数据的权限,让postfix可以读取chmod 755 /etc/sasldb2

六、测试smtp

http://tool.chinaz.com/Tools/Base64.aspx 这个网站可以直接base64加密

telnet测试时需要用到,账号和密码都需要添加加密的字符串

我是直接在windows上操作的

telnet 192.168.2.182 25#输入auth login 进行登录操作auth login334 VXN1cm5hbWU6 #会显示出这个#输入账号为base64的加密字符串dGVzdEBqdW1wc2VydmVyLmNvbQ==#输入密码为base64的加密字符串0dGVzdDEyMw==235 2.7.0 Authentication seccessful  #认证成功后出来的东西

如果失败先查看日志 /var/log/maillog 大概知道是哪步没操作

自此,自建postfix并启用smtp和smtp的虚拟账号完成;

七、域名解析记录设置

postfix配置完毕,想要通过这台postfis邮件服务器发送的邮件被其他邮箱服务商所接受,还需要做A记录、txt记录还mx记录,请适配你自己的域名和ip地址。

postfix用客户端外发游戏出现Relay access denied,拒绝发信

解决办法:

编辑/etc/postfix/main.cn,找到

smtpd_recipient_restrictions=permit_sasl_authenticated, 
    permit_mynetworks, 
    reject_unauth_destination,

修改成

smtpd_recipient_restrictions = permit_sasl_authenticated, 
        permit_mynetworks, 
        reject_unauth_destination,
	reject_non_fqdn_sender,
        reject_non_fqdn_recipient, 
        reject_unknown_recipient_domain

MongoDB 分片的原理、搭建、应用

原文:http://blog.51cto.com/13643643/2148825

什么是分片

高数据量和吞吐量的数据库应用会对单机的性能造成较大压力,大的查询量会将单机的CPU耗尽,大的数据量对单机的存储压力较大,最终会耗尽系统的内存而将压力转移到磁盘IO上。
MongoDB分片是使用多个服务器存储数据的方法,以支持巨大的数据存储和对数据进行操作。分片技术可以满足MongoDB数据量大量增长的需求,当一台MongoDB服务器不足以存储海量数据或者不足以提供可接受的读写吞吐量时,我们就可以通过在多台服务器上分割数据,使得数据库系统能存储和处理更多的数据。

MongoDB分片优势

分片为应对高吞吐量与大数据量提够了方法

  • 使用分片减少了每个分片需要处理的请求数,因此,通过水平扩展,群集可以提高自己的存储容量。比如,当插入一条数据时,应用只需要访问存储这条数据的分片。
  • 使用分片减少了每个分片村存储的数据
    分片的优势在于提供类似线性增长的架构,提高数据可用性,提高大型数据库查询服务器的性能。当MongoDB单点数据库服务器存储成为瓶颈、单点数据库服务器的性能成为瓶颈或需要部署大型应用以充分利用内存时,可以使用分片技术。

    MongoDB分片群集的组成

  • Shard:分片服务器,用于存储实际的数据块,实际生产环境中一个shard server 角色可以由几台服务器组成一个Peplica Set 承担,防止主机单点故障。
  • Config Server:配置服务器,存储了整个分片群集的配置信息,其中包括chunk信息。
  • Routers:前端路由,客户端由此接入,且让整个群集看上去像单一数据库,前端应用可以透明使用。

环境准备

  • 系统版本:CenTos 7
  • 软件版本:MongoDB4.0
  • 关闭防火墙及selinux
    systemctl stop firewalld.service
    setenforce 0
IP:172.16.10.26 IP:172.16.10.27 IP:172.16.10.29
mongos(27017) mongos(27017) mongos(27017)
config(30000) config(30000) config(30000)
shard1主节点(40001) shard1副节点(40001) shard1仲裁节点(40001)
shard2仲裁节点(40002) shard2主节点(40002) shard2副节点(40002)
shard1副节点(40003) shard1仲裁节点(40003) shard1主节点(40003)

部署MongoDB分片群集

群集部署的搭建思路,利用三台服务器,分别安装mongodb数据库,每台服务器创建五个实例(mongos、configs、shard1、shard2、shard3)。三台不同的服务器上的相同名称的实例,创建为一个复制集,分别包括主节点,副节点,仲裁节点。mongos不需创建复制集,config不需指定主副节点及仲裁节点,但是要创建复制集。三台服务器的操作步骤略有差别,但是大多是都是重复操作,步骤完全一致。

安装MongoDB数据库

安装支持软件和mongodb

yum install openssl-devel -y
tar zxf mongodb-linux-x86_64-rhel70-4.0.0.tgz -C /usr/local
mv /usr/local/mongodb-linux-x86_64-rhel70-4.0.0 /usr/local/mongodb  //解压即完成安装

创建数据存储目录和日志存储目录

路由服务器不存储数据,因此就不需要创建数据存储目录,只需创建config、shard1、shaed2、shard3即可,日志文件创建完成之后还需要给予权限。

mkdir -p /data/mongodb/logs/
mkdir /etc/mongodb/
mkdir /data/mongodb/config/
mkdir /data/mongodb/shard{1,2,3}
touch /data/mongodb/logs/shard{1,2,3}.log
touch /data/mongodb/logs/mongos.log
touch /data/mongodb/logs/config.log
chmod 777 /data/mongodb/logs/*.log

创建管理用户,修改目录权限

useradd -M -u 8000 -s /sbin/nologin mongo
chown -R mongo.mongo /usr/local/mongodb
chown -R mongo.mongo /data/mongodb

设置环境变量

echo "PATH=/usr/local/mongodb/bin:$PATH" >> /etc/profile
source /etc/profile

系统内存优化

ulimit -n 25000
ulimit -u 25000
sysctl -w vm.zone_reclaim_mode=0
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag  //*注意*这些优化都是临时的,重启失效

部署配置服务器

创建配置文件

#vim /etc/mongodb/config.conf
pidfilepath = /data/mongodb//logs/config.pid           //pid文件位置
dbpath = /data/mongodb/config/                             //数据文件存放位置
logpath = /data/mongodb//logs/config.log               //日志文件位置
logappend = true                 
bind_ip = 0.0.0.0                                                     //监听地址
port = 30000                                                           //端口号
fork = true 
replSet=configs                                                      //复制集名称
configsvr = true
maxConns=20000                                                  //最大连接数

将配置文件发送到其他服务器

scp /etc/mongodb/config.conf root@172.16.10.27:/etc/mongodb/
scp /etc/mongodb/config.conf root@172.16.10.29:/etc/mongodb/

MongoDB(4.0)分片——大数据的处理之道

启动config实例

mongod -f /etc/mongodb/config.conf  //三台服务器操作一致

配置复制集(任一台操作即可)

mongo --port 30000                    //建议三台服务器都进入数据库,方便查看角色变更
config={_id:"configs",members:[{_id:0,host:"172.16.10.26:30000"},{_id:1,host:"172.16.10.27:30000"},{_id:2,host:"172.16.10.29:30000"}]}    //创建复制集
rs.initiate(config)                //初始化复制集

MongoDB(4.0)分片——大数据的处理之道
MongoDB(4.0)分片——大数据的处理之道

部署shard1分片服务器

创建配置文件

#vim /etc/mongodb/shard1.conf
pidfilepath = /data/mongodb//logs/shard1.pid
dbpath = /data/mongodb/shard1/
logpath = /data/mongodb//logs/shard1.log
logappend = true
journal = true
quiet = true
bind_ip = 0.0.0.0
port = 40001
fork = true
replSet=shard1
shardsvr = true
maxConns=20000

将配置文件发送到其他服务器

scp /etc/mongodb/shard1.conf root@172.16.10.27:/etc/mongodb/
scp /etc/mongodb/shard1.conf root@172.16.10.29:/etc/mongodb/

启动shard1实例

mongod -f /etc/mongodb/shard1.conf  //三台服务器操作一致

配置shard1复制集

在shard分片服务器的创建中,需要注意的点是,不是在任一台服务器上创建都能成功的,如果选择在预先设置为仲裁节点的服务器上创建复制集会报错。以shard1分片服务器为例,可以在172.16.10.26和172.16.10.27服务器上创建复制集,在172.16.10.29上创建则会失败,因为在复制集创建之前,172.16.10.29已经被设置为仲裁节点。
MongoDB(4.0)分片——大数据的处理之道

mongo --port 40001    //建议三台服务器都进入数据库,方便查看角色变更
use admin
config={_id:"shard1",members:[{_id:0,host:"172.16.10.26:40001",priority:2},{_id:1,host:"172.16.10.27:40001",priority:1},{_id:2,host:"172.16.10.29:40001",arbiterOnly:true}]}
rs.initiate(config)

部署shard2分片服务器

创建配置文件

#vim /etc/mongodb/shard2.conf
pidfilepath = /data/mongodb//logs/shard2.pid
dbpath = /data/mongodb/shard2/
logpath = /data/mongodb//logs/shard2.log
logappend = true
journal = true
quiet = true
bind_ip = 0.0.0.0
port = 40002
fork = true
replSet=shard2
shardsvr = true
maxConns=20000

将配置文件发送到其他服务器

scp /etc/mongodb/shard2.conf root@172.16.10.27:/etc/mongodb/
scp /etc/mongodb/shard2.conf root@172.16.10.29:/etc/mongodb/

启动shard2实例

mongod -f /etc/mongodb/shard2.conf  //三台服务器操作一致

配置shard复制集(非仲裁节点服务器)

mongo --port 40002    //建议三台服务器都进入数据库,方便查看角色变更
use admin
config={_id:"shard2",members:[{_id:0,host:"172.16.10.26:40002",arbiterOnly:true},{_id:1,host:"172.16.10.27:40002",priority:2},{_id:2,host:"172.16.10.29:40002",priority:1}]}
rs.initiate(config)

部署shard3分片服务器

创建配置文件

#vim /etc/mongodb/shard3.conf
pidfilepath = /data/mongodb//logs/shard3.pid
dbpath = /data/mongodb/shard3/
logpath = /data/mongodb//logs/shard3.log
logappend = true
journal = true
quiet = true
bind_ip = 0.0.0.0
port = 40003
fork = true
replSet=shard3
shardsvr = true
maxConns=20000

将配置文件发送到其他服务器

scp /etc/mongodb/shard3.conf root@172.16.10.27:/etc/mongodb/
scp /etc/mongodb/shard3.conf root@172.16.10.29:/etc/mongodb/

启动shard3实例

mongod -f /etc/mongodb/shard3.conf  //三台服务器操作一致

配置shard复制集(非仲裁节点服务器)

mongo --port 40003    //建议三台服务器都进入数据库,方便查看角色变更
use admin
config={_id:"shard3",members:[{_id:0,host:"172.16.10.26:40003",priority:1},{_id:1,host:"172.16.10.27:40003",arbiterOnly:true},{_id:2,host:"172.16.10.29:40003",priority:2}]}
rs.initiate(config);

部署路由服务器

创建配置文件

pidfilepath = /data/mongodb/logs/mongos.pid
logpath=/data/mongodb/logs/mongos.log
logappend = true
bind_ip = 0.0.0.0
port = 27017
fork = true
configdb = configs/172.16.10.26:30000,172.16.10.27:30000,172.16.10.29:30000
maxConns=20000

将配置文件发送到其他服务器

scp /etc/mongodb/mongos.conf root@172.16.10.27:/etc/mongodb/
scp /etc/mongodb/mongos.conf root@172.16.10.29:/etc/mongodb/

启动mongos实例

mongos -f /etc/mongodb/mongos.conf  //三台服务器操作一致*注意*这里是“mongos”而非“mongod”

启用分片功能

mongo    //因为默认端口即是27017,所以此处不接端口号
mongos> use admin
mongos> sh.addShard("shard1/172.16.10.26:40001,172.16.10.27:40001,172.16.10.29:40001")
mongos> sh.addShard("shard2/172.16.10.26:40002,172.16.10.27:40002,172.16.10.29:40002")
mongos> sh.status()           //查看群集状态
//此处先添加两各分片服务器,还有一个,待会添加

MongoDB(4.0)分片——大数据的处理之道

测试服务器分片功能

设置分片chunk大小

mongos> use config
switched to db config
mongos> db.settings.save({"_id":"chunksize","value":1})   //设置块大小为1M是方便实验,不然就需要插入海量数据
WriteResult({ "nMatched" : 0, "nUpserted" : 1, "nModified" : 0, "_id" : "chunksize" })

模拟写入数据

mongos> use python
switched to db python
mongos> show collections
mongos> for(i=1;i<=50000;i++){db.user.insert({"id":i,"name":"jack"+i})}
//在python库的user表中循环写入五万条数据
WriteResult({ "nInserted" : 1 })

启用数据库分片

mongos>sh.enableSharding("python")
//数据库分片就有针对性,可以自定义需要分片的库或者表,毕竟也不是所有数据都是需要分片操作的

MongoDB(4.0)分片——大数据的处理之道

为表创建的索引

创建索引的规则是不能一致性太高,要具有唯一性,例如序号,比如性别这一类重复性太高的就不适合做索引

mongos> db.user.createIndex({"id":1})   //以”id“为索引

MongoDB(4.0)分片——大数据的处理之道

启用表分片

mongos> sh.shardCollection("python.user",{"id":1})

MongoDB(4.0)分片——大数据的处理之道

查看分片情况

mongos> sh.status()
--- Sharding Status --- 
            ···省略内容
  shards:
        {  "_id" : "shard1",  "host" : "shard1/172.16.10.26:40001,172.16.10.27:40001",  "state" : 1 }
        {  "_id" : "shard2",  "host" : "shard2/172.16.10.27:40002,172.16.10.29:40002",  "state" : 1 }
            ···省略内容
                        chunks:
                                shard1  3
                                shard2  3
                        { "id" : { "$minKey" : 1 } } -->> { "id" : 9893 } on : shard1 Timestamp(2, 0) 
                        { "id" : 9893 } -->> { "id" : 19786 } on : shard1 Timestamp(3, 0) 
                        { "id" : 19786 } -->> { "id" : 29679 } on : shard1 Timestamp(4, 0) 
                        { "id" : 29679 } -->> { "id" : 39572 } on : shard2 Timestamp(4, 1) 
                        { "id" : 39572 } -->> { "id" : 49465 } on : shard2 Timestamp(1, 4) 
                        { "id" : 49465 } -->> { "id" : { "$maxKey" : 1 } } on : shard2 Timestamp(1, 5) 

手动添加分片服务器,查看分片情况是否发生变化

mongos> use admin
switched to db admin
mongos> sh.addShard("172.16.10.26:40003,172.16.10.27:40003,172.16.10.29:40003")
mongos> sh.status()
--- Sharding Status --- 
           ···省略内容
  shards:
        {  "_id" : "shard1",  "host" : "shard1/172.16.10.26:40001,172.16.10.27:40001",  "state" : 1 }
        {  "_id" : "shard2",  "host" : "shard2/172.16.10.27:40002,172.16.10.29:40002",  "state" : 1 }
        {  "_id" : "shard3",  "host" : "shard3/172.16.10.26:40003,172.16.10.29:40003",  "state" : 1 }
           ···省略内容
                        chunks:
                                shard1  2
                                shard2  2
                                shard3  2
                        { "id" : { "$minKey" : 1 } } -->> { "id" : 9893 } on : shard3 Timestamp(6, 0) 
                        { "id" : 9893 } -->> { "id" : 19786 } on : shard1 Timestamp(6, 1) 
                        { "id" : 19786 } -->> { "id" : 29679 } on : shard1 Timestamp(4, 0) 
                        { "id" : 29679 } -->> { "id" : 39572 } on : shard3 Timestamp(5, 0) 
                        { "id" : 39572 } -->> { "id" : 49465 } on : shard2 Timestamp(5, 1) 
                        { "id" : 49465 } -->> { "id" : { "$maxKey" : 1 } } on : shard2 Timestamp(1, 5) 

服务器又对数据进行重新分片,当你再次移除一个分片服务器,此时又会对数据再次进行分片处理,MongoDB对数据的处理非常灵活

PHP Prime Number Function

//快速计算某个值以内的质数
function getPrimeNumbers($n)
{
    $sieve = [];
    for($i = 1; $i <= $n; $i++) {
        $sieve[$i] = $i;
    }

    $i =2;
    while($i * $i <= $n) {
        if(isset($sieve[$i])) {
            $k = $i;
            while ($k * $i <= $n) {
                unset($sieve[$k * $i]);
                $k++;
            }
        }
        $i++;
    }
    return $sieve;
}

php 抽奖概率算法

/* 
 * 不同概率的抽奖原理就是把0到*(比重总数)的区间分块
 * 分块的依据是物品占整个的比重,再根据随机数种子来产生0-* 中的某个数
 * 判断这个数是落在哪个区间上,区间对应的就是抽到的那个物品。
 * 随机数理论上是概率均等的,那么相应的区间所含数的多少就体现了抽奖物品概率的不同。
 */  


function get_rand($proArr)
{
$result = array();
foreach ($proArr as $key => $val) { 
    $arr[$key] = $val['v']; 
}  
$proSum = array_sum($arr);      // 计算总权重
$randNum = mt_rand(1, $proSum);
$d1 = 0;
$d2 = 0;
for ($i=0; $i < count($arr); $i++)
{
    $d2 += $arr[$i];
    if($i==0)
    {
        $d1 = 0;
    }
    else
    {
        $d1 += $arr[$i-1];
    }
    if($randNum >= $d1 && $randNum <= $d2)
    {
        $result = $proArr[$i];
        break; // 注意这里,当我们已经匹配到奖品时,就应该直接退出循环
    }
}
unset ($arr); 
return $result;


}

mysql中字符和数字在执行sql时进行类型转换

转自:http://blog.csdn.net/likunlun1234/article/details/41045299

https://www.cnblogs.com/micrari/p/6358652.html

select * from v_samp_register where is_end=1;
select * from v_samp_register where is_end=’1′;
is_end是int型,数据库中is_end是1或者0,上面两条语句执行结果怎么就一致了呢???

因为mysql不确定是哪个版本后,执行sql时,会按where条件的类型进行类型自动转换————感觉误导人

Mysql中前边有0的数据,0会被舍去的问题

最近由于项目的需求,需要频繁地拉取不同数据库中的数据,拉取数据的过程中,各种问题,十分悲催,真所谓,一个疏忽,你就要被推倒重来…

在经历了无数次被推倒又站起来,然后又被推倒的艰苦奋斗历程之后,终于完成了数据的迁移、更新、同步、修复。总结一下这期间遇到的部分问题:

1、Mysql中前边有0的数据,0会被舍去的问题

如一条数据为0371xxx,存入数据库后数据变为371xxx

(1)如果字段类型必须为int,可以修改字段,增加zero fill,alter table 表名称 modify 字段名称 int  not null zero fill;

(2)如果不必须为int,修改字段类型为字符串类型,另外sql语句中该字段数据一定要加引号,不加引号即使为字符串类型也会丢失前边的0

2、某些数据部分字段出现错误,而很多数据未出错字段又已做过修改

在数据库中增加一个isexists字段,默认为0.

主键判断数据是否存在,存在更新相应字段,不存在插入,更新与插入的数据isexists设置为1

更新完成后删除isexists为0的数据。确认数据无误后删除isexists字段。

公司项目代码中,某枚举字段数据库表中类型是char(1),在代码中,误以为是TINYINT,所以用数字筛选,后来发现结果不对。发现了一个现象,用数字0筛选会把所有的记录给筛选出来。
经过排查发现是在MySQL查询语句中,’abc’如果和’0’比较结果显然是不等的,但如果’abc’和0比较呢?结果居然是相等的。

随意测试了几下,结果如下:

  1. mysql> select ‘abc’=0;
  2. +———+
  3. | ‘abc’=0 |
  4. +———+
  5. | 1 |
  6. +———+
  7. 1 row in set, 1 warning (0.00 sec)
  1. mysql> select ‘0abc’=0;
  2. +———-+
  3. | ‘0abc’=0 |
  4. +———-+
  5. | 1 |
  6. +———-+
  7. 1 row in set, 1 warning (0.00 sec)
  1. mysql> select ’01abc’=0;
  2. +———–+
  3. | ’01abc’=0 |
  4. +———–+
  5. | 0 |
  6. +———–+
  7. 1 row in set, 1 warning (0.00 sec)
  1. mysql> select ‘013abc’=13;
  2. +————-+
  3. | ‘013abc’=13 |
  4. +————-+
  5. | 1 |
  6. +————-+
  7. 1 row in set, 1 warning (0.00 sec)

以上几个查询通过查看MySQL给出的警告,都可以看到类似如下的信息

  1. mysql> show warnings;
  2. +———+——+——————————————–+
  3. | Level | Code | Message |
  4. +———+——+——————————————–+
  5. | Warning | 1292 | Truncated incorrect DOUBLE value: ‘013abc’ |
  6. +———+——+——————————————–+
  7. 1 row in set (0.00 sec)

查阅MySQL 5.7官方文档中关于比较的章节,其中说明Strings are automatically converted to numbers and numbers to strings as necessary.。也就是说在比较的时候,String是可能会被转为数字的。

而对于数字开头的字符串来说,转为数字的结果就是截取前面的数字部分

  1. mysql> select cast(‘123abc’ as signed);
  2. +—————————–+
  3. | cast(‘123abc’ as signed) |
  4. +—————————–+
  5. | 123 |
  6. +—————————–+
  7. 1 row in set, 1 warning (0.00 sec)
  1. mysql> select cast(‘123.45abc’ as decimal(5,2));
  2. +———————————–+
  3. | cast(‘123.45abc’ as decimal(5,2)) |
  4. +———————————–+
  5. | 123.45 |
  6. +———————————–+
  7. 1 row in set (0.00 sec)
  1. mysql> select cast(‘abc’ as signed);
  2. +———————–+
  3. | cast(‘abc’ as signed) |
  4. +———————–+
  5. | 0 |
  6. +———————–+
  7. 1 row in set, 1 warning (0.00 sec)

“`

而对于开头部分不能截取出数字的字符串来说,转换的结果自然就是0了。

关于字符串类型与整数直接进行比较的坑,说穿了就是MySQL中字符串转为数字的逻辑,没遇到过确实可能不太清楚,遇到过一次以后经验就是,看清楚数据库表字段,尽量避免字符串与数字的直接比较。

此外,书写sql语句的时候务必注意不要犯类型的错误,也许查出来的结果是对的,但是由于类型不匹配的原因,将会导致表索引无法用上