缓存为王:Memcached和MySQL的结合应用

缓存为王:Memcached和MySQL的结合应用

在计算机和网络的世界里,缓存无处不在,从CPU的寄存器到一级缓存二级缓存,从硬盘的文件到阵列卡的缓存到文件的缓存,从浏览器的缓存到web服务器的缓存到数据库的缓存,Cache is King

Memcached是一个分布式的内存缓存系统,在很多大型网站中都有成功的应用案例。设计思想说起来也很简单,服务器端保存精悍而独立,基本上就是一个slab对象缓存管理器,而在客户端实现负载均衡,采用hash算法来选择不同的服务端缓存key-value数据。

FotologFrank同学最近在MySQL官方网站上做了一个Memcached结合MySQL应用的webinar

MySQL命令行的几个用法(续)

继续上一篇的话题,介绍mysql命令行的一些小技巧。

1.以html格式输出结果
使用mysql客户端的参数–html或者-T,则所有SQL的查询结果会自动生成为html的table代码

$ mysql -uroot --html
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3286
Server version: 5.1.24-rc-log MySQL Community Server (GPL)

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> select * from test.test;
<TABLE BORDER=1><TR><TH>i</TH></TR><TR><TD>1</TD></TR><TR><TD>2</TD></TR></TABLE>
2 rows in set (0.00 sec)

2.以xml格式输出结果
跟上面差不多,使用–xml或者-X选项,可以将结果输出为xml格式

$ mysql -uroot --xml
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3287
Server version: 5.1.24-rc-log MySQL Community Server (GPL)

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> select * from test.test;
<?xml version="1.0"?>

<resultset statement="select * from test.test;"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <row>
        <field name="i">1</field>
  </row>
  <row>
        <field name="i">2</field>
  </row>
</resultset>
2 rows in set (0.00 sec)

3.修改命令提示符
使用mysql的–prompt=选项,或者进入mysql命令行环境后使用prompt命令,都可以修改提示符

mysql> prompt \u@\d>
PROMPT set to '\u@\d>'
root@(none)>use mysql
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
root@mysql>

其中\u表示当前连接的用户,\d表示当前连接的数据库,其他更多的可选项可以参考man mysql

MySQL如何获取当前执行的SQL

在MySQL的客户端中通过show [full] processlist可以看到当前所有线程,以及线程的状态,当然也包括执行中的sql,但是显示的语句不完全,并且有很多空闲线程会造成干扰。

这里要介绍一个非常好用的开源工具innotop(sourceforge已经被墙了,要过去先找梯子),由于是用perl写的,所以需要安装相关的perl模块,包括DBIDBD::mysqlTerm::ReadKeyTime::HiRes,这些模块都可以到CPAN找到。

innotop的Q模式则可以完美的解决获取当前运行的SQL的问题。innotop -m Q 或者innotop进入后再按shift+q进入Query list模式:

Query List (? for help) mysql01, 75+03:16:16, 774.20 QPS, 83 thd, 5.1.24-rc-log

CXN    When   Load  QPS     Slow  QCacheHit  KCacheHit  BpsIn    BpsOut
my120  Now    0.00  774.20     0     40.22%    100.00%  207.98k    1.46M
my120  Total  0.00  212.69     2     29.70%    100.00%   56.90k  402.15k

CXN     Cmd    ID      User    Host           DB      Time   Query
mysql01  Query   20936  poster  192.168.1.1    poster  00:00
select a.poster_id, a.pic_id, a.gmt_create, a.gmt_modified, a.url, a.no

然后按e并输入thread ID显示执行计划或者按f显示完整sql语句,或者按o显示系统优化过的语句(需要MySQL的版本支持EXPLAIN EXTENDED)。个人感觉,还是e最有用,其他两个选项,则有点鸡肋了。

Query List (? for help) mysql01, 75+03:16:16, 774.20 QPS, 83 thd, 5.1.24-rc-log
EXPLAIN PARTITIONS
select a.poster_id, a.pic_id, a.gmt_create, a.gmt_modified, a.url, a.notes,
a.type, a.indexed, a.user_id, a.user_nick, b.pic_path
from poster.poster_pic a inner join poster.picture b on
(a.pic_id = b.id) where a.poster_id = 3390 order by a.indexed
______________ Sub-Part 1 ______________  ________ Sub-Part 1 ________
Select Type: SIMPLE                       Select Type: SIMPLE
      Table: a                                  Table: b
 Partitions:                               Partitions:
       Type: ref                                 Type: eq_ref
 Poss. Keys: PRIMARY                       Poss. Keys: PRIMARY
      Index: PRIMARY                            Index: PRIMARY
 Key Length: 4                             Key Length: 8
  Index Ref: const                          Index Ref: poster.a.PIC_ID
  Row Count: 14                             Row Count: 1
    Special: Using where; Using filesort      Special:                

Press e to explain, f for full query, o for optimized query
Query List (? for help) mysql01, 75+03:16:16, 774.20 QPS, 83 thd, 5.1.24-rc-log
select a.poster_id, a.pic_id, a.gmt_create, a.gmt_modified, a.url, a.notes,
a.type, a.indexed, a.user_id, a.user_nick, b.pic_path
from poster.poster_pic a inner join poster.picture b on
(a.pic_id = b.id) where a.poster_id = 3390 order by a.indexed

Press e to explain, f for full query, o for optimized query
Query List (? for help) mysql01, 75+03:16:16, 774.20 QPS, 83 thd, 5.1.24-rc-log
select a.poster_id, a.pic_id, a.gmt_create, a.gmt_modified, a.url, a.notes,
a.type, a.indexed, a.user_id, a.user_nick, b.pic_path
from poster.poster_pic a inner join poster.picture b on
(a.pic_id = b.id) where a.poster_id = 3390 order by a.indexed
Note:
select `poster`.`a`.`POSTER_ID` AS `poster_id`,`poster`.`a`.`PIC_ID` AS
`pic_id`,`poster`.`a`.`GMT_CREATE` AS `gmt_create`,
`poster`.`a`.`GMT_MODIFIED` AS `gmt_modified`,
`poster`.`a`.`URL` AS `url`,`poster`.`a`.`NOTES` AS `notes`,
`poster`.`a`.`TYPE` AS `type`,`poster`.`a`.`INDEXED` AS `indexed`,
`poster`.`a`.`USER_ID` AS `user_id`,`poster`.`a`.`user_nick` AS
`user_nick`,`poster`.`b`.`PIC_PATH` AS `pic_path`
from `poster`.`poster_pic` `a` join `poster`.`picture` `b`
where ((`poster`.`b`.`ID` = `poster`.`a`.`PIC_ID`) and
(`poster`.`a`.`POSTER_ID` = 3390))
order by `poster`.`a`.`INDEXED`

Press e to explain, f for full query, o for optimized query

那么innotop是从哪里取的数据呢?应该是通过information_schema.processlist来获得完整的sql语句,并且根据COMMAND来过滤掉空闲线程的。

mysql> desc information_schema.processlist;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| ID      | bigint(4)   | NO   |     | 0       |       |
| USER    | varchar(16) | NO   |     |         |       |
| HOST    | varchar(64) | NO   |     |         |       |
| DB      | varchar(64) | YES  |     | NULL    |       |
| COMMAND | varchar(16) | NO   |     |         |       |
| TIME    | bigint(7)   | NO   |     | 0       |       |
| STATE   | varchar(64) | YES  |     | NULL    |       |
| INFO    | longtext    | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+
8 rows in set (0.00 sec)

AIX平台升级到Oracle10.2.0.4的几个问题

最近将AIX5306上一个Oracle从9.2.0.6升级到了10.2.0.4,虽然最终升级顺利完成,不过还是碰到了几个小问题,在这里记录一下。

1. plan_table的问题
如果在9i的sys用户下手动执行过$ORACLE_HOME/rdbms/admin/utlxplan.sql脚本建立plan_table,则升级前必须删除。否则执行完升级脚本catupgrd.sql会发现Oracle Database Packages and Types组件一直是invalid的,并且升级脚本的log中有如下错误:

118/44   PL/SQL: ORA-00904: "OTHER_XML": invalid identifier

遇到该错误后,删除plan_table重建也还来得及:

@?/rdbms/admin/utlxplan
@?/rdbms/admin/prvtspao.plb
@?/rdbms/admin/utlrp


2.lock_sga的问题

Oracle10.2.0.4在AIX平台分配共享内存的机制有了一点变化。原来9i使用lock_sga=true是正常的,但是10.2.0.4则无法启动instance,报错:

SQL> startup
ORA-27126: unable to lock shared memory segment in core
IBM AIX RISC System/6000 Error: 1: Not owner

看起来像是权限问题,但是即使给Oracle用户加system组也没有用。后来Oracle解释说需要给Oracle用户赋予两个capability:CAP_BYPASS_RAC_VMMCAP_PROPAGATE,但这两个capabilities是采用大页内存时才需要设置的,这样说10.2.0.4如果lock_sga的话,默认是要采用大页内存的。当然,大页内存的使用还需要os上设置相关参数的,如果os没有设置,oracle应该还是要采用4k的内存页。

#chuser capabilities=CAP_BYPASS_RAC_VMM,CAP_PROPAGATE oracle
#lsuser -a capabilities oracle
oracle capabilities=CAP_BYPASS_RAC_VMM,CAP_PROPAGATE

3.dba_segments和dba_free_space空间计算不一致的问题

select sum(bytes)/1024/1024/1024 from dba_data_files;

SUM(BYTES)/1024/1024/1024
-------------------------
468.554688

select sum(bytes)/1024/1024/1024 from dba_free_space;

SUM(BYTES)/1024/1024/1024
-------------------------
63.3510742

select sum(bytes)/1024/1024/1024 from dba_segments;

SUM(BYTES)/1024/1024/1024
-------------------------
381.477112

显然,468.554688-63.3510742=405.203614,这比从dba_segments算出来的总占用空间381.477112大了20多G,并且这个差距在不断拉大,每天大概相差4G左右。这个问题还在跟Oracle扯皮,不知道他们是否会承认这个是bug。