灌溉梦想,记录脚步

/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 …….

ubuntu(l2tp-ipsec)vpn连接方法

准备所需软件:
racoon
ppp
ipsec-tools
dhcp-client
xl2tpd

配置文件:
1. sudo gedit /etc/racoon/racoon.conf
代码:
log debug;
path pre_shared_key "/etc/racoon/psk.txt";
padding {
maximum_length 20;
randomize off;
strict_check off;
exclusive_tail off;
}
remote anonymous {
exchange_mode main;
doi ipsec_doi;
situation identity_only;
generate_policy on;
proposal_check obey;
proposal {
encryption_algorithm des;
hash_algorithm sha1;
authentication_method pre_shared_key;
dh_group 1;
}
}
sainfo anonymous {
lifetime time 28800 sec;
encryption_algorithm 3des;
authentication_algorithm hmac_md5;
compression_algorithm deflate;
}

2. sudo gedit /etc/racoon/psk.txt
代码:
10.0.255.246 ipsec-vpn
10.0.255.247 ipsec-vpn
10.0.255.248 ipsec-vpn
10.0.191.254 ipsec-vpn
10.0.191.253 ipsec-vpn
137.189.192.201 ipsec-vpn
137.189.192.204 ipsec-vpn

3. sudo gedit /etc/xl2tpd/xl2tpd.conf
代码:
[global]
port = 1701
auth file = /etc/ppp/pap-secrets
[lac connect]
lns = vpn.cuhk.edu.hk
; redial = yes
; redial timeout = 15
; max redials = 5
; hidden bit = yes
require pap = yes
ppp debug = yes
pppoptfile=/etc/ppp/options.xl2tpd

4. sudo gedit /etc/ppp/pap-secrets
代码:
yourID vpn.cuhk.edu.hk yourpassword

5. sudo gedit /etc/ppp/options.xl2tpd
代码:
noauth
lock
debug
mtu 1000
nobsdcomp
nodeflate
noaccomp
nopcomp
novj
defaultroute
replacedefaultroute (可以去掉)
name yourID

6. sudo mkdir /var/run/xl2tpd

启动连接:
sudo /etc/init.d/racoon start
(for archlinux: sudo racoon -f /etc/racoon/racoon.conf)
sudo /etc/init.d/xl2tpd start
(for archlinux: sudo /usr/local/sbin/xl2tpd)
sudo echo "c connect" > /var/run/xl2tpd/l2tp-control

切断连接:
sudo echo "d connect" > /var/run/xl2tpd/l2tp-control
sudo /etc/init.d/xl2tpd stop
sudo /etc/init.d/racoon stop

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条数据。