织网

身体和灵魂,总有一个在路上

Python 使用 LDAP

| Comments

写在开头

过去的两个多星期,几位小伙伴同心协力完成一个自研的,类似pushover的产品。感谢 Leader 的信任,让我在负责开发的同时也兼顾了一把项目经理。谢谢 IOS, Android 客户端的兄弟,设计师的支持,还有一位实习生,开心看到他的点滴成长。

提下背景,我们之前使用 pushover 来做报警推送,但是它对天朝用户不友好,Android 用户需要翻墙才能使用,有时候不稳定,体现为会收不到信息。pushove 需要付费。我们的受众不仅有程序汪,还有运营产品汪,他们需要一款更容易上手的推送软件,至少不需要番羽墙。于是自己开发一个很有必要。

为最大程度降低用户使用门槛,同时保证用户信息的安全,我们用了 LDAP 账户登陆,严格控制权限,以及 HTTPS 协议开发。下面提一提 LDAP 这个东西。

LDAP 是什么

LDAP维基百科

简单地讲,它是以目录树的方式存放账户信息。

这次项目中,我们不希望用户重新注册账户,而是采用原有的用户体系,这样对单点登录以及权限控制的好处不严而喻, LDAP 协议呼之欲出。

virtualenv 下安装 python-ldap

我们采用 Python 开发,这就需要 python-ldap 的帮助了, 记下安装笔记的好处是下次不用在此纠结太长时间。

1
2
apt-get install libsasl2-dev python-dev libldap2-dev libssl-dev
pip install python-ldap

身份验证

1
2
3
4
5
6
7
8
9
10
11
# LDAP 服务的域名和端口
SERVER_NAME = 'xxxx'
SERVER_PORT = xxx
try:
    conn = ldap.open(SERVER_NAME, SERVER_PORT)  
    conn.protocol_version = ldap.VERSION3 #设置ldap协议版本 
    username = "user=xxx,dc=company,dc=com" #身份信息
    password = "xxx" #访问密码
    conn.simple_bind_s(username,password) # 开始绑定,验证成功的话不会抛出异常
except ldap.LDAPError, e: #捕获出错信息
    print e

一点感悟

鄙人觉得,技术领导要带领项目成长, 除了有责任把控项目风险,推进项目进度。 还必须要花很多的心血在驾驭技术上, 身先士卒去调研可行性, 以及做技术攻关, 而非命令式地分配任务,让同事干活, 只问责结果。 否则很容易导致凝聚力不足,团队技术氛围不足,这样的团队易消极,也易滋生失败的项目。 然而在天朝, 很多人存在一个潜意识:写好代码是为了以后不写代码,这种阶级思想让我反感。

以前看过一个新闻, 硅谷在面试技术 VP ,仍然要求其在各位工程师面前手写代码,以此作为面试的重要环节, 不得不点赞。

Sysdig 值得拥有

| Comments

定位服务器问题时, 我们需要各式各样的武器, 诸如 iftop, ifstat, netstat, tcpdump, iostat。dstat 等, 因此工具箱需要装满很多工具, 在面对问题的时候才能显得不费吹灰之力, 迅速定位问题并解决, 保障服务稳定运行。Sysdig 的横空出世, 对我们而言, 就是一把瑞士军刀, 灵活小巧, 武艺多端.

安装

1
2
3
4
curl -s https://s3.amazonaws.com/download.draios.com/DRAIOS-GPG-KEY.public | apt-key add -
curl -s -o /etc/apt/sources.list.d/draios.list http://download.draios.com/stable/deb/draios.list
apt-get update
apt-get -y install sysdig

常用操作

sysdig 有很多 chisel, chisel 意为 铲子, 可以理解为定位某类问题的工具, sysdig 采用 Lua 编写的。

  • 查看 chisel 列表
1
sysdig -cl  
  • 查看具体某个 chisel 的提示
1
sysdig -i spy_logs
  • 使用某个 chisel
1
sysdig -c spy_logs
  • 过滤器可以帮助我们从各种输出信息中, 筛选出我们需要的, 比如 proc.name=foo , 如果你记住不了太多过滤器也无妨, 我们可以借助如下命令查看过滤器
1
sysdig -l
  • 记录定位信息到文本, 以及从文本读取信息
1
2
sysdig -w tracefile.cap
sysdig -r tracefile.dump proc.name=sshd

高效的实战

  • 服务器上经常需要查看哪个服务带宽占用使用较高, 特别是被 DDOS 的时候。
1
sudo sysdig -c topprocs_net
  • 查看某个IP的通讯数据,并以ASCII 码输出
1
sudo sysdig -s2000 -A -c echo_fds fd.cip=127.0.0.1
  • 查看非请求 redis-server 的其他请求进程和句柄
1
sudo sysdig -p"%proc.name %fd.name" "evt.type=accept and proc.name!=redis-server"
  • 查看访问该服务器的所有 GET 请求数据
1
sudo sysdig -s 2000 -A -c echo_fds fd.port=80 and evt.buffer contains GET
  • 查看访问该服务器的 SQL 语句
1
sudo sysdig -s 2000 -A -c echo_fds evt.buffer contains SELECT
  • 查看磁盘读写最高的进程
1
sysdig -c topprocs_file
  • 查看延迟最大的系统调用
1
sysdig -c topscalls_time
  • 查看具体文件的操作细节
1
sysdig -A -c echo_fds "fd.filename=syslog"
  • 查看 IO 延迟大于 1ms 的文件
1
sudo sysdig -c fileslower 1
  • 监视某个文件是否被操作, 从安全出发想象空间很大哦
1
sudo sysdig evt.type=open and fd.name contains /etc

Sysdig 官网

Ansible 使用经验

| Comments

当你只有一两台服务器的情况下,可以直接登上服务器,手敲命令完成软件部署,代码发布等工作。但假如你有10台,100台的时候,这种方式不仅浪费大量时间,而且给人为犯错带来了可能。于是我们选择 Ansible 来做自动化批量操作。

之前有记录一些 Ansible 入门的使用,请看这里, 这半年的积累, 总结一些实用的经验, 记录了一把。

更好地配置文件

我们会如下配置 /etc/ansible/host, 特意指明用户与 端口

1
2
3
[web-cluster]
<node-1-IP> ansible_ssh_port=<Your Port> ansible_ssh_user=zj
<node-2-IP> ansible_ssh_port=<Your Port> ansible_ssh_user=zj

在 /etc/ansible/ansible.cfg 文件里 我们特意提及了 ansible-role 的配置,未来我们会使用这个东西

1
roles_path    = /home/zj/my-ansible/roles

使用 ansible role 来区分业务

打开 ansible 部署脚本的文件夹, 目录树如下

1
2
3
4
5
6
7
8
9
cd /home/zj/my-ansible/
haproxy
     - entry.yaml
roles
     - haproxy
        - files
        - handlers
        - vars
        - tasks

我用一个管理 haproxy 的例子来讲解这种方式。 在 roles 目录下创建 haproxy, 如上所示,需要有四个目录;

  • files 目录下放置需要被传输到远端的文件;
  • vars 目录下有一个 main.yml 文件,可以定义一些通用的配置变量,可以在 ansbile 脚本中使用;
  • handlers 目录下有一个 main.yml, 可以定义一些通用的操作,比如重启服务等;
  • tasks 目录下是我们编写 main.yml 脚本,执行业务逻辑的地方;

那么 ansible role 的入口在哪呢?

在 ~/my-ansible/haproxy/entry.yml 中,指定了roles的角色,如此一来, ansible-playbook 就会去 /home/zj/my-ansible/roles/haproxy 准备执行 tasks/main.yml

1
2
3
- hosts: web-cluster
  roles:
    - haproxy

files 目录的路径定位

摘取 ~/my-ansible/roles/haproxy/tasks/main.yml

1
2
3
- name: copy haproxy conf
  copy: src=haproxy.cfg dest=/etc/haproxy/haproxy.cfg owner=root group=root
  sudo: yes

这里的 src=haproxy.cfg 意味着 ~/my-ansible/roles/haproxy/files/haproxy.cfg

使用 tags 区分不同操作

1
2
3
4
5
- name: install ppa
  shell: add-apt-repository -y ppa:vbernat/haproxy-1.5
  sudo: yes
  tags:
    - install-haproxy

以下命令,是使用 tags 参数区分操作的例子

1
2
cd ~/my-ansible/haproxy
ansible-playbook entry.yml -v -K --tags "install-haproxy"

规划 ansible roles 的 tasks 目录

tasks 目录有一个主执行文件 main.yml, 因为业务操作步骤太多,导致 main.yml 文件很长,那么可读性就下降了。为此,我们使用了 include 语法。

cat ~/my-ansible/roles/haproxy/tasks/main.yml

1
- include: 'install-haproxy.yml'

include 上述文件,这样 main.yml 就显得简洁,我们可以将相关的操作写在对应的 yml 文件里

cat ~/my-ansible/roles/haproxy/tasks/install-haproxy.yml

1
2
3
4
5
- name: copy haproxy conf
  copy: src=haproxy.cfg dest=/etc/haproxy/haproxy.cfg owner=root group=root
  sudo: yes
  tags:
     - install-haproxy

tags 最好也与该 yml 文件名一致,清晰分明

ansible-play-book 一些常用的选项

  • -K 需要 sudo 权限去客户机执行命令,会提示你输入密码
  • -v 可以输出冗余的执行过程
  • –check 可以测试脚本执行情况,但实际并未在远程机器执行
  • –tags 提示 ansible-play-book 调用哪些 tags 命令

使用过ansible roles 之后,最大的体会是操作调理化,甚至编程化,合理的利用 handler, vars, 能更加优雅抽象。


上述的例子在 Github 有代码, 结合本文阅读可能更容易上手 Link

Supervisor 监听器

| Comments

我们服务多是用 supervisor 启动的, 但监控多数是用 monit, 如果我们能通过监测 supervisor 事件变化来做监控,就可以写一套通用的监控程序。

庆幸的是,supervisor 的 eventListener 支持我的设想。

这个监控程序需要用 supervisor 启动,类型不再是program, 而是eventlistener,这里有几个比较耗时的地方需要记录下。

  • supervisor 有独特的通信协议,需要遵循,否则通讯不会被触发
1
2
3
4
5
6
def write_stdout(self, s):
    sys.stdout.write(s)
    sys.stdout.flush()

write_stdout('READY\n') //类似开始握手
write_stdout('RESULT 2\nOK') //结束通讯
  • 需要从标准输入端读取事件,而且他是个阻塞的事件模型
1
2
3
4
5
while 1:
    self.write_stdout('READY\n')
    line = sys.stdin.readline()
    do_some_thing()
    self.write_stdout('RESULT 2\nOK')
  • supervisor 配置文件需要订阅事件
1
2
3
4
5
6
7
8
[eventlistener:alarm]
user=zj
command=/usr/bin/python /home/ymserver/bin/alarm/main.py
events=PROCESS_STATE_EXITED,PROCESS_STATE_STOPPED,PROCESS_STATE_FATAL

# 记录控制台输出的日志位置
stderr_logfile=/home/zj/log/supervisor/alarm.err.log
stdout_logfile=/home/zj/log/supervisor/alarm.output.log

弄好 supervisor 配置,以及部署好代码之后,需要重启 supervisor 才会真正的订阅事件。 从此 supervisor 管理的程序一旦有 FATAL,EXIT 等状态就会触发程序,程序中就会触发自定义的报警。


代码

Happy Hack!

Twemproxy 一个 Redis 代理

| Comments

为解决线上 Redis 服务直连出现链接数爆棚而做的调研, 对 Twitter 开源的 twemproxy 做一些记录。 我们之所以放弃官方的 RedisCLuster 是因为不太满意其性能

初窥原理 * 安装与配置 * 不支持的操作 * 压力测试 * 摘自极光博客的评论

初窥原理

  • Twitter 出品的轻量级 Redis,memcached 代理,使用它可以减少缓存服务器的连接数,并且利用它来作分片。
  • 作是说最差情况下,性能损耗不会多于20%。背后是用了pipeline,redis是支持使用pipeline批处理的。
  • twemproxy 与每个 redis 服务器都会建立一个连接,每个连接实现了两个 FIFO 的队列, 通过这两个队列实现对 redis 的 pipeline 访问,将多个客户端的访问合并到一个连接,这样既减少了redis服务器的连接数,又提高了访问性能。

安装与配置

  • 安装
1
2
3
4
5
6
7
8
apt-get install automake
apt-get install libtool
git clone git://github.com/twitter/twemproxy.git
cd twemproxy
autoreconf -fvi
./configure
make
sudo make install

默认的可执行文件在 /usr/local/sbin/nutcracker

  • 配置文件 /etc/nutcracker/nutcracker.yml
1
2
3
4
5
6
7
8
9
10
11
alpha:
    listen: 127.0.0.1:8877
    hash: fnv1a_64
    distribution: ketama
    auto_eject_hosts: true
    redis: true
    server_retry_timeout: 30000
    server_failure_limit: 3
    servers:
        - 127.0.0.1:6379:1 master0  #后端的redis-server
        - 127.0.0.1:6380:1 master1

当 redis 做缓存的使用的时候应该启用 auto_eject_hosts, 如果某个节点失败的时候将该节点删除,虽然丧失了数据的一致性,但作为缓存使用,保证了这个集群的高可用性。当redis做存储的使用时为了保持数据的一致性,应该禁用 auto_eject_hosts,也就是当某个节点失败之后并不删除该节点。

不支持的操作

1
2
3
4
5
keys command: keys,migrate,move object,randomkey,rename,renamenx,
sort strings command: bitop,mset,msetnx
list command: blpop,brpop,brpoplpush
scripting command: script exists,script flush,script kill,script load
pub/sub command:(全部不支持)psubscribe,publish,punsubscribe,subscribe,unsubscribe

压测

感谢 redis 提供的 redis-benchmark 工具,用它来做压测挺好的。

  • n 表示多少个连接
  • r 表示多少个 key,
  • t 代表命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
zj@zheng-ji.info:~$ redis-benchmark -p 6700 -t smembers,hexists,get,hget,lrange,ltrim,zcard,setex,sadd -n 1000000 -r 100000000

====== GET ======
1000000 requests completed in 12.95 seconds
50 parallel clients
3 bytes payload
keep alive: 1

99.19% <= 1 milliseconds
99.93% <= 2 milliseconds
100.00% <= 2 milliseconds
77220.08 requests per second

====== SADD ======
1000000 requests completed in 10.74 seconds
50 parallel clients
3 bytes payload
keep alive: 1

99.88% <= 1 milliseconds
99.95% <= 2 milliseconds
99.97% <= 3 milliseconds
99.99% <= 4 milliseconds
100.00% <= 4 milliseconds
93144.56 requests per second

如作者所言, 性能几乎可以跟直连redis比拟,背后的数据也很均匀,使用twemproxy 观察连接数, 一直都保持在个位数左右。

摘自极光博客的评论

  • 前端使用 Twemproxy 做代理,后端的 Redis 数据能基本上根据 key 来进行比较均衡的分布。
  • 后端一台 Redis 挂掉后,Twemproxy 能够自动摘除。恢复后,Twemproxy 能够自动识别、恢复并重新加入到 Redis 组中重新使用。
  • Redis 挂掉后,后端数据是否丢失依据 Redis 本身的策略配置,与 Twemproxy 基本无关。
  • 如果要新增加一台 Redis,Twemproxy 需要重启才能生效;并且数据不会自动重新 Reblance,需要人工单独写脚本来实现。
  • 如同时部署多个 Twemproxy,配置文件一致(测试配置为distribution:ketama,modula),则可以从任意一个读取,都可以正确读取 key对应的值。
  • 多台 Twemproxy 配置一样,客户端分别连接多台 Twemproxy可以在一定条件下提高性能。根据 Server 数量,提高比例在 110-150%之间。
  • 如原来已经有 2 个节点 Redis,后续有增加 2 个 Redis,则数据分布计算与原来的 Redis 分布无关,现有数据如果需要分布均匀的话,需要人工单独处理。
  • 如果 Twemproxy 的后端节点数量发生变化,Twemproxy 相同算法的前提下,原来的数据必须重新处理分布,否则会存在找不到key值的情况。

参考链接

极光推送的博客

黑客马拉松

| Comments

周末参加了公司组织的黑客马拉松比赛,

通宵达旦完成了作品是个值得纪念的经历, 我们的产品叫做:正义的朋友

  • 我们想要实现的功能是让人在紧急关头用最快速的方式联系到可以帮助你的人,于是我们通过锁屏应用来实现;
  • 用户在锁屏状态,画一个v手势,会把自己的地理位置发送给设置好的联系人,并持续每十秒发送一次周围的声音给联系人;
  • 用户在锁屏状态,画一个w手势,会发出专业的求救声

这次比赛的感觉, 与当年叫神马团队的似曾相识, 队友非常给力, 大家都很拼, 我喜欢这种感觉, 事实上,在比赛之前,为了工作上的项目我已经几乎透支了, 队友也是一样。 但周六上午我们还是快速进入状态, 被逼的潜力果然不容小觑. 晒一张我们队伍合照.

记录错误登陆的 Btmp 文件

| Comments

今天查看了服务器时,发现 /var/log/btmp 日志文件较大。

此文件是记录错误登录的日志, 文件较大意味着有人使用密码字典登录ssh服务, 这个文件是需要用 lastb 命令才可读的。

查看尝试恶意登陆的前十个IP

1
sudo lastb | awk '{ print $3}' | awk '{++S[$NF]} END {for(a in S) print a, S[a]}' | sort -rk2 |head

如果有有必要封阻IP的话,可以执行:

1
iptables -A INPUT -i eth0 -s *.*.*.0/24 -j DROP

my.cnf 配置依据

| Comments

阅读完构建高性能服务器 一书,书中对 MySQL 配置做了讲解,我用烂笔头记录一番,明白它们这么配置的真正意义,形成系统的认知。

通用配置

1
skip-name-resolve:

禁止 MySQL 对外连接 DNS 解析 ,这一选项可以消除 MySQL 进行DNS解析时间,开启该选项,所有远程主机连接授权都要使用 IP。

1
back_log=512

指出在 MySQL 暂停响应之前,有多少个请求被存在堆栈中。

1
key_buffer_size

指定用于索引的缓冲区大小,增加它可得到更好的索引处理能力,对于内存 4G 左右,可设置为 256MB。

1
max_allowed_packet=4M

设定在一次网络传输中的最大值。

1
thread_stack=256k

设置每个线程的堆栈大小,可满足普通操作。

1
table_cache=614k

高速缓冲区的大小,当mysql访问一个表示,缓冲区还有空间,那么这个表就会被放入缓冲区,一般看峰值时间状态值,open_tables与open_cache,用于判断是否需要增加table_cache,如果open_Table接近table_cache就要增加了。

1
sort_buffer_size=6M

设定查询排序所用的缓冲区大小,是对每个链接而言,如果有100个连接,那么分配的总缓存是100*6=600M。 read_buffer_size,join_buffer_size 都是对单个链接而言。

1
thread_cache_size=64

设置缓存中的链接线程的最大数量,4GB内存以上的我们会给64或者更大。

1
query_cache_size=64M

如果该值比较小反而会影响效率,可以考虑不用。如果太大,缓存区中碎片会很多。

1
tmp_table_size

设置内存临时表的最大值,如果超过改制,就会将临时表写入磁盘,范围是1kB-4GB。

1
max_connection

如果超过该值,会出现too many connections

1
max_connect_errors

设置每个主机中连接请求异常中断最大次数,如果超过,MySQL禁止host连接请求,直到MySQL重启。

1
wait_timeout = 120

一个请求的最大链接时间。

1
thread_concurrency=8

该参数为服务器逻辑CPU * 2。

1
skip-networking

该选项可以关闭连接方式,如果需要远程连接,不要开启。

1
innodb_flush_log_at_trx_commit = 1

设置为0就是等到 innodb_log_buffer_size 队列满了之后再统一存储,默认是1,是最安全的设置。

1
innodb_thread_concurrency = 8

服务器几个CPU就设置多少。

1
read_rnd_buffer_Size = 16M

设置随机读的使用的缓冲区。

innodb_buffer_pool 的合理设置

不要武断的把innodb_buffer pool 配置为内存的50-80% 应具体而定。

1
2
3
4
5
6
7
show status like 'innodb_buffer_pool_%'

关注的有
innodb_buffer_pool_pages_data;
innodb_buffer_pool_page_total;
innodb_buffer_pool_read_request;
innodb_buffer_pool_reads;

然后看

1
2
读命中率 (innodb_buffer_pool_read_request - innodb_buffer_pool_reads) / innodb_buffer_pool_read_request;
写命中率 innodb_buffer_pool_pages_data /innodb_buffer_pool_page_total;

如果读写命中率都能在95%以上就很好了。

文件打开数的合理设置依据

1
2
show global status like 'open_files'
show variables like 'open_file_limit';

比较合适的设置是 Open_files / open_files_limit * 100% <= 75;

打开表优化设置依据

1
2
show global status like 'open%tables';
show variable like 'table_cache';

比较合适

1
2
open_tables / opende_tables * 100 > 85%;
open_Tables / table_Cache* 100% < 95%;

临时表的设置依据

每次执行语句,关于已经被创造了的临时表的数量,可以这么设置:

1
2
show gloabl status like 'created_tmp5';
Created_tmp_disk_table / Created_tmp_tables * 100% <= 25 %

查看索引命中率

1
show global status like 'key_read%';

key_cache_miss_rate = key_Read / key_read_request * 100% 小于 1% 是很好的, 意味着1000个请求有一个直接读硬盘。

轻巧实时统计用户数

| Comments

背景

最近在优化一个短地址的统计服务,之前是使用 Cookie 来做统计每天的UV,而且这个需求是近乎实时的, 业务方需要每5分钟就能看到最新统计结果。但有些情况我们是取不到Cookie的,比如服务器对服务器的狂刷访问,那么UV就计算不准确, 是时候要改造方案了。

后来我用 IP+UserAgent 来识别用户,从而统计 UV。好了,接下来你会怎么做这个实时统计呢?

两个方案的选择

  • Plan A:

将每天的 IP+UA 存进 Redis 的 Set 集合里,它会自动去重,然后计算该集合里元素的个数得到结果,此方案似乎不错, 但真的好吗?假如每天大概有200W个UV,1个用户标识IP+UA需要大概150个字节,那么大约要耗费300MB的内存。

觉得内存太宝贵,应该有更好的方法,想起了位运算, 于是就有了

  • Plan B:

IP+UA 组合成的字符串哈希成一个数值,然后借助 Redis 的 BitSet 数据结构求出UV。以下是伪代码

1
2
3
4
5
6
conn = redis()
index = hash(UA+IP)
key = "xxx_2015-05-10"
conn.do('SETBIT', key, index, 1) # 将该hash值对应的位赋值为1

realtime_uv = conn.do('BITCOUNT', key) # 得到实时的uv

根据业务的情况,我的hash桶开了200W个位,大概需要消耗2M的内存,的确节约不少空间,位运算的效率也很快。 于是欣然选择 Plan B

一些链接

搭建 Postfix

| Comments

我们需要搭建邮件服务,采用Postfix服务, 坑点不少,遂记录。 现在我们决定在 IP:1.2.3.4 的机器上部署Postfix服务,让它可以发邮件

安装

1
sudo apt-get install postfix

配置

编辑 /etc/postfix/main.cnf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
biff = no
append_dot_mydomain = no
readme_directory = no
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_use_tls=yes
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
myhostname = mail.zheng-ji.info 邮箱服务器域名
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = $myhostname
mydestination = mail.zheng-ji.info, localhost.localdomain, localhost
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128, hash:/etc/postfix/access 可以使用这个邮箱服务的外部地址
relay_domains = $mydestination
inet_interfaces = all
inet_protocols = all

授权

为了让邮件能真正到达对方邮箱而不被视为垃圾邮件, 我们需要进行DNS权威认证

1
2
3
A 记录指向 1.2.3.4
MX 记录也指向 1.2.3.4
TXT 记录 v=spf1 ip4:1.2.3.4 ~all

以上操作是防止被认为垃圾邮件。

外部需要访问该Postfix 服务发送邮件,需要有access权限, 编辑/etc/postfix/access, 假设 IP:5.6.7.8 的机器想访问该服务

1
5.6.7.8  OK

重启并授权生效

1
2
sudo service postfix restart
postmap access