小题大做

tommy's blog

  DonewsBlog  |  Donews首页  |  Donews社区  |  Donews邮箱  |  我的首页  |  联系作者  |  聚合   |  登录
  93篇文章 :: 0篇收藏:: 28篇评论:: 5个Trackbacks

文章

收藏

相册

发展方向思考

好友链接

存档


正在读取评论……


2006年01月



    摘要:my.cnf完整內容:

CODE:
# MySQL Server Instance Configuration File
# ----------------------------------------------------------------------
# Generated by the MySQL Server Instance Configuration Wizard
#
#
# Installation Instructions
# ----------------------------------------------------------------------    (全文共10223字)——点击此处阅读全文




    摘要:mysql从 3.23.42 开始,InnoDB 包括了 InnoDB 监视器,能输出InnoDB 内部状态的信息,这些数据在性能调优时十分有用,当打开时,监视器能每15秒在服务器端输出数据到标准输出,如果不是从命令行启动的话,这些输出会写入到 .err 文件中,在 Windows 平台上,必须在 DOS 命令行下以 --standalone --console 参数启动。

主要信息包括:

每个激活的事务锁住的表以及记录
事务的锁等待
线程的信号等待
延迟的文件 i/o 请求
缓冲池统计以及删除和插入缓冲合并的活动

启动的命令为:

CREATE TABLE innodb_monitor(a int) type = innodb;

停止的语法是:
DROP TABLE innodb_monitor;

如果数据库关闭时,监视器还在运行,下次启动监视器前必须先关闭。

用同样的语法你可以启动 innodb_lock_monitor    (全文共535字)——点击此处阅读全文



之前写了一个简单的MGM node上的config.ini的说明.这里把整个配置方法补充完成.

在MySQL Cluster中,我们需要每个node/host上都要写1个configuration文件.
• 每个data node or SQL node都需要有一个my.cnf文件, 其中包含了2条有用的连接信息:
一个connectstring告诉节点去何处寻找MGM node,还有一个告诉MySQL server 在本机上运行NDB模式.

•management node需要一个config.ini文件,记载了他需要维护多少个replicas,在每个data node上,需要给data和indexes分配多少内存,去何处寻找data nodes,每个data node上要把data存放在何处,去何处发现任何的SQL nodes.

配置Storage node和SQL Nodes

data nodes 的my.cnf 相当简单. 该文件应该位于/etc目录,并且可以很简单的编辑,例如:

vi /etc/my.cnf

每个data node和SQL node上的my.cnf应该如下所写:

# Options for mysqld process:
[MYSQLD]
ndbcluster # run NDB engine
ndb-connectstring=192.168.0.10 # location of MGM node

# Options for ndbd process:
[MYSQL_CLUSTER]
ndb-connectstring=192.168.0.10 # location of MGM node

配置Management Node

配置MGM node首先:(running as root):
mkdir /var/lib/mysql-cluster
cd /var/lib/mysql-cluster
vi config.ini

config.ini 文件的推荐设置如下:

# Options affecting ndbd processes on all data nodes:
[NDBD DEFAULT]
NoOfReplicas=2 # Number of replicas
DataMemory=80M # How much memory to allocate for data storage
IndexMemory=18M # How much memory to allocate for index storage

# For DataMemory and IndexMemory, we have used the
# default values. Since the "world" database takes up
# only about 500KB, this should be more than enough for
# this example Cluster setup.

# TCP/IP options:
[TCP DEFAULT]
portnumber=2202 # This the default; however, you can use any
# port that is free for all the hosts in cluster
# Note: It is recommended beginning with MySQL 5.0 that
MySQL Cluster
# you do not specify the portnumber at all and simply allow
# the default value to be used instead

# Management process options:
[NDB_MGMD]
hostname=192.168.0.10 # Hostname or IP address of MGM node
datadir=/var/lib/mysql-cluster # Directory for MGM node logfiles

# Options for data node "A":

[NDBD]
# (one [NDBD] section per data node)
hostname=192.168.0.30 # Hostname or IP address
datadir=/usr/local/mysql/data # Directory for this data node's datafiles


# Options for data node "B":
[NDBD]
hostname=192.168.0.40 # Hostname or IP address
datadir=/usr/local/mysql/data # Directory for this data node's datafiles

# SQL node options:
[MYSQLD]
hostname=192.168.0.20 # Hostname or IP address
# (additional mysqld connections can be
# specified for this node for various
# purposes such as running ndb_restore)
(NOTE: The "world" database can be downloaded from http://dev.mysql.com/doc/ where it can be
found listed under "Examples".)

Once all the configuration files have been created and these minimal options have been specified,
you are ready to proceed with starting the cluster and verifying that all processes are running.

Note: The default port for Cluster management nodes is 1186; the default port for data nodes is
2202. Beginning with MySQL 5.0.3, this restriction is lifted, and the cluster will automatically allocate
ports for data nodes from those that are already free.




apache限制并发数,IP,带宽设置

限制并发数
下载模块:

到官方网址: http://www.nowhere-land.org/programs/mod_vhost_limit/下载模块

http://www.nowhere-land.org/programs/mod_vhost_limit/mod_vhost_limit-0.4.tar.gz

安装:
apxs -c mod_vhost_limit.c -o /path/to/libexec/mod_vhost_limit.so

在 httpd.conf 加入:

LoadModule vhost_limit_module libexec/mod_vhost_limit.so
AddModule mod_vhost_limit.c

配置:

MaxClients 150
ExtendedStatus On

NameVirtualHost *

<VIRTUALHOST * />
    ServerName       server1
    DocumentRoot     /some/where/1
    MaxVhostClients  100


<VIRTUALHOST * />
    ServerName       server2
    DocumentRoot     /some/where/2
    MaxVhostClients  30


<VIRTUALHOST * />
    ServerName       server3
    DocumentRoot     /some/where/3


其中: server1 被限制为 100 个并发线程数。 server2 被限制为 30 个并发线程数。 server3 没有被限制。

注:需 mod_status 的 ExtendedStatus On 支持!!

如超出限制的并发数在客户端就会出现503错误 
----------------------------------------------------------------------------------------------

限制IP连接数

到这里下载模块 http://dominia.org/djao/limit/mod_limitipconn-0.04.tar.gz

安装:
tar zxvf mod_limitipconn-0.04.tar.gz
cd mod_limitipconn-0.04
make APXS=/usr/local/apache/bin/apxs  ß-----这里要按你自己的路径设置
make install APXS=/usr/local/apache/bin/apxs ß-----这里要按你自己的路径设置

编辑httpd.conf
添加
全局变量:
  < IfModule mod_limitipconn.c >
      < Location / >   # 所有虚拟主机的/目录
          MaxConnPerIP 3     # 每IP只允许3个并发连接
          NoIPLimit image/*  # 对图片不做IP限制
    < /Location >

  < Location /mp3 >  # 所有主机的/mp3目录
    MaxConnPerIP 1         # 每IP只允许一个连接请求    
    OnlyIPLimit audio/mpeg video    # 该限制只对视频和音频格式的文件
    < /Location >
< /IfModule >

  

或者虚拟主机的:
< VirtualHost xx.xxx.xx.xx > ##ip 地址
    ServerAdmin easy@phpv.net
    DocumentRoot /home/easy
    ServerName www.phpv.net
  < IfModule mod_limitipconn.c >
      < Location / >    
      MaxConnPerIP 5        
          NoIPLimit image/*      
      < /Location >
      < Location /mp3 >    # 所有主机的/mp3目录
      MaxConnPerIP 2         # 每IP只允许一个连接请求    
      OnlyIPLimit audio/mpeg video # 该限制只对视频和音频格式的文件
      < /Location >
  < /IfModule >
  < /VirtualHost >
 
----------------------------------------------------------------------------------------------

限制带宽:

下载模块 ftp://ftp.cohprog.com/pub/apache/module/1.3.0/mod_bandwidth.c
安装:
/usr/local/apache/bin/apxs -c ./mod_bandwidth.c -o /usr/local/apache/libexec/mod_bandwidth.so  
 

<-------以上/usr/local/apache请设置为你的路径

编辑httpd.conf
添加:
 LoadModule bandwidth_module libexec/mod_bandwidth.so
AddModule mod_bandwidth.c
重启你的apache
----------------------------------------------------------------------------------------------

给大家推荐两个Apache模块,一个是mod_limitipconn,用来控制Apache的并发联接数,通过该模块可以限制同一来源IP的并发联接数。另一个模块是bw_mod,用于Apache网站带宽控制,可以根据来源IP,网段来划分带宽,也可以根据网站文件类型来限制带宽,参数比较灵活,可以根据自己实际情况进行调整。
mod_limitipconn官方网址为:http://dominia.org/djao/limitipconn.html
mod_mod官方网址为:http://ivn.cl/apache/
具体安装及配置过程就不介绍了,可以参见官方使用说明,这里只简单地谈谈使用心得。
一、对于mod_limitipconn,其实该模块不仅提供客户端并发联接数的控制能力,从安全角度来说还可以起到对抗固定来源IP地址发起的 DOS攻击,包括来源固定的大量访问请求型攻击(大量GET或POST请求型的攻击),当同一来源IP地址的联接数超过限定的值后,会弹回对方的访问请求,给对方一个“503服务临时无效”的响应。当Apache服务器受到大量的访问请求型攻击的时候,由于大量的Apache进程及PHP和MYSQL运行消耗,会导致服务器资源迅速耗尽,网站打开缓慢或瘫痪。如果是此种类型的攻击,使用mod_limitipconn模块则可以有效地提升服务器的抗攻击能力,因为大量的请求被弹回,节省了服务器运行PHP及MYSQL的性能消耗。当然只要请求进了80端口,不管是接受还是弹回请求,Aapche都有运行成本,所以此方法只能是减轻而无法解决,毕竟应用层的处理效率是比较低的。
二、对于网站访问量比较大、使用了mod_limitipconn模块且限制同一客户端并发联接数低于3的情况下,如果用Apache默认的配置参数,极可能经常出现“服务临时无效”的提示。因为Apache默认是设置“KeepAlive on”,且“KeepAliveTimeout 180”,所以一旦建立联接,那么在3分钟内这个联接是不会被释放的。所以如果网站不同页面点击频率比较高或图片资源比较多的话,会经常出现服务临时无效的提示。那么有两种方式去解决,一是加大并发联接数的量,比如设置为普通站点10个并发联接数,图片站点则20个。另一种方式就是如果你不想加大这个值的话,可以设置KeepAlive为off,然后缩短Timeout时间,这样联接会很快被释放出来。具体情况根据需要去调整测试,以得到一个最适合自己站点情况的值。
三、如果要同时限制并发联接数与带宽的话,就用bw_mod+mod_limitipconn,因为虽然bw_mod也可以控制并发联接数,但他是针对某个目录或整个网站的并发联接数,是用来控制服务器端的总联接数,比如设置MaxConnection all 1000,那么这个网站所能接受的最大并发联接数为1000,而并不是限制每一客户端的并发联接数,而mod_limitipconn则是针对同一来源 IP的客户端的并发联接数,所以这两者的联接数限制是有所区别的。
四、个人感觉用了bw_mod及mod_limitipconn模块后,网站访问速度有所下降,能凭直观地感觉出来,并且CPU的负载有所上升。特别是在网站访问量比较大的情况下,这两个模块会消耗一定的主机性能,所以轻重权衡这个得大家自己根据情况来采用了。另外bw_mod里有个参数是用来设置控制精度与频率的,默认是1000毫秒,如果你想提高带宽控制精度就改小这个数值,但会消耗更多的CPU资源,反之亦然,降低精度可提升性能。





    摘要:

首先,download the file mysql-max-5.1.3-alpha-pc-linux-gnu-i686.tar.gz

A. Storage and SQL Node Installation

1.

groupadd mysql
useradd -g mysql mysql

2.

cd /var/tmp       (假设download到此目录)
tar -xzvf -C /usr/local/bin mysql-max-5.1.3-alpha-pc-linux-gnu-i686.tar.gz
ln -s /usr/local/bin/mysql    (全文共1670字)——点击此处阅读全文





    摘要:一个sample config.ini
代码:
# This file is placed in the start directory of ndb_mgmd,
# the management server.

[COMPUTER DEFAULT]

[DB DEFAULT]
NoOfReplicas: 2
#设置复制的个数,这个同时也决定一个node group的成员个数

[API DEFAULT]

[MGM DEFAULT]
Arbitration Rank: 2
#暂时不知道干啥的

[TCP DEFAULT]
PortNumber: 28002
#这个是各个cluster node的连接端口

[COMPUTER]
Id: 1
Hostname: ndb_mgmd.mysql.com
#定义cluster中的计算机id,和他的计算机名,可以是ip

[COMPUTER]
Id: 2
HostName: ndb    (全文共1782字)——点击此处阅读全文




    摘要:

一、介绍

这篇文档旨在介绍如何安装配置基于2台服务器的MySQL集群。并且实现任意一台服务器出现问题或宕机时MySQL依然能够继续运行。
注意!
虽然这是基于2台服务器的MySQL集群,但也必须有额外的第三台服务器作为管理节点,但这台服务器可以在集群启动完成后关闭。同时需要注意的是并不推荐在集群启动完成后关闭作为管理节点的服务器。尽管理论上可以建立基于只有2台服务器的MySQL集群,但是这样的架构,一旦一台服务器宕机之后集群就无法继续正常工作了,这样也就失去了集群的意义了。出于这个原因,就需要有第三台服务器作为管理节点运行。
另外,可能很多朋友都没有3台服务器的实际环境,可以考虑在VMWare或其他虚拟机中进行实验。
下面假设这3台服务的情况:
 Server1: mysql1.vmtest.net 192.168.0.1
 Server2: mysql2.vmtest.net 192.168.0.2
 Server3: mysql3.vmtest    (全文共6745字)——点击此处阅读全文



以下是一个我已经调试通过的PHP调用mysql存储过程测试用例,供大家参考:

mysql :

delimiter $
mysql> CREATE PROCEDURE `sp_insert_aa`(in id int(10),in title varchar(20),in del_id int(10),out counts int(4))
    -> begin
    -> insert into aa(id,title) values(id,title);
    -> delete from aa where aa.id=del_id;
    -> select count(*) into counts from aa;
    -> end$

delimiter ;

PHP codes:

<?php
$id = !$_GET['id']?1:$_GET['id'];
$title = empty($_GET['title'])?'empty':$_GET['title'];
$delid = empty($_GET['del_id'])?0:$_GET['del_id'];

$con = mysql_connect('SERVER','USER','PWD');
 if (!(mysql_select_db('DBname',$con)) || !$con)
 {
  die("mysql server has occurs an error...");
 }
 mysql_query(="set @counts",$con);
 $sql = "call sp_insert_aa('".$id."','".$title."','".$delid."',@counts)";
 mysql_query($sql,$con);
 
 $affected_rows = mysql_affected_rows();
 if($affected_rows < 0)
 {
  echo "insert nothing!";
  return FALSE;
 } 

 $result = mysql_query("select @counts",$con);
 $row = mysql_fetch_row($result); 
 $c = $row[0];
 
 echo "counts is ".$c;
 return TRUE;
?>





    摘要:存储过程和函数是MySql5.0刚刚引入的。关于这方面的操作在PHP里面没有直接的支持。但是由于Mysql PHP API的设计,使得我们可以在以前的PHP版本中的mysql php api中支持存储过程和函数的调用。

在php中调用存储过程和函数。

   1。调用存储过程的方法。

      a。如果存储过程有 IN/INOUT参数,声明一个变量,输入参数给存储过程,该变量是一对,

      一个php变量(也可以不必,只是没有php变量时,没有办法进行动态输入),一个Mysql

        变量。

      b。如果存储过程有OUT变量,声明一个Mysql变量。

&    (全文共2621字)——点击此处阅读全文



14.2. Design for Performance

The right place to start planning for the required performance is in the design process. You should avoid belated code optimization, which could lead to unwanted side effects, bugs, or code that is harder to read and maintain.
Although the design gives you a more abstract impression of your application, you need to align it with constraints, such as hardware capacity or operational budgets, as well as the scaling characteristics you want and the expected amount of initial traffic.
Whether you are a cowboy coder or process geek, this section contains useful information because this chapter discusses designing PHP 5 applications in particular.

14.2.1. PHP Design Tip #1: Beware of State

This is the first design rule because avoiding a server-side state between requests as far as possible is helpful to scaling your application. State is information carried over from one request to the next, ranging from simple things such as a user id and password, to more complex requests such as the user's progress in a multi-page form.
Of course, an application without any kind of state would be useless; this design rule is about moving state to the right place rather than eliminating it. This allows you to scale your application efficiently by simply adding servers as traffic grows.
14.2.1.1 Session State
The most common form of a server-side state is sessions, where the browser obtains a cookie that refers to information stored on the server. By default, PHP stores session information in local files, so when you deploy that second server, each session may end up having different information stored on each server, as shown in Figure 14.1.

Figure 14.1. Locally stored session data (state) causes problems after you go beyond one server.

This application is running on two servers that are load balanced by a simple round-robin rule in the router. Both use the default (file) storage back-end for PHP sessions. The user's browser first sends a request (Request1) that is redirected to Web Server 1, along with the session id "1234abc…" When Web Server 1 responds, the session variables a and b have the values 1 and 2, respectively. Then, the browser sends another request (Request2) that the load balancer sends to Web Server 2. However, this server has different values stored for the session variables a and b, so the user receives a different result. In fact, the result may vary every time the user reloads the page.
14.2.1.2 Isolating State
So, how do you fix this problem? One possibility is to store data in the user's browser via cookies. Doing so would avoid the entire state issue on the server side, but you should not store any confidential information in cookies. Cookies are easily faked and stored in plain-text files on the user's computer.
The other option is to isolate the data comprising the state on the server side. You can store the session data in a database on a dedicated server, or use a dedicated session back-end server such as msession. Figure 14.2 shows how this architecture would look using a custom session handler that stores session data in a MySQL database on a different machine.

Figure 14.2. Session data is moved off web server machines, which allows you to scale by adding hardware.

This makes the database server the single point of failure, but you can at least handle replication and failover for the database separate from scaling web servers.

14.2.2. PHP Design Tip #2: Cache!

Caching is a great way to reduce the response time of your site. By having caching in mind during the design phase, you can layer your application so that adding caching is straightforward. When you design for caching, consider issues like expiration schemes from the beginning rather than hacking it in as an afterthought.
Figure 14.3 shows a high-level diagram of an application separated into a Database Server, an Application Logic layer, and a Display Logic layer.

Figure 14.3. A cleanly layered web application.

Here, the Database Server includes the database itself (such as MySQL or Oracle). The Application Logic layer hides SQL and database details behind a PHP-based API. Finally, the Display Logic layer interfaces the user, manages forms and templates, and communicates with the database through the Application Logic layer.
You may add caching between every layer of your application, as shown in Figure 14.4.

Figure 14.4. A cleanly layered application with a cache between each layer.

This design captures four distinct types of cache functionality:
  • Database query/result caching
  • Call/return value caching
  • Template caching/code generation
  • Output caching
14.2.2.1 Database Query/Result Caching
Caching the results of database queries can speed up your site and reduce the load on the database server. The biggest challenge is to determine the best caching strategy. Should you cache the results from every single query? Do you know in advance which queries are going to be expensive?
The following example demonstrates an approach to this using the Cache_DB class, which is part of the Cache pear package. It wraps a DB connection object inside a proxy object that intercepts query() calls and uses a Strategy pattern to determine a caching strategy for each query:
<?php

require_once ''DB.php'';
require_once ''Cache/DB.php'';

abstract class QueryStrategy
{
    protected $cache;
    abstract function query($query, $params);
}

class Cache1HourQueryStrategy extends QueryStrategy
{
    function __construct($dsn, $cache_options) {
        $this->cache = new Cache_DB(''file'', $cache_options, 3600);
        $this->cache->setConnection($dsn);
    }

    function query($query, $params = array()) {
        $hitmiss = $this->cache->isCached(md5($query), ''db_cache'') ? " HIT" : "MISS";
        print "Cache 1h $hitmiss: $query\n";
        return $this->cache->query($query, $params);
    }
}

class Cache5MinQueryStrategy extends QueryStrategy
{
    function __construct($dsn, $cache_options) {
        $this->cache = new Cache_DB(''file'', $cache_options, 300);
        $this->cache->setConnection($dsn);
    }

    function query($query, $params = array()) {
        $hitmiss = $this->cache->isCached(md5($query), ''db_cache'') ? " HIT" : "MISS";
        print "Cache 5m $hitmiss: $query\n";
        return $this->cache->query($query, $params);
    }
}

class UncachedQueryStrategy extends QueryStrategy
{
    function __construct($dsn) {
        $this->cache = DB::connect($dsn);
    }

    function query($query, $params = array()) {
        print "Uncached:      $query\n";
        return $this->cache->query($query, $params);
    }
}

class QueryCacheStrategyWrapper
{
    private $cache_1h = null;
    private $cache_5m = null;
    private $direct = null;

    function __construct($dsn) {
        $opts = array(
            ''cache_dir'' => ''/tmp'',
            ''filename_prefix'' => ''query'');
        $this->cache_1h = new Cache1HourQueryStrategy($dsn, $opts);
        $this->cache_5m = new Cache5MinQueryStrategy($dsn, $opts);
        $this->direct = new UncachedQueryStrategy($dsn);
    }

    function query($query, $params = array()) {
        $obj = $this->cache_5m;
        $re = ''/\s+FROM\s+(\S+)\s*((AS\s+)?([A-Z0-9_]+))?(,*)/i'';
        if (preg_match($re, $query, $m)) {
            if ($m[1] == ''bids'') {
                $obj = $this->direct;
            } elseif ($m[5] == '','') { // a join
                $obj = $this->cache_1h;
            }
        }
        return $obj->query($query, $params);
    }

    function __call($method, $args) {
        return call_user_func_array(array($this->dbh, $method), $args);
    }
}

$dbh = new QueryCacheStrategyWrapper(getenv("DSN"));

test_query($dbh, "SELECT * FROM vendors");
test_query($dbh, "SELECT v.name, p.name FROM vendors v, products p".
           " WHERE p.vendor = v.id");
test_query($dbh, "SELECT * FROM bids");

function test_query($dbh, $query) {
    $u1 = utime();
    $r = $dbh->query($query);
    $u2 = utime();
    printf("elapsed: %.04fs\n\n", $u2 - $u1);
}

function utime() {
    list($usec, $sec) = explode(" ", microtime());
    return $sec + (double)$usec;
}

The QueryCacheStrategyWrapper class implements the Strategy wrapper, and uses a regular expression to determine whether the query should be cached and if it should be cached for five minutes or one hour. If the query contains a join across multiple database tables, it is cached for one hour; if it is a SELECT on the bids table (for an auction), the query is not cached. The rest will be cached for five minutes.
Here is the output from this example the first time the queries are run, and the results are not cached:
Cache 5m MISS: SELECT * FROM vendors
elapsed: 0.0222s

Cache 1h MISS: SELECT v.name, p.name FROM vendors v, products p WHERE p.vendor = v.id
elapsed: 0.0661s

Uncached:      SELECT * FROM bids WHERE product = 42
elapsed: 0.0013s

As you can see, the join is relatively expensive compared to the other queries. Now, look at the timings on the second run:
Cache 5m MISS: SELECT * FROM vendors
elapsed: 0.0098s

Cache 1h MISS: SELECT v.name, p.name FROM vendors v, products p WHERE p.vendor = v.id
elapsed: 0.0055s

Uncached:      SELECT * FROM bids WHERE product = 42
elapsed: 0.0015s

The cache gave a 125 percent speed-up for the first query, and a whopping 1,100 percent speed-up for the join.
A good exercise to complete after reading the APD section, "Profiling with ADP," later in this chapter would be to adapt the caching strategy in your own database (just change the "bids" table name), and use APD to compare the performance of the wrapped caching solution with a regular non-caching approach.
14.2.2.2 Call Caching
Call caching means caching the return value of a function given a set of parameters. Both the Cache and Cache_Lite pear packages provide this. Chapter 11, "Important pear Packages," contains an example of call caching.
14.2.2.3 Compiled Templates
Most template systems today compile templates to PHP code before displaying them. This not only makes the template display faster, but it also allows an opcode cache to cache them between requests so they do not need to be parsed on every request.
The only template packages in pear that do not compile to PHP code are HTML_Template_IT and HTML_Template_PHPLIB. If you use one of the others, such as Smarty or HTML_Template_Flexy, everything will be taken care of for you.
14.2.2.4 Output Caching
Finally, you may cache the printed output of an entire script or just parts of it using PHP's output buffering functions. Again, the pear caching packages have wrappers in place for output caching. See the Cache_Lite example in Chapter 11.

14.2.3. PHP Design Tip #3: Do Not Over Design!

With PHP 5's new OO features, it is easier to make clean object-oriented designs. PHP has a vast amount of built-in functions and functions provided by various extensions, most of which are procedural (calling functions rather than working with objects).
14.2.3.1 OO Wrappers for Built-In Functions
To make interfaces "cleaner," it may be tempting to wrap a class layer around built-in functions. Unless these wrappers provide real value, they just add bloat and complexity. "Real value" could be providing a unified API to different extensions (similar to, for example, pear DB), or it could be adding new, higher-level functionality (similar to pear Net_Socket).
14.2.3.2 Generalize Carefully
Generalization is expensive (saying it is cheap). Know why you make something more general or abstract, and think about what you expect to gain from doing it. If you add abstractions without knowing exactly why you need them, chances are you are making another abstraction that you need further down the road.
14.2.3.3 Do Not Pretend PHP Is Java!
PHP and languages such as Java or C++ are vastly different. One thing is that PHP is compiled at runtime, but PHP has a huge amount of low-level, built-in functionality that Java provides through higher-level packages. Even though PHP 5 has a vastly improved object model, object instantiation in Java is several times faster than in PHP. Java has String objects, while PHP has a string type. Java has a Vector class, and PHP has arrays. Writing a Vector class for PHP could be interesting as an exercise, but for production use, it is just silly because PHP has built-in functionality for doing the same thing much faster.
PHP applications need to be designed as PHP applications that accommodate PHP's different strengths and weaknesses.



视图,就是把数据库中单个表或多个用JOIN连接起来的表中的数据,通过提取并生成到一个新窗口的方式提供给用户察看的一种功能。数据库开发和管理人员广泛使用视图功能主要基于如下两个原因:

对数据库安全的管理

-视图可以通过隐藏元表中的某些敏感信息列来帮助保护敏感数据,这些元表可以是单个实际表,或 者是JOIN表,通过限制从这些元表中可以返回的实际的数据行,或解密已保存在磁盘上的加密数据来实现对数据库的安全 管理。

优化数据库的性能

-视图可以用来帮助调优数据库性能,就是通过预定义一个微调过的JOIN条件建立的多表视图,或通过限制只允许少量数据从巨大的数据库表中返回来实现。

MySQL5所支持的视图功能在一定条件下可以实现使 用视图来执行某些UPDATE语句,使那些数据可以得到更新,下面举例说明:

mysql> select * from customer;
+-------------+---------------------+--------------------+------------------+
| customer_id | customer_first_name | customer_last_name | customer_ssn     |
+-------------+---------------------+--------------------+------------------+
|           1 | fred                | smith              | ☼Q,U¶  ¢ƒ╠▒4╨☺ö| 
+-------------+---------------------+--------------------+------------------+ 
1 row in set (0.03 sec)

mysql> create view v_customer as t_name,
    -> select customer_id, customer_first_name, customer_last_name
    -> aes_decrypt(cusomer_ssn,'password') as customer_ssn
    -> from customer; 
Query OK, 0 rows affected (0.03 sec)

mysql> select * from v_customer;
+-------------+---------------------+--------------------+--------------+
| customer_id | customer_first_name | customer_last_name | customer_ssn |
+-------------+---------------------+--------------------+--------------+
|           1 | fred                | smith              | 456097234    |
+-------------+---------------------+--------------------+--------------+
从上例可以看到,通过使用解密函数aes_decrypt()得到指定的customer_ssn的值并利用创建视图的方式把该值显示出来,而且 并未破环原始表对其他customer_ssn值在磁盘或数据库的加密式存放。这样管理人员就保证敏感信息不会被随意破坏。



第一节 数据库集群技术的现状

目前数据库集群系统应用得比较成功,应用范围比较广泛的是:Oracle公司的Oracle9与IBM公司DB2。Oracle9采用Shared-storage的技术,DB2选择了Shared-nothing的技术,二者各有长短。
最新的数据库集群系统的理论基础是分布式计算,将数据分布到每个节点,所有的计算节点并行处理数据,将结果汇总。这样的方式无疑是最完美的。但是目前仍然不能实现全部的功能。


对于Shared-storage以及Shared-nothing的技术请参考Oracle以及IBM网站上的相关资料。
第二节 目前数据库应用状况

目前数据库应用状况大致分为两类,第一类是数据量在100G以下,数据库访问频繁,请求密集。主要是Web APP类型的应用,例如:网站,论坛等。这些Web APP类型的应用访问数据库的特点是:访问频繁,数据库每秒钟要接受几千次以上的查询,需要经常追加数据,同时对数据的响应速度要求比较高。另一类是用于科学计算、存储历史数据的应用,数据量往往达到几百G。这些应用访问数据库的特点是:多为查询操作,数据都是分批、定时、集中倒入数据库,数据库的记录非常多,积累了大量的数据,对数据库的响应速度没有太高要求。
第三节 暴露出来的问题

第一类应用,由于访问比较频繁,而且为了支持更多的访问,Web Server一般都使用了负载均衡的集群,但是对于数据库来说,由于无法实现集群操作,每秒钟的请求不断增加,随着服务器负载的增加,响应单个请求的速度越来越慢,如果库文件比较大,出现写操作的时候还会出现锁表时间过长等影响访问效率的事情。
第二类应用,主要是数据文件太大,每次处理数据都需要大量的时间,如果写错一个语句就需要花几个小时来重做查询。
第四节 如何解决

首先应当从硬件、软件、程序、索引、SQL语句这几个方面进行优化,如果仍然不能解决问题,我们就要考虑数据库系统的集群(并行处理)了。
对于第一类的应用,在数据库服务器正常运行,负载不高的情况下,应用对数据库系统的状况还是满意的。但是数据库系统负载过高之后,就会出现完成请求的时间加长,达不到系统的要求时间。既然负载是由于过多的请求造成的,我们就采取分担请求的方式,让一部分的请求去访问另外一台服务器,让单台服务器的负载降低,从而解决问题。
对于第二类的应用,就需要分布式计算的系统来解决了,一般的系统是无能为力了。
第五节 针对于"Linux+Apache+PHP+MySQL"的第一类应用问题的解决方式

一个实际案例的解决:
我在工作当中遇到了这样的问题,我们的Web Server是Linux+Apache+Php的三台机器组成的集群,MySQL运行在SUN450,2G内存的平台上。由于WEB的访问量在高峰的时候几乎满负荷运转,LoadAvg(就是一分钟之内处于Running状态的进程数量)都在10-20之间,反映出来就是大量的请求都在访问数据库的时候被挂住了,导致一个请求没有完成,下一个请求又进来,最后恶性循环。LoadAvg会在瞬间飙升至800以上。数据库那边就更糟糕了,LoadAvg达到 300多,数据库的线程非常多,CPU忙于切换线程状态,这个时候除非Restart MySQL,否则怎么都不会好。在对SQL语句优化完成后还是不能很好的解决问题,我们增加了一台数据库服务器,通过MySQL的数据同步机制,让两台数据库上的数据保持同步,修改了一部分只会发生读取操作的php程序,让这些程序连接另外一台数据库,算是把负载分离出去一部分,问题得到了初步的解决。但是后来业务做大,我们又增加了多台服务器,修改了很多程序,分离他们对数据库的读取操作,访问不同的服务器。
第六节 MySQL-HA-Proxy方案的提出

通过修改程序的方式实现将系统的负载分离,是件很痛苦的事情,工程浩大,而且不能弄错,因为除了主服务器可以写入、修改数据,而其它的服务器只能通过数据同步更新自身的数据,所以如果你对那些数据库进行了写操作,结果将是灾难性的。
如果我们能够有一个程序分拣SQL语句,根据他的类型(读取/写入),分别传送给不同的服务器,然后再将结果返回。采用一种类似HTTP的PROXY的方式,这样我们就不需要通过修改源程序的方式来分担负载了,如果再能够根据服务器的负载状况,或者是表的状态(可用/锁定),来判断应该将这个请求分配到哪台服务器,那就比我们修改源程序所能达到的效果还要好。
第七节 MySQL Client 与 Server之间如何通信

四处寻找,也没有找到一篇关于Mysql通讯协议的文章,看来只有分析Mysql的源程序了。于是找来mysql 3.23.49的代码,打开sniffer工具。MySQL的通讯协议可能变更过多次,在3.23.49的版本里面,通讯协议的版本竟然是10。
简单的分析了一下通讯协议,现在规整如下,有些地方还不是很完善,由于我实在没有太多的时间仔细研读mysql的代码,目前我只了解到了这些。
Server 对 Client 请求的响应数据格式:
偏移区域类型长度(byte)说明
0HEADData Length3
1
2
3FLAG1=0普通信息
=1多段信息
=2认证返回
>2段结束字
4DATACMD Code1
5MessageDataLength - 1
当FLAG=0 , 2的时候 CMD Code 与 Message 的定义
CMDCode类型Message的结构
00状态码偏移类型Length(byte)
0Affect rows2
0A服务器版本号偏移类型Length(byte)
只有在刚刚连接上Server的时候有效,Server会马上返回一个数据节段的信息0VersionString8end of '\0'
8Session ID432bits
12UnKnown11
FF当出现错误的时候返回信息偏移类型Length(byte)
0ErrCode2
2ErrMsgEND
FE多段信息传输的结束

Client 对 Server 提交数据的格式:

偏移区域类型Length(byte)
0HEADData Length3
1
2
3Compressed1
4DATACommand ID1
5Command DataData Length - 1
Command ID 与 Command Data 的说明:
ID类型数据格式
0COM_SLEEP
1COM_QUITNULL
2COM_INIT_DBDatabase name
3COM_QUERYstand query string
4COM_FIELD_LISTtable name [128] wildcard[128]
5COM_CREATE_DBDatabase name
6COM_DROP_DBDatabase name
7COM_REFRESHoptions(bits)
8COM_SHUTDOWNNULL
9COM_STATISTICSNULL
10COM_PROCESS_INFONULL
11COM_CONNECT
12COM_PROCESS_KILLsid[4]
13COM_DEBUGNULL
14COM_PINGNULL
15COM_TIME
16COM_DELAYED_INSERT
17COM_CHANGE_USER[user][passwd][db]
18 COM_BINLOG_DUMP
19COM_TABLE_DUMP
20COM_CONNECT_OUT
第八节 Client 如何通过 Server 的用户认证

协议分析完成了,我尝试着让它工作起来,可是认证这个部分遇到了麻烦,Mysql Server在Client连接上它的时候,会首先返回给Client一个数据包,包含协议的版本号,版本信息,SessionID,一个8字节的 Key,就是这个Key的原因。Client会使用这个Key来加密密码,然后将用户名,密码,需要打开的数据库等信息发送给Server,这样就完成认证了。我不知道Client是如何利用这个Key来加密的,所以我打算跳过密码,我将Client的数据包重组,去掉Password的信息之后,我成功了,但是集群里面的Mysql用户都是没有密码的,安全性多多少少有些问题,不过这些服务器都是放在HA后面的,没有外部的IP地址,应该问题不大,不过多多少少是个缺憾。
但是我总要知道用户的密码是否正确吧?怎么办呢?使用一个专用的Mysql来完成密码认证。安装一个最小化资源的Mysql Server用来做MysqlAuth(专用认证服务器),当Client连接后,就将MysqlAuth的第一个数据包返回给Client,这里面当然就包含着Key,然后Client会使用这个Key,加密密码之后,将认证信息发回来,这个时候,MysqlHA系统就会将这个信息转发给 MysqlAuth,并且自己保留一份,如果认证通过了,就把保留的那一份进行重组,去掉密码信息,然后用重组后的认证信息去连接集群中的服务器。


图中HA就是使用HeartBeat方式建立的高可靠性系统(具体实现方法请参考 http://www.linuxvirtualserver.org/)。Proxy为Mysql-Proxy系统,MysqlAuth是专用的认证服务器。红色的RealServer为主要服务器,可以进行数据更新操作,同时将数据同步到其它的RealServer。


第十节 结束语

我现在已经基本完成了mysql-proxy的程序的开发,但是目前仍然处于测试阶段,最新的版本是0.0.4,下一个版本仍然还在修订中。从0.0.3版本开始,mysql-proxy已经可以完整的跑完mysql自身提供的sql-bench了,但是这个sql-bench只能提供单点的性能,没有对集群的mysql系统提供测试功能。
系统提供了动态采集RealServer上的LoadAvg然后反馈给Mysql Proxy的程序,但是由于这部分我没有进行测试,所以我在前面的测试中采用的请求分配方式是轮询方式,如果出现两个负载一样的RealServer系统会自动的在它们之间轮换选择。
Mysql-proxy的源代码您可以到我的网站下载: http://netsock.org/bbs/Mysql-HA-Cluster项目。还有一部分测试的数据我也会在那里公布。
如何进行系统测试?
既然是专门为Linux+Apache+Php+Mysql这样的系统做的集群,就应该找一个实际的应用来跑跑看,然后模拟大量的访问,来进行测试。
选择一个论坛系统也许不错,VBB吧,用的比较多,也比较流行。模拟访问就用Apache自身提供的AB来做。
测试系统的最小环境就是:(五台机器)
1 x Apache + PHP
1 x AB
1 x Mysql Proxy + Mysql Auth Server
2 x Mysql Real Server
 



MySQL从5.0.2版开始引入触发器,触发器就是一个已命名的数据库对象,这个对象和某张表 相关,而且当这张表发生某种特定事件后,触发器将被激活执行相应的动作,触发器允许这 些动作在这张表中的一行或多行的数据被操作的前后执行。在流行业务系统的处理过程中,开发和管理人员可以用触发器来实现数据审计和其他安全相关的功能,如在运行中的数据执行加密功能。

举个例子来说:一个客户数据库中包含客户的社会保险号,企业的安全和审计人员必须将这些信息加密后存入磁盘。针对这种情况,管理员可以通过创建一个触发器来自动获取并加密这些数据然后再插入相应的数据库表中。如下所示:

mysql> delimiter // 
mysql> create trigger t_customer_insert before insert on customer
    -> for each row
    -> begin 
    -> set NEW.customer_ssn = aes_encrypt(NEW.customer_ssn,'password');
    -> end; 
    -> //
Query OK, 0 rows affected (0.00 sec)
mysql> delimiter ;

mysql> insert into customer values (1,'fred','smith','456097234');
Query OK, 1 row affected (0.00 sec)
mysql> select * from customer;

可以看出存在磁盘数据库表中的社会保险号ssn已经变成加密后的不可读乱码格式。

另外MySQL5也引进了对游标的支持,在第一个发行版本中游标有向前翻阅结果集和不可执行数据更新语句的特点。游标可以用在MySQL5的新编码对象,如存储过程和触发器,甚至是独立的存储过程逻辑块中。以下是一个在存储过程中的使用游标的简单例子:
mysql> delimiter // 
mysql> CREATE PROCEDURE cursor_demo()
    -> BEGIN 
    ->   DECLARE a, b CHAR(16); 
    ->   DECLARE cur1 CURSOR FOR SELECT id,data FROM test.t1;
    -> OPEN cur1; 
    -> REPEAT  
    ->  FETCH cur1 INTO a,b;
    -> UNDONE END REPEAT;
    -> CLOSE cur1; 
    -> END
    -> //
下面再举一个触发器的例子,该例子可以计算所有插入某表的某个列中的数值的和:
mysql> CREATE TABLE account (acct_num INT, amount DECIMAL(10,2));
mysql> CREATE TRIGGER ins_sum BEFORE INSERT ON account
    -> FOR EACH ROW SET @sum = @sum + NEW.amount;
可见触发器功能可以提高管理人员管理数据库的灵活性。




    摘要:

MySQL 5 已经正式推出了,支援 Stored Procedures 、 Functions 、 Views 、 Triggers 等。 目前 phpMyAdmin 2.6.4 好像还不支援这些新特色 (View 可以看得到,但是没有建立的介面?) ,不过 MySQL 官方自己推了一个 MySQL Query Browser ,还不错用, 缺点是中文的支援性不佳 (输入中文时会怪怪的) 。

用 MySQL Query Browser 写一个 Stored Procedure :

DELIMITER $$

DROP PROCEDURE IF EXISTS `spTest` $$
CREATE PROCEDURE `spTest`(p_title VARCHAR(200), p_description TEXT)
    DETERMINISTIC
BEGIN
  INSERT INTO category (title, description) 
  VALUES (p_title, p_description);
END     (全文共1337字)——点击此处阅读全文




    摘要:
cre8d design blog里有一篇关于Blog Design Trends的文章,例举了目前Blog设计方面的7个趋势。这些趋势已经在很多的国外Blog中被广泛应用。

- 大字体(Big fonts):
11号Verdana字体已经过时,大字体的标题和正文重新流行。如Garrett Dimon’s blogWhitespace都使用了大字体。在传统的西文网站中,字体过小的情况的确比较普遍。对中文网站来说,12px的大小个人觉得还是不错。而在Blog中,再大一点的字体也许可读性更强,要不要把我的Blog正文字体改为13px?

- 顶端粗边线(Top border):
这是一个很细小的装饰,但    (全文共2079字)——点击此处阅读全文