当前位置:  编程技术>软件工程/软件设计
本页文章导读:
    ▪PHP缓存技术介绍       普遍缓存技术 数据缓存:这里所说的数据缓存是指数据库查询缓存,每次访问页面的时候,都会先检测相应的缓存数据是否存在, 如果不存在,就连接数据库,得到数据,并把查询.........
    ▪linux中exit()和 _exit()说明          exit和_exit函数都是用来终止进程的。当程序执行到exit或_exit时,系统无条件的停止剩下所有操作,清除包括PCB在内的各种数据结构,并终止本进程的运行。但是,这两个函数是有区.........
    ▪源码详解openfire保存消息记录_修改服务端方式      实现openfire消息记录通常有两种方式,修改服务端和添加消息记录插件。 今天,简单的说明一下修改服务端方式实现消息记录保存功能。 实现思路 修改前: 默认的,openfire只提供保存离线.........

[1]PHP缓存技术介绍
    来源: 互联网  发布时间: 2013-11-19

普遍缓存技术

数据缓存:这里所说的数据缓存是指数据库查询缓存,每次访问页面的时候,都会先检测相应的缓存数据是否存在, 
          如果不存在,就连接数据库,得到数据,并把查询结果序列化后保存到文件中,以后同样的查询结果
          就直接从缓存表或文件中获得。
          用的最广的例子看Discuz的搜索功能,把结果ID缓存到一个表中,下次搜索相同关键字时先搜索缓存表。

          举个常用的方法,多表关联的时候,把附表中的内容生成数组保存到主表的一个字段中,
          需要的时候数组分解一下,这样的好处是只读一个表,坏处就是两个数据同步会多不少步骤,
          数据库永远是瓶颈,用硬盘换速度,是这个的关键点。

普遍缓存技术

  每次访问页面的时候,都会先检测相应的缓存页面文件是否存在,如果不存在,就连接数据库,得到数据,
  显示页面并同时生成缓存页面文件,这样下次访问的时候页面文件就发挥作用了。
  (模板引擎和网上常见的一些缓存类通常有此功能)

时间触发缓存:

检查文件是否存在并且时间戳小于设置的过期时间,如果文件修改的时间戳比当前时间戳减去过期时间戳大,
那么就用缓存,否则更新缓存。

内容触发缓存:

当插入数据或更新数据时,强制更新缓存。

静态缓存:

这里所说的静态缓存是指静态化,直接生成HTML或XML等文本文件,有更新的时候重生成一次,
适合于不太变化的页面,这就不说了。

以上内容是代码级的解决方案,我直接CP别的框架,也懒得改,内容都差不多,
很容易就做到,而且会几种方式一起用,但下面的内容是服务器端的缓存方案,
非代码级的,要有多方的合作才能做到

内存缓存:

Memcached是高性能的,分布式的内存对象缓存系统,用于在动态应用中减少数据库负载,
提升访问速度。
这里说下Memcached的例子:

    <?php
    $memcache = new Memcache;
    $memcache->connect('localhost', 11211) or die ("Could not connect");
    $version = $memcache->getVersion();
    echo "Server's version: ".$version."\n";
    $tmp_object = new stdClass;
    $tmp_object->str_attr = 'focalbook';
    $tmp_object->int_attr = 123;
    $memcache->set('key', $tmp_object, false, 10) or die ("Failed to save data at the server");
    echo "Store data in the cache (data will expire in 10 seconds)\n";
    $get_result = $memcache->get('key');
    echo "Data from the cache:\n";
    var_dump($get_result);
    ?>

读库

    <?php
    $sql = 'SELECT * FROM users';
    $key = md5($sql);   //memcached 对象标识符
    if ( !($datas = $mc->get($key)) ) {
        //  在 memcached 中未获取到缓存数据,则使用数据库查询获取记录集。
        echo "n".str_pad('Read datas from MySQL.', 60, '_')."n";
        $conn = mysql_connect('localhost', 'focalbook', 'focalbook');
        mysql_select_db('focalbook');
        $result = mysql_query($sql);
        while ($row = mysql_fetch_object($result))
            $datas[] = $row;
        //  将数据库中获取到的结果集数据保存到 memcached 中,以供下次访问时使用。
        $mc->add($key, $datas);
    } else {
        echo "n".str_pad('Read datas from memcached.', 60, '_')."n";
    }
    var_dump($datas);
    ?>

php的缓冲器:

有eaccelerator, apc, phpa,xcache,这个这个就不说了吧,搜索一堆一堆的,自己看啦,知道有这玩意就OK

MYSQL缓存:

这也算非代码级的,经典的数据库就是用的这种方式,看下面的运行时间,0.09xxx之类的
我贴段根据蓝色那家伙修改后部分my.ini吧,2G的MYISAM表可以在0.05S左右,据说他前后改了有快一年

    [client]
    ……
    default-character-set=gbk
    default-storage-engine=MYISAM
    max_connections=600
    max_connect_errors=500
    back_log=200
    interactive_timeout=7200
    query_cache_size=64M
    ……
    table_cache=512
    ……
    myisam_max_sort_file_size=100G
    myisam_max_extra_sort_file_size=100G
    myisam_sort_buffer_size=128M
    key_buffer_size=1024M
    read_buffer_size=512M
    ……
    thread_concurrency=8

基于反向代理的Web缓存:

如Nginx,SQUID,mod_proxy(apache2以上又分为mod_proxy和mod_cache)
NGINX的例子

    <nginx.conf>
    #user  nobody;
    worker_processes  4;
    error_log  logs/error.log crit;
    pid        logs/nginx.pid;
    worker_rlimit_nofile 10240;
    events {
        use epoll;
        worker_connections  51200;
    }
    http {
        include       mime.types;
        default_type  application/octet-stream;
        sendfile    on;
        keepalive_timeout 65;
        tcp_nodelay on;
        # server pool
        upstream bspfrontsvr {
                server 10.10.10.224:80   weight=1;
                server 10.10.10.221:80   weight=1;
        }

        upstream bspimgsvr {
                server 10.10.10.201:80   weight=1;
        }

        upstream bspstylesvr {
                server 10.10.10.202:80   weight=1;
        }

        upstream bsphelpsvr {
                server 10.10.10.204:80   weight=1;
        }

        upstream bspwsisvr {
                server 10.10.10.203:80   weight=1;
        }

        upstream bspadminsvr {
                server 10.10.10.222:80   weight=1;
        }

        upstream bspbuyersvr {
                server 10.10.10.223:80   weight=1;
        }

        upstream bspsellersvr {
                server 10.10.10.225:80   weight=1;
        }
        upstream  bsploginsvr  {
                server 10.10.10.220:443  weight=1;
        }
        upstream  bspregistersvr  {
                server 10.10.10.220:80  weight=1;
        }
        log_format  jisuzw_com  '$remote_addr - $remote_user [$time_local] "$request" '
                                 '$status $body_bytes_sent "$http_referer" "$http_user_agent" ';
        #--------------------------------------------------------------------
        #img.jisuzw.com
        server {
            listen       10.10.10.230:80;
            server_name  img.jisuzw.com;
            location / {
                            proxy_pass      http://bspimgsvr;
                            include         proxy_setting.conf;
            }
            access_log  logs/img.log  jisuzw_com;
        }

        #style.jisuzw.com
        server {
            listen       10.10.10.230:80;
            server_name  style.jisuzw.com;
            location / {
                            proxy_pass      http://bspstylesvr;
                            include         proxy_setting.conf;
            }
            access_log  logs/style.log  jisuzw_com;
        }

        #help.jisuzw.com
        server {
            listen       10.10.10.230:80;
            server_name  help.jisuzw.com;
            location / {
                            proxy_pass      http://bsphelpsvr;
                            include         proxy_setting.conf;
            }
            access_log  logs/help.log  jisuzw_com;
        }

        #admin.jisuzw.com
        server {
            listen       10.10.10.230:80;
            server_name  admin.jisuzw.com;
            location / {
                            proxy_pass      http://bspadminsvr;
                     
    
[2]linux中exit()和 _exit()说明
    来源: 互联网  发布时间: 2013-11-19

    exit和_exit函数都是用来终止进程的。当程序执行到exit或_exit时,系统无条件的停止剩下所有操作,清除包括PCB在内的各种数据结构,并终止本进程的运行。但是,这两个函数是有区别的。

    exit()函数的作用是:直接使用进程停止运行,清除其使用的内存空间,并清除其在内核中的各种数据结构;_exit()函数则在这一基础上做了一些包装。在执行退出之前加了若干道工序。exit()函数与_exit()函数最大区别就在于exit()函数在调用exit系统之前要检查文件的打开情况,把文件缓冲区的内容写回文件。

       由于Linux的标准函数库中,有一种被称作“缓冲I/O”的操作,其特征就是对应每一个打开的文件,在内存中都有一片缓冲区。每次读文件时,会连续的读出若干条记录,这样在下次读文件时就可以直接从内存的缓冲区读取;同样,每次写文件的时候也仅仅是写入内存的缓冲区,等满足了一定的条件(如达到了一定数量或遇到特定字符等),再将缓冲区中的内容一次性写入文件。

     这种技术大大增加了文件读写的速度,但也给编程代来了一点儿麻烦。比如有一些数据,认为已经写入了文件,实际上因为没有满足特定的条件,它们还只是保存在缓冲区内,这时用_exit()函数直接将进程关闭,缓冲区的数据就会丢失。因此,要想保证数据的完整性,就一定要使用exit()函数。

exit的函数声明在stdlib.h头文件中。

_exit的函数声明在unistd.h头文件当中。

下面的实例比较了这两个函数的区别。printf函数就是使用缓冲I/O的方式,该函数在遇到“\n”换行符时自动的从缓冲区中将记录读出。实例就是利用这个性质进行比较的。

exit.c源码

#include <stdlib.h>
#include <stdio.h>

int main(void)
{
    printf("Using exit...\n");
    printf("This is the content in buffer");
    exit(0);
}

输出信息:

Using exit...

This is the content in buffer

#include <unistd.h>
#include <stdio.h>

int main(void)
{
    printf("Using exit...\n");
    printf("This is the content in buffer");
    _exit(0);
}

则只输出:

Using exit...

说明:在一个进程调用了exit之后,该进程并不会马上完全小时,而是留下一个称为僵尸进程(Zombie)的数据结构。僵尸进程是一种非常特殊的进程,它几乎已经放弃了所有的内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其它进程收集,除此之外,僵尸进程不再占有任何内存空间。

作者:DLUTBruceZhang 发表于2013-4-16 15:02:24 原文链接
阅读:58 评论:0 查看评论

    
[3]源码详解openfire保存消息记录_修改服务端方式
    来源: 互联网  发布时间: 2013-11-19

实现openfire消息记录通常有两种方式,修改服务端和添加消息记录插件。

今天,简单的说明一下修改服务端方式实现消息记录保存功能。


实现思路

修改前:

默认的,openfire只提供保存离线记录至ofOffline表中。当发送一条消息时,判断用户是否在线,若为true,不保存消息;若为fasle,保存消息至离线消息表中。


修改后:

仿照保存离线消息,用户每发送一条消息,将消息存放在ofHistory表中,ofHistory表结构同ofOffline


实现步骤:

1.修改初始数据库文件,路径src/database/openfire_sqlserver.sql

将ofOffline修改为ofHistory

CREATE TABLE ofHistory (
  username              NVARCHAR(64)    NOT NULL,
  messageID             INTEGER         NOT NULL,
  creationDate          NVARCHAR(64)    NOT NULL,
  messageSize           INTEGER         NOT NULL,
  stanza                NTEXT           NOT NULL,
  CONSTRAINT ofHistory_pk PRIMARY KEY (username, messageID)
);

CREATE TABLE ofOffline (
  username              NVARCHAR(64)    NOT NULL,
  messageID             INTEGER         NOT NULL,
  creationDate          CHAR(15)        NOT NULL,
  messageSize           INTEGER         NOT NULL,
  stanza                NTEXT           NOT NULL,
  CONSTRAINT ofOffline_pk PRIMARY KEY (username, messageID)
);


注:其他数据库修改方式雷同

2.添加保存消息方法

MessageRouter类中110行

   try {
                    // Deliver stanza to requested route
                    routingTable.routePacket(recipientJID, packet, false);
                    //保存消息记录dml@2013.4.15
                    OfflineMessageStore oms = new OfflineMessageStore();
                    oms.addMessage_toHistory(packet);
                    
                }
                catch (Exception e) {
                	log.error("Failed to route packet: " + packet.toXML(), e);
                    routingFailed(recipientJID, packet);
                }

3.修改OfflineMessageStore类,添加保存消息记录方法

/**
 * $RCSfile$
 * $Revision: 2911 $
 * $Date: 2005-10-03 12:35:52 -0300 (Mon, 03 Oct 2005) $
 *
 * Copyright (C) 2004-2008 Jive Software. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jivesoftware.openfire;

import java.io.StringReader;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.database.SequenceManager;
import org.jivesoftware.openfire.container.BasicModule;
import org.jivesoftware.openfire.event.UserEventDispatcher;
import org.jivesoftware.openfire.event.UserEventListener;
import org.jivesoftware.openfire.user.User;
import org.jivesoftware.openfire.user.UserManager;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.StringUtils;
import org.jivesoftware.util.XMPPDateTimeFormat;
import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.CacheFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;

/**
 * Represents the user's offline message storage. A message store holds messages
 * that were sent to the user while they were unavailable. The user can retrieve
 * their messages by setting their presence to "available". The messages will
 * then be delivered normally. Offline message storage is optional, in which
 * case a null implementation is returned that always throws
 * UnauthorizedException when adding messages to the store.
 * 
 * @author Iain Shigeoka
 */
public class OfflineMessageStore extends BasicModule implements
		UserEventListener {

	private static final Logger Log = LoggerFactory
			.getLogger(OfflineMessageStore.class);
	// 保存消息记录 dml@2013.4.16
	private static final String INSERT_HISTORY = "INSERT INTO ofHistory (username, messageID, creationDate, messageSize, stanza) "
			+ "VALUES (?, ?, ?, ?, ?)";

	private static final String INSERT_OFFLINE = "INSERT INTO ofOffline (username, messageID, creationDate, messageSize, stanza) "
			+ "VALUES (?, ?, ?, ?, ?)";
	private static final String LOAD_OFFLINE = "SELECT stanza, creationDate FROM ofOffline WHERE username=?";
	private static final String LOAD_OFFLINE_MESSAGE = "SELECT stanza FROM ofOffline WHERE username=? AND creationDate=?";
	private static final String SELECT_SIZE_OFFLINE = "SELECT SUM(messageSize) FROM ofOffline WHERE username=?";
	private static final String SELECT_SIZE_ALL_OFFLINE = "SELECT SUM(messageSize) FROM ofOffline";
	private static final String DELETE_OFFLINE = "DELETE FROM ofOffline WHERE username=?";
	private static final String DELETE_OFFLINE_MESSAGE = "DELETE FROM ofOffline WHERE username=? AND creationDate=?";

	private static final int POOL_SIZE = 10;

	private Cache<String, Integer> sizeCache;

	/**
	 * Pattern to use for detecting invalid XML characters. Invalid XML
	 * characters will be removed from the stored offline messages.
	 */
	private Pattern pattern = Pattern.compile("&\\#[\\d]+;");

	/**
	 * Returns the instance of <tt>OfflineMessageStore</tt> being used by the
	 * XMPPServer.
	 * 
	 * @return the instance of <tt>OfflineMessageStore</tt> being used by the
	 *         XMPPServer.
	 */
	public static OfflineMessageStore getInstance() {
		return XMPPServer.getInstance().getOfflineMessageStore();
	}

	/**
	 * Pool of SAX Readers. SAXReader is not thread safe so we need to have a
	 * pool of readers.
	 */
	private BlockingQueue<SAXReader> xmlReaders = new LinkedBlockingQueue<SAXReader>(
			POOL_SIZE);

	/**
	 * Constructs a new offline message store.
	 */
	public OfflineMessageStore() {
		super("Offline Message Store");
		sizeCache = CacheFactory.createCache("Offline Message Size");
	}

	/**
	 * Adds a message to this message store. Messages will be stored and made
	 * available for later delivery.
	 * 
	 * @param message
	 *            the message to store.
	 */
	public void addMessage(Message message) {
		if (message == null) {
			return;
		}
		// ignore empty bodied message (typically chat-state notifications).
		if (message.getBody() == null || message.getBody().length() == 0) {
			// allow empty pubsub messages (OF-191)
			if (message.getChildElement("event",
					"http://jabber.org/protocol/pubsub#event") == null) {
				return;
			}
		}
		JID recipient = message.getTo();
		String username = recipient.getNode();
		// If the username is null (such as when an anonymous user), don't
		// store.
		if (username == null
				|| !UserManager.getInstance().isRegisteredUser(recipient)) {
			return;
		} else if (!XMPPServer.getInstance().getServerInfo().getXMPPDomain()
				.equals(recipient.getDomain())) {
			// Do not store messages sent to users of remote servers
			return;
		}

		long messageID = SequenceManager.nextID(JiveConstants.OFFLINE);

		// Get the message in XML format.
		String msgXML = message.getElement().asXML();

		Connection con = null;
		PreparedStatement pstmt = null;
		try {
			con = DbConnectionManager.getConnection();
			pstmt = con.prepareStatement(INSERT_OFFLINE);
			pstmt.setString(1, username);
			pstmt.setLong(2, messageID);
			pstmt.setString(3, StringUtils.dateToMillis(new java.util.Date()));
			// SimpleDateFormat df = new
			// SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			// pstmt.setString(3, df.format(new Date()).toString());

			pstmt.setInt(4, msgXML.length());
			pstmt.setString(5, msgXML);
			pstmt.executeUpdate();
		}

		catch (Exception e) {
			Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
		} finally {
			DbConnectionManager.closeConnection(pstmt, con);
		}

		// Update the cached size if it exists.
		if (sizeCache.containsKey(username)) {
			int size = sizeCache.get(username);
			size += msgXML.length();
			sizeCache.put(username, size);
		}
	}

	/**
	 * 保存消息记录
	 * 
	 * @author dml
	 * @param message
	 */
	public void addMessage_toHistory(Message message) {
		if (message == null) {
			return;
		}
		// ignore empty bodied message (typically chat-state notifications).
		if (message.getBody() == null || message.getBody().length() == 0) {
			// allow empty pubsub messages (OF-191)
			if (message.getChildElement("event",
					"http://jabber.org/protocol/pubsub#event") == null) {
				return;
			}
		}
		JID recipient = message.getTo();
		String username = recipient.getNode();
		// If the username is null (such as when an anonymous user), don't
		// store.
		if (username == null      
    
最新技术文章:
 




特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3