灌溉梦想,记录脚步

/etc/sudoers配置范例以及解释

  /etc/sudoers配置范例以及解释:
  示例
  下面是sudoers条目的示例.显然,一些示例有点不自然.首先,我们定义别名:
  # User alias specification
  User_Alias FULLTIMERS = millert, mikef, dowdy
  User_Alias PARTTIMERS = bostley, jwfox, crawl
  User_Alias WEBMASTERS = will, wendy, wim
  # Runas alias specification
  Runas_Alias OP = root, operator
  Runas_Alias DB = oracle, sybase
  # Host alias specification
  Host_Alias SPARC = bigtime, eclipse, moet, anchor :\
  SGI = grolsch, dandelion, black :\
  ALPHA = widget, thalamus, foobar :\
  HPPA = boa, nag, python
  Host_Alias CUNETS = 128.138.0.0/255.255.0.0
  Host_Alias CSNETS = 128.138.243.0, 128.138.204.0/24, 128.138.242.0
  Host_Alias SERVERS = master, mail, www, ns
  Host_Alias CDROM = orion, perseus, hercules
  # Cmnd alias specification
  Cmnd_Alias DUMPS = /usr/bin/mt, /usr/sbin/dump, /usr/sbin/rdump,\
  /usr/sbin/restore, /usr/sbin/rrestore
  Cmnd_Alias KILL = /usr/bin/kill
  Cmnd_Alias PRINTING = /usr/sbin/lpc, /usr/bin/lprm
  Cmnd_Alias SHUTDOWN = /usr/sbin/shutdown
  Cmnd_Alias HALT = /usr/sbin/halt, /usr/sbin/fasthalt
  Cmnd_Alias REBOOT = /usr/sbin/reboot, /usr/sbin/fastboot
  Cmnd_Alias SHELLS = /usr/bin/sh, /usr/bin/csh, /usr/bin/ksh, \
  /usr/local/bin/tcsh, /usr/bin/rsh, \
  /usr/local/bin/zsh
  Cmnd_Alias SU = /usr/bin/su
  接下来我们改写了一些编译进的默认值.我们希望sudo在所有情况下使用auth设施在系统日志中作记录.我们不想总是输出初次使用sudo的提示,并且用户millert使用sudo不需要口令.另外,我们为SERVERS Host_Alias中的主机维护一个附加的本地日志文件.并且由于这个日志需要保存许多年,我们要在日志的每一行中加入年份信息.
  # Override built in defaults
  Defaults syslog=auth
  Defaults:FULLTIMERS !lecture
  Defaults:millert !authenticate
  Defaults@SERVERS log_year, logfile=/var/log/sudo.log
  实际上决定谁能运行什么的是用户说明部分:
  root ALL = (ALL) ALL
  %wheel ALL = (ALL) ALL
  我们让root和wheel组的成员可以在任何主机上以任何人的身份运行任何命令.
  FULLTIMERS ALL = NOPASSWD: ALL
  专职系统管理员(millert,mikef和dowdy)可以在任何主机上执行任何命令而不需要进行身份验证.
  PARTTIMERS ALL = ALL
  兼职系统管理员(bostley,jwfox和crawl)可以在任何主机上运行任何命令,但他们首先必须进行身份验证(因为这个条目没有NOPASSWD标签).
  jack CSNETS = ALL
  用户jack可以在CSNETS别名(网络128.138.243.0,128.138.204.0和128.138.242.0)中的机器上运行任何命令.在这些网络中,只有128.138.204.0明确的给出了掩码(用CIDR方式),指明这是个C类网.对CSNETS中的其他网络来说,如果本地主机的掩码匹配的话将使用本地主机的掩码.
  lisa CUNETS = ALL
  用户lisa可以在CUNETS别名(B类网络128.138.0.0)中的任何主机上执行任何命令.
  operator ALL = DUMPS, KILL, PRINTING, SHUTDOWN, HALT, REBOOT,\
  /usr/oper/bin/
  用户operator可以执行的命令被限制在一个简单的maintenance中.这里就是和备份,杀死进程,打印系统,关闭系统和任何在/usr/oper/bin/中的命令.
  joe ALL = /usr/bin/su operator
  用户joe只能su成operator.
  pete HPPA = /usr/bin/passwd [A-z]*, !/usr/bin/passwd root
  用户pete可以修改HPPA上除了root以外任何用户的口令.注意,这里人为passwd不会在命令行上使用多个用户名.
  bob SPARC = (OP) ALL : SGI = (OP) ALL
  用户可以在SPARC和SGI上以任何在OP Runas_Alias中列出的用户(root和operator)的身份运行任何命令.
  jim +biglab = ALL
  用户jim可以在biglab网络用户组中的机器上运行任何命令.因为biglab前面加上了前缀”+”,所以sudo知道这是一个网络用户组.
  +secretaries ALL = PRINTING, /usr/bin/adduser, /usr/bin/rmuser
  网络用户组secretaries中的用户需要帮助管理打印机和进行增删用户的工作,所以需要允许他们在任何机器上执行这些命令.
  fred ALL = (DB) NOPASSWD: ALL
  用户fred可以在DB Runas_Alias (oracle 或 sybase)上以任何人的身份执行任何命令而不需要提供口令.
  john ALPHA = /usr/bin/su [!-]*, !/usr/bin/su *root*
  用户john可以在ALPHA上su成除root的任何人,但是不允许他给su加上任何标志执行.
  jen ALL, !SERVERS = ALL
  用户jen可以在除了SERVERS Host_Alias (master, mail, www 和 ns)以外的任何机器上执行任何命令.
  jill SERVERS = /usr/bin/, !SU, !SHELLS
  用户jill可以在任何SERVERS Host_Alias中的机器上运行/usr/bin/下除了属于SU和SHELLS Cmnd_Aliases外的任何命令.
  steve CSNETS = (operator) /usr/local/op_commands/
  用户steve可以在任何CSNETS中的机器上执行/usr/local/op_commands/中的所有命令,但是只能以operator的身份.
  matt valkyrie = KILL
  用户matt应该可以在他自己的工作站valkyrie上杀死挂起的进程.
  WEBMASTERS www = (www) ALL, (root) /usr/bin/su www
  任何在WEBMASTERS User_Alias (will, wendy,和 wim)中的用户都能够在主机www上以www(网页的所有者)的身份执行任何命令,或者简单的su成www.
  ALL CDROM = NOPASSWD: /sbin/umount /CDROM,\
  /sbin/mount -o nosuid\,nodev /dev/cd0a /CDROM
  所有的用户都应该能够在 CDROM Host_Alias (orion, perseus, hercules)中的主机上mount和unmount光盘驱动器而不需要输入口令.对用户来说敲入这么长的命令有些冗长而乏味,所以把它封装在一个 shell脚本中是一个最佳的选择.
  安全要点
  使用”!”来从ALL中减去命令一般来说不会产生预期作用.用户可以简单的通过把希望执行的命令改名执行的法子来绕过限制.例如:
  bill ALL = ALL, !SU, !SHELLS
  这并不会阻止bill执行SU和SHELLS中列出的命令.他只需要把这些命令改一个名字,或者从一个编辑器或者其他程序中escape到shell(译注:原文是use a shell escape from an editor or other program)就可以运行了.所以这种类型的限制至少应该经过深思熟虑(并从策略上加强它).
  CAVEATS
  sudoers必需总是使用visudo命令来编辑,因为它会锁定文件并且进行语法检察.这强制sudoers摆脱语法错误,因为sudoers有语法错误时sudo是不会运行的.
  当使用机器的网络用户组时(与用户相反),如果您在网络用户组中存贮了完整的主机名(这经常是事实),您需要让主机名像hostname命令的输出一样是完整的或者在sudoers中使用fqdn选项.
  文件
  /etc/sudoers 谁能作什么的一个列表
  /etc/group 本地组文件
  /etc/netgroup 网络组文件

linux 限制用户登录

  控制用户的登录地点
  文件/etc/secruity/access.conf可控制用户登录地点,为了使用access.conf,必须在文件/etc/pam.d/login中加入下面行:
  account required /lib/security/pam_access.so
  access.conf文件的格式:
  permission : users : origins
  其中:
  permission:可以是 “+”或”-“,表示允许或拒绝。
  user:可以是用户名、用户组名,如果是all则表示所有用户。
  origins:登录地点。local表示本地,all表示所有地点,console表示控制台。另外,origins也可以是某一网络。
  后面两个域中加上 except是”除了”的意思。例如:除了用户wheel、shutdown、sync禁止所有的控制台登录:
  -:ALL EXCEPT wheel shutdown sync:console
  root账户的登录地点不在access.conf文件中控制,而是由/etc/securetty文件控制。
  必须保证/etc/pam.d/login有下面这行:
  auth required pam_securetty.so
  etc/securetty文件指定了允许root登录的tty设备,由/bin/login程序读取,其格式是一个被允许的名字列表,你可以编辑/etc/securetty且注释掉如下的行。
  # tty2
  # tty3
  # tty4
  # tty5
  # tty6
  这时,root仅可在tty1终端登录。
  关于PAM的一些解释
  热身:
  何要授予用户特权的程序都要能够进行用户认证。当您登入系统时,您需要提供用户名和口令,而后登入进程据此以检验登入的合法性—确认您就是该用户。还有除口令认证之外的其他认证形式,而且口令的存储方式也是各不相同的。
  1、说明
  A、PAM可加载目标文件(模块)是在RedHat Linux系统中它们被放在了/lib/security目录下
  B、PAM库本地系统配置文件/etc/pam.conf or /etc/pam.d/目录下的一些配置文件来设置
  2、# more login
  #%PAM-1.0
  auth required pam_securetty.so
  用来控制root用户只可以从包含在/etc/securetty文件中的终端登录系统。
  auth required pam_stack.so service=system-auth
  auth required pam_nologin.so
  提供标准的UNIX nologin登录认证。如果/etc/nologin文件存在,则只有root用户可以登录,其他用户登录时只会得到/etc/nologin文件的内容。如果/etc/nologin不存在,则该模块没有作用。
  account required pam_stack.so service=system-auth
  password required pam_stack.so service=system-auth
  # pam_selinux.so close should be the first session rule
  session required pam_selinux.so close
  session required pam_stack.so service=system-auth
  session optional pam_console.so
  # ls -l /dev/pts/1
  crw–w—- 1 root tty 136, 1 May 15 21:19 /dev/pts/1
  # ls -l /dev/pts/2
  crw–w—- 1 test tty 136, 2 May 15 21:20 /dev/pts/2
  用户登陆时,它将TTY设备权限改成该用户所有,当用户退出时,将TTY设备权限改为root所有。
  # pam_selinux.so open should be the last session rule
  session required pam_selinux.so multiple open
  login要做两件事,首先查询用户,然后为用户提供所需服务,例如提供一个shell程序。
  通常,login会提示用户输入密码。然后对密码进行校验,这项任务就是Linux-PAM完成的。
  上例中三个required连续使用, 即便第一个模块失败了,也要完成三个模块的校验。这是一种安全上的考虑 —这种设计永远不要让用户知道他或她们为什么会被拒绝,否则会让其更容易突破认证。可以将”required”改成”requisite”来修改这种认证方式。如果有任何”requisite”模块以失败返回,整个PAM认证将终止再调用其它模块也以失败返回。
  3、pam_unix认证模块
  所属类型: account; auth; password; session
  功能描述:该模块是标准UNIX认证模块pam_unix的替代模块。
  在作为auth类型使用时,此时该模块可识别的参数有debug、audit、use_first_pass、try_first_pass、nullok、nodelay,主要功能是验证用户密码的有效性,在缺省情况下(即不带任何参数时),该模块的主要功能是禁止密码为空的用户提供服务;
  auth required /lib/security/$ISA/pam_env.so
  auth sufficient /lib/security/$ISA/pam_unix.so likeauth nullok
  auth required /lib/security/$ISA/pam_deny.so
  在作为account类型使用时,此时该模块可识别的参数有debug、audit,该模块主要执行建立用户帐号和密码状态的任务,然后执行提示用户修改密码,用户采用新密码后才提供服务之类的任务;
  account required /lib/security/$ISA/pam_unix.so
  account sufficient /lib/security/$ISA/pam_succeed_if.so uid < 100 quiet
  account required /lib/security/$ISA/pam_permit.so
  在作为password类型使用时,此时该模块可识别的参数有debug、 audit、 nullok;、not_set_pass、use_authtok、try_first_pass、use_first_pass、md5、bigcrypt、shadow、nis、
  remember,该模块完成让用户更改密码的任务;
  password requisite /lib/security/$ISA/pam_cracklib.so retry=3
  password sufficient /lib/security/$ISA/pam_unix.so nullok use_authtok md5
  shadow
  password required /lib/security/$ISA/pam_deny.so
  在作为session类型使用时,此时该模块没有可识别的参数,该模块仅仅完成记录用户名和服务名到日志文件的工作。
  session required /lib/security/$ISA/pam_limits.so
  session required /lib/security/$ISA/pam_unix.so
  可带参数:
  debug:将调试信息写入日志
  audit:记录更为信息的信息
  nullok:缺省情况下,如果用户输入的密码为空,则系统能够不对其提供任何服务。但是如果使用参数,用户不输入密码就可以获得系统提供的服务。同时,也允许用户密码为空时更改用户密码。 ?
  nodelay:当用户认证失败,系统在给出错误信息时会有一个延迟,这个延迟是为了防止。黑客猜测密码,使用该参数时,系统将取消这个延迟。通常这是一个1秒钟的延迟。
  try_first_pass:在用作auth模块时,该参数将尝试在提示用户输入密码前,使用前面一个堆叠的auth模块提供的密码认证用户;在作为password模块使用时,该参数是为了防止用户将密码更新成使用以前的老密码。
  use_first_pass:在用作auth模块时,该参数将在提示用户输入密码前,直接使用前面一个堆叠的auth模块提供的密码认证用户;在作为password模块使用时,该参数用来防止用户将密码设置成为前面一个堆叠的password模块所提供的密码。
  no_set_pass:使密码对前后堆叠的password模块无效。
  use_authok:强制使用前面堆叠的password模块提供的密码,比如由pam_cracklib模块提供的新密码。
  md5:采用md5对用户密码进行加密。
  shadow:采用影子密码。
  unix:当用户更改密码时,密码被放置在/etc/passwd中。
  bigcrype:采用DEC C2算法加密用户密码。
  nis:使用NIS远处过程调用来设置新密码。
  remember=x:记录x个使用过的旧密码,这些旧密码以MD5方式加密后被保存在/etc/security/opasswd文件中。
  broken_shadow:在作为account使用时,该参数用来忽略对影子密码的读错误。
  likeauth:未知。
  配置实例:
  参考/etc/pam.d/system-auth
  设置密码中的常见错误信息?
  ⑴当用户输入的密码字符数太少时:
  BAD PASSWORD: it’s WAY too short
  ⑵当用户输入的密码相同字符太多时:
  BAD PASSWORD: it does not contain enough DIFFERENT characters
  ⑶当用户输入的密码为某英文单词时:
  BAD PASSWORD: it is based on a dictionary word
  ⑷当用户在”(current) UNIX password:”提示后输入的现有密码错误时:passwd: Authentication token manipulation error
  ⑸当用户两次输入的密码不相同时:Sorry, passwords do not match passwd: Authentication information cannot be recovered
  ⑹当用户输入的密码未被系统接受时:
  passwd: Authentication token manipulation error
  example 1
  auth required pam_securetty.so
  只用来控制root用户只可以从包含在/etc/securetty文件中的终端登录系统。
  telnet 服务使用PAM的login进行用户身份验证,#more /etc/pam.d/login便能看到此行,要让root不受限制远程login,第一种方法注销此处这一行,另一种在 /etc/securetty文件中加入诸如pts/n(1-n);
  同理如果想限制root使用ssh远程进入系统,只需在/etc/pam.d/sshd文件中加入这行;auth required pam_securetty.so即可。
  example 2
  account required pam_access.so
  pam_access是pam中处理用户访问控制的模块,没有使用pam前,linux对用户的所有访问控制都是借助hosts.allow, hosts.deny文件,实现所有服务的访问控制,再加上usertty就是对用户登陆控制(专门是针对login)。
  一种是直接修改/etc/security/access.conf
  另一种是使用参数accessfile=/path/to/file.conf
  例如修改access.conf文件:
  +:root:ALL //root从任意位置连入系统
  +:redhat:164.70.12.//redhat只能从这个网段连入
  -:ALL:ALL 其余DENY
  然后 # vi /etc/pam.d/sshd
  加入这一行 account required pam_access.so
  example 3
  限制用户LOGIN次数
  在/etc/security/limits.conf :
  加入redhat – maxlogins 3
  然后 # vi /etc/pam.d/sshd
  加入这一行session required pam_limits.so
  则同一用户至多3-1次login入系统
  example 4
  限制用户LOGIN时间
  # vi /etc/security/time.conf加入以下一行
  sshd;*;redhat;!Tu2200-2230
  # vi /etc/pam.d/sshd 加入以下一行
  account required pam_time.so
  则redhat每星期二晚上22:00-22:30不能使用SSH来login系统。
  example 5
  用户访问控制
  # vi /etc/pam.d/vsftpd 加入以下一行
  auth required pam_listfile.so item=user sense=deny file=/etc/ftpusers onerr=succeed
  # vi /etc/ftpusers …….

mysql性能的检查和调优方法

  我一直是使用mysql这个数据库软件,它工作比较稳定,效率也很高。在遇到严重性能问题时,一般都有这么几种可能:
  1、索引没有建好;
  2、sql写法过于复杂;
  3、配置错误;
  4、机器实在负荷不了;
  1、索引没有建好
  如果看到mysql消耗的cpu很大,可以用mysql的client工具来检查。
  在linux下执行
  /usr/local/mysql/bin/mysql -hlocalhost -uroot -p
  输入密码,如果没有密码,则不用-p参数就可以进到客户端界面中。
  看看当前的运行情况
  show full processlist
  可以多运行几次
  这个命令可以看到当前正在执行的sql语句,它会告知执行的sql、数据库名、执行的状态、来自的客户端ip、所使用的帐号、运行时间等信息
  在我的cache后端,这里面大部分时间是看不到显示任何sql语句的,我认为这样才算比较正常。如果看到有很多sql语句,那么这台mysql就一定会有性能问题
  如果出现了性能问题,则可以进行分析:
  1、是不是有sql语句卡住了?
  这是出现比较多的情况,如果数据库是采用myisam,那么有可能有一个写入的线程会把数据表给锁定了,如果这条语句不结束,则其它语句也无法运行。
  查看processlist里的time这一项,看看有没有执行时间很长的语句,要留意这些语句。
  2、大量相同的sql语句正在执行
  如果出现这种情况,则有可能是该sql语句执行的效率低下,同样要留意这些语句。
  然后把你所怀疑的语句统统集合一下,用desc(explain)来检查这些语句。
  首先看看一个正常的desc输出:
  mysql> desc select * from imgs where imgid=1651768337;
  +—-+————-+——-+——-+—————+———+———+——-+——+——-+
  | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  +—-+————-+——-+——-+—————+———+———+——-+——+——-+
  | 1 | SIMPLE | imgs | const | PRIMARY | PRIMARY | 8 | const | 1 | |
  +—-+————-+——-+——-+—————+———+———+——-+——+——-+
  1 row in set (0.00 sec)
  注意key、rows和Extra这三项,这条语句返回的结果说明了该sql会使用PRIMARY主键索引来查询,结果集数量为1条,Extra没有显示,证明没有用到排序或其他操作。由此结果可以推断,mysql会从索引中查询imgid=1651768337这条记录,然后再到真实表中取出所有字段,是很简单的操作。
  key是指明当前sql会使用的索引,mysql执行一条简单语句时只能使用到一条索引,注意这个限制;rows是返回的结果集大小,结果集就是使用该索引进行一次搜索的所有匹配结果;Extra一般会显示查询和排序的方式,。
  如果没有使用到key,或者rows很大而用到了filesort排序,一般都会影响到效率,例如:
  mysql> desc select * from imgs where userid=”7mini” order by clicks desc limit 10;
  +—-+————-+——-+——+—————+——+———+——+——-+—————————–+
  | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  +—-+————-+——-+——+—————+——+———+——+——-+—————————–+
  | 1 | SIMPLE | imgs | ALL | NULL | NULL | NULL | NULL | 12506 | Using where; Using filesort |
  +—-+————-+——-+——+—————+——+———+——+——-+—————————–+
  1 row in set (0.00 sec)
  这条sql结果集会有12506条,用到了filesort,所以执行起来会非常消耗效率的。这时mysql执行时会把整个表扫描一遍,一条一条去找到匹配userid=”7mini”的记录,然后还要对这些记录的clicks进行一次排序,效率可想而知。真实执行时如果发现还比较快的话,那是因为服务器内存还足够将12506条比较短小的记录全部读入内存,所以还比较快,但是并发多起来或者表大起来的话,效率问题就严重了。
  这时我把userid加入索引:
  create index userid on imgs (userid);
  然后再检查:
  mysql> desc select * from imgs where userid=”7mini” order by clicks desc limit 10;
  +—-+————-+——-+——+—————+——–+———+——-+——+—————————–+
  | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  +—-+————-+——-+——+—————+——–+———+——-+——+—————————–+
  | 1 | SIMPLE | imgs | ref | userid | userid | 51 | const | 8 | Using where; Using filesort |
  +—-+————-+——-+——+—————+——–+———+——-+——+—————————–+
  1 row in set (0.00 sec)
  嗯,这时可以看到mysql使用了userid这个索引搜索了,用userid索引一次搜索后,结果集有8条。然后虽然使用了filesort一条一条排序,但是因为结果集只有区区8条,效率问题得以缓解。
  但是,如果我用别的userid查询,结果又会有所不同:
  mysql> desc select * from imgs where userid=”admin” order by clicks desc limit 10;
  +—-+————-+——-+——+—————+——–+———+——-+——+—————————–+
  | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  +—-+————-+——-+——+—————+——–+———+——-+——+—————————–+
  | 1 | SIMPLE | imgs | ref | userid | userid | 51 | const | 2944 | Using where; Using filesort |
  +—-+————-+——-+——+—————+——–+———+——-+——+—————————–+
  1 row in set (0.00 sec)
  这个结果和userid=”7mini”的结果基本相同,但是mysql用userid索引一次搜索后结果集的大小达到2944条,这2944条记录都会加入内存进行filesort,效率比起7mini那次来说就差很多了。这时可以有两种办法可以解决,第一种办法是再加一个索引和判断条件,因为我只需要根据点击量取最大的10条数据,所以有很多数据我根本不需要加进来排序,比如点击量小于10的,这些数据可能占了很大部分。
  我对clicks加一个索引,然后加入一个where条件再查询:
  create index clicks on imgs(clicks);
  mysql> desc select * from imgs where userid=”admin” order by clicks desc limit 10;
  +—-+————-+——-+——+—————+——–+———+——-+——+—————————–+
  | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  +—-+————-+——-+——+—————+——–+———+——-+——+—————————–+
  | 1 | SIMPLE | imgs | ref | userid,clicks | userid | 51 | const | 2944 | Using where; Using filesort |
  +—-+————-+——-+——+—————+——–+———+——-+——+—————————–+
  1 row in set (0.00 sec)
  这时可以看到possible_keys变成了userid,clicks,possible_keys是可以匹配的所有索引,mysql会从possible_keys中自己判断并取用其中一个索引来执行语句,值得注意的是,mysql取用的这个索引未必是最优化的。这次查询mysql还是使用userid这个索引来查询的,并没有按照我的意愿,所以结果还是没有什么变化。改一下sql加上use index强制mysql使用clicks索引:
  mysql> desc select * from imgs use index (clicks) where userid=’admin’ and clicks>10 order by clicks desc limit 10
  +—-+————-+——-+——-+—————+——–+———+——+——+————-+
  | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  +—-+————-+——-+——-+—————+——–+———+——+——+————-+
  | 1 | SIMPLE | imgs | range | clicks | clicks | 4 | NULL | 5455 | Using where |
  +—-+————-+——-+——-+—————+——–+———+——+——+————-+
  1 row in set (0.00 sec)
  这时mysql用到了clicks索引进行查询,但是结果集比userid还要大!看来还要再进行限制:
  mysql> desc select * from imgs use index (clicks) where userid=’admin’ and clicks>1000 order by clicks desc limit 10
  +—-+————-+——-+——-+—————+——–+———+——+——+————-+
  | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  +—-+————-+——-+——-+—————+——–+———+——+——+————-+
  | 1 | SIMPLE | imgs | range | clicks | clicks | 4 | NULL | 312 | Using where |
  +—-+————-+——-+——-+—————+——–+———+——+——+————-+
  1 row in set (0.00 sec)
  加到1000的时候结果集变成了312条,排序效率应该是可以接受。
  不过,采用换索引这种优化方式需要取一个采样点,比如这个例子中的1000这个数字,这样,对userid的每个数值,都要去找一个采样点,这样对程序来说是很难办的。如果按1000取样的话,那么userid=’7mini’这个例子中,取到的结果将不会是8条,而是2条,给用户造成了困惑。
  当然还有另一种办法,加入双索引:
  create index userid_clicks on imgs (userid, clicks)
  mysql> desc select * from imgs where userid=”admin” order by clicks desc limit 10;
  +—-+————-+——-+——+———————-+—————+———+——-+——+————-+
  | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  +—-+————-+——-+——+———————-+—————+———+——-+——+————-+
  | 1 | SIMPLE | imgs | ref | userid,userid_clicks | userid_clicks | 51 | const | 2944 | Using where |
  +—-+————-+——-+——+———————-+—————+———+——-+——+————-+
  1 row in set (0.00 sec)
  这时可以看到,结果集还是2944条,但是Extra中的filesort不见了。这时mysql使用userid_clicks这个索引去查询,这不但能快速查询到userid=”admin”的所有记录,并且结果是根据clicks排好序的!所以不用再把这个结果集读入内存一条一条排序了,效率上会高很多。
  但是用多字段索引这种方式有个问题,如果查询的sql种类很多的话,就得好好规划一下了,否则索引会建得非常多,不但会影响到数据insert和update的效率,而且数据表也容易损坏。
  以上是对索引优化的办法,因为原因可能会比较复杂,所以写得比较的长,一般好好优化了索引之后,mysql的效率会提升n个档次,从而也不需要考虑增加机器来解决问题了。
  但是,mysql甚至所有数据库,可能都不好解决limit的问题。在mysql中,limit 0,10只要索引合适,是没有问题的,但是limit 100000,10就会很慢了,因为mysql会扫描排好序的结果,然后找到100000这个点,取出10条返回。要找到100000这个点,就要扫描100000条记录,这个循环是比较耗时的。不知道会不会有什么好的算法可以优化这个扫描引擎,我冥思苦想也想不出有什么好办法。对于limit,目前直至比较久远的将来,我想只能通过业务、程序和数据表的规划来优化,我想到的这些优化办法也都还没有一个是万全之策,往后再讨论。
  2、sql写法过于复杂
  sql写法假如用到一些特殊的功能,比如groupby、或者多表联合查询的话,mysql用到什么方式来查询也可以用desc来分析,我这边用复杂sql的情况还不算多,所以不常分析,暂时就没有好的建议。
  3、配置错误
  配置里主要参数是key_buffer、sort_buffer_size/myisam_sort_buffer_size,这两个参数意思是:
  key_buffer=128M:全部表的索引都会尽可能放在这块内存区域内,索引比较大的话就开稍大点都可以,我一般设为128M,有个好的建议是把很少用到并且比较大的表想办法移到别的地方去,这样可以显著减少mysql的内存占用。
  sort_buffer_size=1M:单个线程使用的用于排序的内存,查询结果集都会放进这内存里,如果比较小,mysql会多放几次,所以稍微开大一点就可以了,重要是优化好索引和查询语句,让他们不要生成太大的结果集。
  另外一些配置:
  thread_concurrency=8:这个配置标配=cpu数量x2
  interactive_timeout=30
  wait_timeout=30:这两个配置使用10-30秒就可以了,这样会尽快地释放内存资源,注意:一直在使用的连接是不会断掉的,这个配置只是断掉了长时间不动的连接。
  query_cache:这个功能不要使用,现在很多人看到cache这几个字母就像看到了宝贝,这是不唯物主义的。mysql的query_cache在每次表数据有变化的时候都会重新清理连至该表的所有缓存,如果更新比较频繁,query_cache不但帮不上忙,而且还会对效率影响很大。这个参数只适合只读型的数据库,如果非要用,也只能用query_cache_type=2自行用SQL_CACHE指定一些sql进行缓存。
  max_connections:默认为100,一般情况下是足够用的,但是一般要开大一点,开到400-600就可以了,能超过600的话一般就有效率问题,得另找对策,光靠增加这个数字不是办法。
  其它配置可以按默认就可以了,个人觉得问题还不是那么的大,提醒一下:1、配置虽然很重要,但是在绝大部分情况下都不是效率问题的罪魁祸首。2、mysql是一个数据库,对于数据库最重要考究的不应是效率,而是稳定性和数据准确性。
  4、机器实在负荷不了
  如果做了以上调整,服务器还是不能承受,那就只能通过架构级调整来优化了。
  1、mysql同步。
  通过mysql同步功能将数据同步到数台从数据库,由主数据库写入,从数据库提供读取。
  我个人不是那么乐意使用mysql同步,因为这个办法会增加程序的复杂性,并常常会引起数据方面的错误。在高负荷的服务中,死机了还可以快速重启,但数据错误的话要恢复就比较麻烦。
  2、加入缓存
  加入缓存之后,就可以解决并发的问题,效果很明显。如果是实时系统,可以考虑用刷新缓存方式使缓存保持最新。
  在前端加入squid的架构比较提倡使用,在命中率比较高的应用中,基本上可以解决问题。
  如果是在程序逻辑层里面进行缓存,会增加很多复杂性,问题会比较多而且难解决,不建议在这一层面进行调整。
  3、程序架构调整,支持同时连接多个数据库
  如果web加入缓存后问题还是比较严重,只能通过程序架构调整,把应用拆散,用多台的机器同时提供服务。
  如果拆散的话,对业务是有少许影响,如果业务当中有部分功能必须使用所有的数据,可以用一个完整库+n个分散库这样的架构,每次修改都在完整库和分散库各操作一次,或定期整理完整库。
  当然,还有一种最笨的,把数据库整个完完整整的做拷贝,然后程序每次都把完整的sql在这些库执行一遍,访问时轮询访问,我认为这样要比mysql同步的方式安全。
  4、使用 mysql proxy 代理
  mysql proxy 可以通过代理把数据库中的各个表分散到数台服务器,但是它的问题是没有能解决热门表的问题,如果热门内容散在多个表中,用这个办法是比较轻松就能解决问题。
  我没有用过这个软件也没有认真查过,不过我对它的功能有一点点怀疑,就是它怎么实现多个表之间的联合查询?如果能实现,那么效率如何呢?
  5、使用memcachedb
  数据库换用支持mysql的memcachedb,是可以一试的想法,从memcachedb的实现方式和层面来看对数据没有什么影响,不会对用户有什么困扰。
  为我现在因为数据库方面问题不多,没有试验过这个玩意。不过,只要它支持mysql的大部分主要的语法,而且本身稳定,可用性是无需置疑的。

rhel5下的yum安装配置方法

  如果用过ubuntu或者debian,一定会知道有apt-get这个命令的,出格的好用。在redhat下默认没有apt,取而代之的是yum这个东东。rhel5(as5)里默认也装有yum,但是那个yum是要有授权才能使用,上哪去找这个授权尚未知晓,所以这里是用rhel的孪生兄弟centos的yum来替换掉原生的yum,虽然看起来不那么正规,但实际上是完全没有问题的,假如真有问题,可以向信息产业部举报。
  先删掉自带的yum:
  rpm -aq|grep yum|xargs rpm -e –nodeps
  下载三个文件并安装:
  wget http://mirrors.163.com/centos/5/os/i386/CentOS/yum-3.2.19-18.el5.centos.noarch.rpm
  wget http://mirrors.163.com/centos/5/os/i386/CentOS/yum-metadata-parser-1.1.2-2.el5.i386.rpm
  wget http://mirrors.163.com/centos/5/os/i386/CentOS/python-iniparse-0.2.3-4.el5.noarch.rpm
  wget http://mirrors.163.com/centos/5/os/i386/CentOS/yum-fastestmirror-1.1.16-13.el5.centos.noarch.rpm
  rpm -ivh python-iniparse-0.2.3-4.el5.noarch.rpm yum-metadata-parser-1.1.2-2.el5.i386.rpm yum-3.2.19-18.el5.centos.noarch.rpm yum-fastestmirror-1.1.16-13.el5.centos.noarch.rpm
  下载配置:
  wget http://sudone.com/download/CentOS-Base.repo -O /etc/yum.repos.d/CentOS-Base.repo
  更新:
  yum update
  可能下载会比较慢,有一个办法可以解决,那就是等…或者可以去寻找快一点的源,不过那消耗的时间会更多。。执行到后面的时候会问yes/no,那是问你要不要更新整个系统,我至今没有选择过yes。
  装一个ImageMagick测测看看?:
  yum install ImageMagick
  试一下搜索:
  yum search kernel
  基本大功告成
  附x86_64:
  wget http://mirrors.163.com/centos/5/os/x86_64/CentOS/yum-3.2.19-18.el5.centos.noarch.rpm
  wget http://mirrors.163.com/centos/5/os/x86_64/CentOS/yum-metadata-parser-1.1.2-2.el5.x86_64.rpm
  wget http://mirrors.163.com/centos/5/os/x86_64/CentOS/python-iniparse-0.2.3-4.el5.noarch.rpm
  wget http://mirrors.163.com/centos/5/os/x86_64/CentOS/yum-fastestmirror-1.1.16-13.el5.centos.noarch.rpm

cacti监控mysql配置

  插件一(可用):
  一,脚本下载以及设置
  wget http://mysql-cacti-templates.googlecode.com/files/mysql-cacti-templates-1.1.2.tar.gz
  tar -xzvf mysql-cacti-templates-1.1.2.tar.gz
  cd mysql-cacti-templates-1.1.2
  cp ss_get_mysql_stats.php /xok.la/cacti/scripts
  可以看到里面有多个监控项目,报告监控apache和nginx.我这只测试mysql,mysql相关的就2个文件:
  模板文件:cacti_host_template_x_db_server_ht_0.8.6i.xml
  插件:ss_get_mysql_stats.php
  修改ss_get_mysql_stats.php 文件 第30行
  $mysql_user = ‘cacti’;
  $mysql_pass = ‘cacti’;
  $cache_dir = “/xok.la/cacti/cache/”;
  设置准备监控的数据库的账户相关信息
  mkdir /xok.la/cacti/cache/
  chown -R vhost.vhost /xok.la/cacti/cache/
  chmod 777 -R /xok.la/cacti/cache/
  默认在获取的数据/tmp/下,会有cacti不能读取的情况。所以放在cacti目录来。
  二,创建监控Mysql需要的账户以及权限
  配置MySQL服务器,让cacti所在机器能够访问MySQL服务器的状态信息,必须拥有”process”权限。如果要监控InnoDB状态,还必须有”SUPER”权限。
  mysql> grant process,super on *.* to ‘cacti’@’%’ identified by ‘cacti’;
  mysql> grant all privileges on cacti.* to cacti@”%” identified by “cacti”;
  三,模板导入
  在cacti管理界面(Import Templates)导入cacti_host_template_x_db_server_ht_0.8.6i.xml。
  四,添加设备
  创建Graph。在Console选项卡下的左侧菜单栏中选择Devices,为要监控的主机新建一个Devices或选择已有Devices。在Associated Graph Templates中添加想要监控MySQL状态的Graph Templates(如X MySQL Connections GT模板)。并点击最上面的Create Graphs for this Host链接,在Graph Templates的选择框中选择X MySQL Connections GT,然后点击Create按钮,出现以下WEB页。
  监控的对象有:
  X InnoDB Buffer Pool Activity GT
  X InnoDB Buffer Pool GT
  X InnoDB I/O GT
  X InnoDB I/O Pending GT
  X InnoDB Insert Buffer GT
  X InnoDB Log GT
  X InnoDB Row Operations GT
  X InnoDB Semaphores GT
  X InnoDB Transactions GT
  X MyISAM Indexes GT
  X MySQL Binary/Relay Logs GT
  X MySQL Command Counters GT
  X MySQL Connections GT
  X MySQL Files and Tables GT
  X MySQL Handlers GT
  X MySQL Network Traffic GT
  X MySQL Processlist GT
  X MySQL Query Cache GT
  X MySQL Query Cache Memory GT
  X MySQL Replication GT
  X MySQL Select Types GT
  X MySQL Sorts GT
  X MySQL Table Locks GT
  X MySQL Temporary Objects GT
  X MySQL Threads GT
  X MySQL Transaction Handler GT
  插件二(可用):
  一,脚本下载
  wget http://www.faemalia.net/mysqlUtils/teMySQLcacti-20060810.tar.gz
  tar -xzvf teMySQLcacti-20060810.tar.gz
  cd teMySQLcacti
  cp mysql_stats.php /xok.la/cacti/scripts/
  cp dumpMemcachedStats.php /xok.la/cacti/scripts/
  二,模板导入
  在cacti管理界面(Import Templates)导入cacti_host_template_temysql_host-step300-heartbeat600.xml 与cacti_host_template_memcached_host-step300-heartbeat600.xml模板文件。
  三,创建监控Mysql需要的账户以及权限
  配置MySQL服务器,让cacti所在机器能够访问MySQL服务器的状态信息,必须拥有”process”权限。如果要监控InnoDB状态,还必须有”SUPER”权限。
  mysql> grant process,super on *.* to ‘cacti’@’%’ identified by ‘cacti’;
  mysql> grant all privileges on cacti.* to cacti@”%” identified by “cacti”;
  四,添加设备
  创建Graph。在Console选项卡下的左侧菜单栏中选择Devices,为要监控的主机新建一个Devices或选择已有Devices。在Associated Graph Templates中添加想要监控MySQL状态的Graph Templates(如teMySQL – Index Usage模板,此套模板是以teMySQL开头的一系列模板)。并点击最上面的Create Graphs for this Host链接,在Graph Templates的选择框中选择teMySQL – Locking and Slow,然后点击Create按钮,出现以下WEB页。
  监控的对象有:
  teMySQL – CPU Usage
  teMySQL – Index Usage
  teMySQL – InnoDB Buffers Pages/Mem
  teMySQL – InnoDB File I/O
  teMySQL – InnoDB InsBuffer
  teMySQL – InnoDB Locks
  teMySQL – InnoDB Row
  teMySQL – Load Average
  teMySQL – Locking and Slow
  teMySQL – Network Usage
  teMySQL – Old Command Stats
  teMySQL – Old Handler Stats
  teMySQL – Query Cache
  teMySQL – Replication
  teMySQL – Select Handler
  teMySQL – Select Queries
  teMySQL – Sorts
  teMySQL – Temporary Objects
  teMySQL – Threads/Abends
  teMySQL – Volatile Handler
  teMySQL – Volatile Queries

mysql双机热备份的实现步骤

  MySQL 提供了数据库的同步功能,这对我们实现数据库的冗灾、备份、恢复、负载均衡等都是有极大帮助的。本文描述了常见的同步设置方法。
同步有两种形式:
"主-从",和"主-主"。
一:"主-从"方式
IXDBA.NET社区论坛
1、准备服务器
由于MySQL不同版本之间的(二进制日志)binlog格式可能会不一样,因此最好的搭配组合是Master的MySQL版本和Slave的版本相同或者更低,Master的版本肯定不能高于Slave版本。
本文中,我们假设主服务器(以下简称Master)和从服务器(以下简称Slave)的版本都是4.1.24,操作系统是Redhat Linux AS4.0
假设
同步Master的主机ip为:192.168.60.219,Slave主机ip为:192.168.60.132,2个MySQL的basedir目录都是/usr/local/mysql,datadir都是:/usr/local/mysql/data(即为mysql数据库的默认数据目录)。
2、设置同步服务器
(1)、设置同步Master
每个同步服务器都必须设定一个唯一的编号,否则同步就不能正常运行了。接下来配置数据库同步配置文件,mysql数据库的配置文件默认名为my.cnf,数据库启动的时候从默认的data目录下读取my.cnf的信息,如果data下没有这个文件,可以建立一个,my.cnf的模板默认一般在mysql/support-files目录下,在此目录下有各种情况下的cnf文件,如my-huge.cnf,my-large.cnf,my-medium.cnf,my-small.cnf等等,根据情况,选择my-medium.cnf即可,然后拷贝到data下,改名为my.cnf.开始修改 my.cnf,增加以下几行:
log-bin
server-id = 1 (标识为master库)
sql-bin-update-same
binlog-ignore-db=mysql
set-variable=binlog-ignore-db=mysql #指定需要日志的数据库
然后在Master上增加一个账号专门用于同步,如下:
mysql>GRANT REPLICATION SLAVE ON *.* TO backup@192.168.60.132 IDENTIFIED BY ‘1234’;
如果想要在Slave上有权限执行 "LOAD TABLE FROM MASTER" 或 "LOAD DATA FROM MASTER" 语句的话,必须授予全局的 FILE 和 Select 权限:
mysql>GRANT FILE,Select,REPLICATION SLAVE ON *.* TO backup@192.168.60.132 IDENTIFIED BY ‘1234’;
上面my.cnf文件中第四行表示不记录数据库mysql的更新日志,这就避免了Master上的权限设置等被同步到Slave上,如果对这方面没有限制,就可以不设置这个参数。
最后设置完成my.cnf,设置完成后,首先检查mysql/data目录下是否有mysql的启动关闭日值,类似的为*.info,localhost*,ib*之类的日值信息。如果有删除,然后在master服务器上启动mysql。可以通过查看data下的localhost.localdomain.err文件,测试master于Slave的连通情况。,同时用show slave status看同步配置情况。
接下来备份Master上的数据,首先执行如下SQL语句:
mysql>FLUSH TABLES WITH READ LOCK;
不要退出这个终端,否则这个锁就不生效了;接着导出数据,可以直接打包压缩数据文件,也可以使用mysqldump工具来做,推荐前者的方法,这样更为快捷简便。
root$cd /usr/local/mysql
root$tar zcf data.tar.gz ./data (在这里也可能是 "var" 等其它实际存放数据文件的目录,根据实情而定)
然后将这些数据拷贝到Slave服务器上,解开,设置好正确的权限及属主等之后, 启动Slave数据库,然后用"UNLOCK TABLES" 语句来释放锁。然后关闭数据库。
(2)、设置Slave
同主数据库一样,找到my.cnf的模板,修给成my.cnf,增加如下几行:
server-id = 2 (Slave服务器标识)
master-host = 192.168.60.219 #主服务器名
master-user = backup #同步账户名,默认是test
master-password =1234 #同步帐户密码,默认是空
master-port = 3306 #主服务器的 TCP/IP 端口号,默认是3306
set-variable=replicate-ignore-db=mysql #略过同步的数据库名,如果有多个,请设置多次
set-variable=replicate-do-db=cicro #想要同步的数据库名,如果有多个,请设置多次。
master-connect-retry=10 预设重试间隔60秒
设置完成后,首先检查mysql/data目录下是否有mysql的启动关闭日值,类似的为*.info,localhost*,ib*之类的日值信息。如果有删除,然后在Slave服务器上启动mysql,然后在Slave上检验一下是否能正确连接到Master上,并且具备相应的权限。
可以通过查看data下的localhost.localdomain.err文件,测试Slave与master的连通情况。
root$mysql -h192.168.60.219 -ubackup -p 1234
mysql>SHOW GRANTS;
+————————————————————————————————————————————–+
| Grants for backup@192.168.60.132 |
+————————————————————————————————————————————–+
| GRANT Select, FILE, REPLICATION SLAVE ON *.* TO ‘backup’@’192.168.60.132’ IDENTIFIED BY PASSWORD ‘*9FF2C222F44C7BBA5CC7E3BE8573AA4E1776278C’ |
+————————————————————————————————————————————–+
现在,重新启动Slave。启动成功后,登录Slave,查看一下同步状态:
mysql -hlocalhost -uroot
mysql>SHOW SLAVE STATUS\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.60.132
Master_User: backup
Master_Port: 3306
Connect_Retry: 10
Master_Log_File: localhost-bin.000002
Read_Master_Log_Pos: 1556
Relay_Log_File: localhost-relay-bin.000004
Relay_Log_Pos: 51
Relay_Master_Log_File: localhost-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB: cicro,cicro
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 1556
Relay_Log_Space: 51
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
1 row in set (0.00 sec)
可以看到,Slave_IO_Running 和 Slave_SQL_Running 两列的值都为 "Yes",这表明 Slave 的 I/O 和 SQL 线程都在正常运行。
至此,主-从同步设定成功。
二:"主-主"方式:
如果在master中加入slave设置,在Slave加入master设置,则就成了"主-主"同步方式。
1:配置master服务器
接着上面的配置,在master的my.cnf中加入一下配置信息:
master-host=192.168.60.132
master-user=backup
master-password=1234
replicate-do-db=cicro
master-connect-retry=10 预设重试间隔60秒
2:配置slave服务器:
首先在slave上增加一个账号专门用于同步,如下:
mysql> GRANT FILE,Select,REPLICATION SLAVE ON *.* TO backup@192.168.60.219 IDENTIFIED BY ‘1234’;
在slave的配置文件my.cnf中添加以下信息:
binlog-do-db=cicro
注意:当有错误产生时检查slave的data目录下*.err日志文件。此时同步的线程退出,当纠正错误后要让同步机制进行工作,运行slave start。
同样,首先删除两台服务器data下的日志信息,然后依次启动slave,master。实现双机互备。
测试:
向slave批量插入大数据量表AA(1872000)条,master数据库每秒钟可以更新2500条数据。

多MASTER自增字段冲突的问题

  You may know about the MySQL Cluster, which is a complex architecture to achieve high availability and performance. One of the advantages of MySQL Cluster is that each node is a peer to the others, whereas in a normal replicating system you have a master and many slaves, and applications must be careful to write only to the master.
  The main disadvantages of MySQL Cluster are (as of MySQL 5.0):
  The database is in memory only, thus requiring more resources than a normal MySQL database. (MySQL 5.1 introduces table spaces, with the capability of storing nonindexed data on disk.)
  Some normal features are not available, such as full-text searches, referential integrity, and transaction isolation levels higher than READ COMMITTED.
  There are some cases where the MySQL Cluster is the perfect solution, but for the vast majority, replication is still the best choice.
  Replication, too, has its problems, though:
  There is a fastidious distinction between master and slaves. Your applications must be replication-aware, so that they will write on the master and read from the slaves. It would be so nice to have a replication array where you could use all the nodes in the same way, and every node could be at the same time master and slave.
  There is the fail-over problem. When the master fails, it’s true that you have the slaves ready to replace it, but the process of detecting the failure and acting upon it requires the administrator’s intervention.
  Fixing these two misfeatures is exactly the purpose of this article. Using features introduced in MySQL 5.0 and 5.1, it is possible to build a replication system where all nodes act as master and slave at the same time, with a built-in fail-over mechanism.
  Setting Up a Multimaster Replication System
  For those of you not well acquainted with the replication basics, I can refer to an earlier article explaining MySQL replication, and the demanding reader can integrate with the dry but extensive official MySQL replication manual.
  Back to business. Consider the situation where you set up a replication system with more than one master. This has been a common scenario over the past several years. Chapters 7 and 8 of Jeremy Zawodny’s High Performance MySQL describe such a solution. At the time of the book’s publication, though, the necessary technology was not yet available.
  One hard-to-solve problem in a multimaster replication is the conflict that can happen with self-generated keys. The AUTO_INCREMENT feature is quite convenient, but in a replication environment it will be disruptive. If node A and node B both insert an auto-incrementing key on the same table, conflicts arise immediately.
  Rescue comes with recent versions. MySQL 5 introduces a couple of server variables for replicated auto-increment that address this specific problem and allow for the creation of an array of peer-to-peer nodes with MySQL replication.
  Quoting from the manual:
  auto_increment_increment controls the increment between successive AUTO_INCREMENT values.
  auto_increment_offset determines the starting point for AUTO_INCREMENT column values.
  By choosing non-conflicting values for these variables on different masters, servers in a multiple-master configuration will not use conflicting AUTO_INCREMENT values when inserting new rows into the same table. To set up N master servers, set the variables like this:
  Set auto_increment_increment to N on each master.
  Set each of the N masters to have a different auto_increment_offset, using the values 1, 2, … , N.
  Using those two variables as described in the manual, you can ensure that all nodes in your replication array will use different sequences of auto-incrementing numbers. For example, using auto_increment_increment = 10 and auto_increment_offset=3, the numbers generated when inserting three records will be 3, 13, 23. Using 10, 7, you’ll get 7, 17, 27, and so on.
  For my four-node array, I set auto_increment_increment to 10 for each node, and auto_increment_offset to 1 in the first node, 2 in the second, and so on.
  This is theoretically clear, but it still isn’t clear how I managed to transform these servers into peer-to-peer nodes.
  The answer is a circular replication, where each node is master of the following node and slave of the preceding one.
  Circular replication with two nodes
  In its simplest form, circular replication has two nodes, where each one is at the same time master and slave of the other (Figure 1).

  Figure 1. Circular replication between two nodes
  For this test, I used two servers in my company (water and air; there will soon be two more, named fire and earth). Their basic configuration is:
  # node A – (water) setup
  [mysqld]
  server-id = 10
  # auto_increment_increment = 10
  # auto_increment_offset = 1
  master-host = air.stardata.it
  master-user = nodeAuser
  master-password = nodeApass
  # node B – (air) setup
  [mysqld]
  server-id = 20
  # auto_increment_increment = 10
  # auto_increment_offset = 2
  master-host = water.stardata.it
  master-user = nodeBuser
  master-password = nodeBpass
  Notice the two magic variables in the configuration files. If you omit such variables (or comment them, as in this example), then something nasty may happen, and the unfortunate circumstances are easy to demonstrate. Remember that MySQL replication is asynchronous. It means that the replication process in the slave can happen at a different time than the one taking place in the master. This feature makes replication more resilient and ensures that even if you suffer a connection breakdown between master and slave, replication will continue when the slave connection resumes. However, this feature has a nasty side effect when you deal with auto-incremented values. Assume that you have a table like this:
  Create TABLE x (
  id int(11) NOT NULL AUTO_INCREMENT,
  c char(10) DEFAULT NULL,
  PRIMARY KEY (id)
  ) ENGINE=MyISAM DEFAULT CHARSET=latin1
  Assume also that the connection between node A and node B breaks for a moment. Suppose you issue an Insert statement in both servers, while the replication is not working and the auto_increment variables are not set:
  [node A] insert into x values (null, ‘aaa’), (null, ‘bbb’), (null, ‘ccc’);
  [node B] insert into x values (null, ‘xxx’), (null, ‘yyy’), (null, ‘zzz’);
  When replication resumes, you get a blocking error in both nodes:
  Error ‘Duplicate entry ‘1’ for key ‘PRIMARY” on query. Default database:
  ’test’. Query: ‘insert into x values (null, ‘aaa’)’
  The reason is easy to discover:
  [node A] select * from x;
  +—-+——+
  | id | c |
  +—-+——+
  | 1 | aaa |
  | 2 | bbb |
  | 3 | ccc |
  +—-+——+
  [node B] select * from x;
  +—-+——+
  | id | c |
  +—-+——+
  | 1 | xxx |
  | 2 | yyy |
  | 3 | zzz |
  +—-+——+
  Both nodes have produced the same primary keys. Thus, when replication resumed, the DBMS justly complained that there was a mistake. Now activate those two variables to see what happens.
  [node A] set auto_increment_increment = 10;
  [node A] set auto_increment_offset = 1;
  [node B] set auto_increment_increment = 10;
  [node B] set auto_increment_offset = 2;
  Clean the errors, delete all the records in the test table, and redo the insertion (after stopping the replication, to simulate a communication breakdown):
  [node A] SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; start slave;
  [node B] SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; start slave;
  [node A] truncate x;
  [node A] stop slave ;
  [node B] stop slave ;
  [node A] insert into x values (null, ‘aaa’), (null, ‘bbb’), (null, ‘ccc’);
  [node B] insert into x values (null, ‘xxx’), (null, ‘yyy’), (null, ‘zzz’);
  Now the situation is different.
  [node A] select * from x;
  +—–+——+
  | id | c |
  +—–+——+
  | 1 | aaa |
  | 11 | bbb |
  | 21 | ccc |
  +—–+——+
  [node B] select * from x;
  +—–+——+
  | id | c |
  +—–+——+
  | 2 | xxx |
  | 12 | yyy |
  | 22 | zzz |
  +—–+——+
  Thus, when replication resumes, there is no conflicting error. This proves it. Choosing appropriate values for the auto_increment_increment and auto_increment_offset server variables prevents conflicts between auto-generated keys in this circular replication setup. QED.