概述

灰度发布是最近一年在国内互联网讨论较多的一个话题。灰度发布在国外并没有明确的定义,在国内的百科上如此定义

灰度发布是指在黑与白之间,能够平滑过渡的一种发布方式。AB test就是一种灰度发布方式,让一部用户继续用A,一部分用户开始用B,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面 来。灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度。

由此也可见灰度发布很多时候都和AB测试混在一起,但实际上灰度发布还包含了多级发布的概念。

11年,Facebook的David Wei写了一篇文章《代码和产品发布的几种方式》明确分析了下几个概念:

1、多级发布:也可以称为分步代码发布,是一种代码发布的方式。基本操作是整个团队共用一个代码库,一定频率(比如每天一次,或者每周一次)把整个代码的最新版本做一个新的发布分支(release branch),把发布分支逐步发布到产品线。

2、AB测试:这是一种很成熟的概念,是产品发布的常用手段。比起分步代码发布,AB测试往往有更长的周期(比如几个星期甚至几个月)。基本操作是产品的开发者加一个或者多个配置控制(一般每个产品配置应该带有配置的ID),允许通过调节相应的配置来让一个产品发布到“逐步选择”的用户群。

从概念中可以看出多级发布和AB测试中最重要的区别:面向对象不一样。多级发布针对的是代码发布,AB测试针对的产品发布。本文主要讨论代码多级发布相关的需求和实现方案。

需求场景

在具体的互联网应用中(主要针对如下架构)

多级发布的需求场景如下:

第一种:单个业务模块上线,属于具体一个业务中的一个模块,非基础模块。有如下的特点:

  • 50%的上线需求是这种场景。
  • 上线流程:单机器-》多机器-》全部机器 的过程。
  • 上线时间间隔非常短,一般在半个小时内完成全部上线。
  • 会对用户带来影响,比如说用户不停刷新有可能看到不同的版本。

第二种:基础库模块上线。大部分的基础库上线会和第一种业务模块上线类似,但部分上线(尤其是哪些影响业务模块较多,修改较大,有高性能要求)也会有如下特点:

  • 整体预估20%的上线需求,其中5%有如下特殊需求。
  • 可能的特殊需求:分业务系统逐步上线到所有机器。
  • 上线时间间隔有可能持续较长时间,比如说几周以上。
  • 基础库上线一般不会对用户带来影响。

第三种:多业务多模块上线。一般这种上线的项目都是非常重要或者有重大功能修改的项目,重要性非常高。特点如下:

  • 30%的比例。
  • 一般上线流程是分业务上线。并且大体原则是从后(端)到前(端)。跨系统依赖的会梳理出顺序,按照次序先后上线。
  • 原则上各个模块之间上线间隔都在小时或者分钟级别。
  • 对于具体用户可见的部分会采用,有可能会用到长时间间隔的上线方式。

难点&解决方案

多级发布的主要难题有以下几个:

  1. 监控完善到位。在每一级别的发布中,如何能够快速的通过监控系统发现问题,包含功能异常、性能异常。
  2. 策略灵活可控。比如说能够支持指定用户查看某一级别的发布版本、能够灵活的支持动态调度和动态扩容的需求。
  3. 用户体验无损伤。在发布的过程中,最好能够保证用户不会出现刷新版本频繁切换的问题。PS:该问题在facebook也存在,但据说目前不care。
  4. 发布过程可测试。在发布的过程中,每一个阶段都是可以方便确认功能正确性的。

同时多级发布也有一些限制,比如说同一个模块的最多只能有一个上线流程在进行,也就是不支持同一个模块多个版本并行上线

其中监控需求,本身是一个相对独立的需求,不在多级发布中考虑,那么多级发布只需要解决2、3、4三个难题。

多级发布解决方案按照不同的实现层度如下:

第一、实现多级发布基本功能:按照比例实现多级发布

假设总共有16台机器,分成8级发布,则可以按照1/8的分级方式进行上线发布。比如发布了第一级别后如下图:

为什么要按照比例,而不是直接给机器划分级别呢?主要是处于几个考虑:

  1. 给机器不同的标签定义会导致机器的异构化带来维护的难度。
  2. 无法支持机器动态调度的需求。
  3. 无法支持机器数目扩容的需求。

第二、保证用户体验:采用一致性哈希负载均衡

如何保证用户体验不受到影响的关键是:在多级发布的时候保证一个用户的请求固定的落在一个发布级别中。那么对应的方法就是:前端接入层和运行层之间采用一致性哈希负载均衡算法。

这种算法有几个依赖:

  • 接入层和运行层的各个节点是无状态对等的。原则上都会满足。
  • 在代码发布阶段,最好不能有机器的变更。如果有机器变更则会导致部分用户在某一时刻出现业务版本的切换(原则上影响也不大)

对于一些默认不是一致性hash算法的,也可以在代码发布的时候,把前端接入层和运行层之间的负载均衡方法切换到一致性哈希。

第三、可测性和灵活性:接入层引入规则通用库。(如果接入层采用Nginx做反向代理,那么就是一个nginx扩展)

可测性是指:业务模块的阶段性发布能够理解可测。这种需要只需要接入层规则通用库能够支持通过Http请求某一个参数来进行强制的请求分流即可。比如说通过参与version来指定对应请求分流的版本,具体比如说URL中有参数version=1,则分流到多级发布中的第一级。

灵活性:主要是指其他一些测试性的需求,比如说强制某些用户分流在多级发布的某一级,这些同样可以可以在接入层中实现。

本文首发xlq的博客(转载请保留)http://blog.xiuwz.com/2012/03/05/%e6%b5%85%e8%b0%88%e7%81%b0%e5%ba%a6%e5%8f%91%e5%b8%83%e4%b9%8b%e5%a4%9a%e7%ba%a7%e5%8f%91%e5%b8%83/
posted @ 2012-07-04 16:59 小马歌 阅读(4357) | 评论 (0)编辑 收藏
 

最近有几个朋友提起”灰度发布"这个概念和相关的问题。想解释一下几种具体的发布方式(具体名称中文翻译不一定正确)、他们的优缺点和实现难点。

这几种方式都可以作为快速运营的软件或者web服务公司逐步发布新代码或者新产品,边尝试边改进的方法,这些方法可以避免一次发布里面某个产品/代码的漏洞对网站产生瞬间毁灭性的后果。 

几种方式各有优缺点和难点,根据实际情况一个公司可能使用不同的方法做不同的发布。

 

 

  • 分步代码发布(multi-phase code push):这是敏捷开发的团队常用的代码发布方式。基本操作是整个团队共用一个代码库,一定频率(比如每天一次,或者每周一次)把整个代码的最新版本做一个新的发布分支(release branch)把发布分支逐步发布到产品线。
  • 特点:"逐步选择"的过程不由代码控制(如果代码控制,那新一版本的控制代码有问题就可能让整个代码发布过程崩溃)。“逐步选择”过程由运营团队负责:比如选择每个机柜的第一台机器,或者每个机群的第一个机柜,或者多个数据中心里面选择某一个数据中心⋯⋯关键是选择的时候是均匀分布到各种不同的机器上。如果新代码在某一种配置的机器上有问题,运营团队能够及时发现。另外multi-phase code push的发布周期必须短于敏捷开发的迭代周期,往往一天或者一周之内要把代码发布到所有机器。
  • 监控:multi-phase code push一般要做实时的监控:代码逻辑错误的信息按照代码版本(比如svn revision number)来分类,保证新版本的代码不带来新的错误;硬件的信息(CPU内存IO)按照选择的机器、机柜、机群、数据中心分类:保证新的版本不引起更大资源消耗。当以上的信息都确认之后,可以给更大规模的机器安装新代码。
  • 难点:
  • 如果前端负载均衡器不能保证用户和机器一致的话,一个用户可能在发布过程中看到若干次新版本和若干次旧版本(比如第一个页面是新版本,而AJAX是旧版本),版本不兼容会造成Javascript错误、CSS错位,甚至一些逻辑错误;Javascript体系架构需要做一些安全检测,或者要求程序员开发的时候考虑版本兼容(一般在快节奏的web开发里面不容易);或者用保持用户和机器一致的前端负载均衡器;
  • 监控的时候硬件资源消耗信息有可能因为发布过程本身产生很大的扰动,而与代码无关(比如重启之后缓存要重新warmup,增大IO,产生虚报),这需要代码发布经理(pusher)的经验来排除。
  • AB测试(AB testing):这是产品发布的常用手段。比起分步代码发布,AB测试往往有更长的周期(比如几个星期甚至几个月)。基本操作是产品的开发者加一个或者多个配置控制(一般每个产品配置应该带有配置的ID),允许通过调节相应的配置来让一个产品发布到“逐步选择”的用户群。
  • 特点:“逐步选择”是一个有代码控制的逻辑过程。一般的产品基于用户ID选择;也有基于IP或者其他信息的。
  • 监控:AB测试的数据一般按照产品配置ID和打开/关闭状态分类,分析某个产品配置在打开的时候和关闭的时候对用户行为的影响,和对硬件资源的消耗,由此可以预测这个产品在100%发布之后的影响。
  • 难点:
    • 如何做选择:不同的产品有不同的选择方式。一般可以考虑用户ID,但如果跟浏览器的缓存效率关系很大的,可能需要考虑IP(因为一个浏览器可能被多个用户使用);如果对非注册用户做的产品(比如各种注册流程的测试),也可能需要IP,或者实时随机选取;
    • 产品效果的评价:有些产品需要有网络效应,如果按照用户ID随机抽取样本,网络效应可能被打破而使产品在AB测试期间失效 (比如一个社交网站的平均用户连接度是50,即一个用户连接其他50个用户,按照1%用户ID随机抽样的AB测试,那被选中的用户子群内部的连接度可能不到1)
    • "逐步选择"的逻辑本身是一个代码,如果这个代码写错的话可能带来灾难性后果。
  • 灰度上线(dark launch):我想“灰度上线”这个术语可能来源于dark launch。这是产品发布的另一种手段,往往用于需要一次发布的产品。 有一些产品可能因为市场营销策略的原因,或者因为产品本身的特点(比如Facebook的用户名注册,或者可能像火车售票系统)不能进行AB测试那样的逐步上线。同时,我们又需要知道这个产品一次上线的时候带来的影响,在这种情况下我们可以用灰度上线。基本操作是在用户访问网站的时候,打开新功能所需要运行的代码,但把用户可见的输出、互动和写操作都屏蔽掉,按照AB测试的方法逐步把这个去掉用户互动的产品发布出去。
  • 特点:外界感觉不到新产品的测试过程
  • 监控:和AB测试一样,但主要关注的是系统的负载和资源消耗
  • 难点:
    • 如何屏蔽用户互动:一方面要获得几乎真实的产品负载,另一方面希望不要把代码搞乱导致真正发布的时候需要很大改动;
    • 对真实产品发布后负载的预测:产品发布之后可能形成正反馈(比如一个产品发布之后大受欢迎,引起更多的用户注册⋯⋯)灰度上线只能预测第一层效果,不能预测用户行为的改变所引起的连锁反应。
这几种方式好像都被称作灰度上线,它们还是有很大不同的。根据产品发布需要,各有优劣。
posted @ 2012-07-04 16:33 小马歌 阅读(163) | 评论 (0)编辑 收藏
 

在传统软件产品发布过程中(例如微软的Windows 7的发布过程中),一般都会经历Pre-Alpha、Alpha、Beta、Release candidate(RC)、RTM、General availability or General Acceptance (GA)等几个阶段(参考Software release life cycle)。可以看出传统软件的发布阶段是从公司内部->外部小范围测试>外部大范围测试->正式发布,涉及的用户数也是逐步放量的过程。

    在互联网产品的发布过程中也较多采用此种发布方式:产品的发布过程不是一蹴而就,而是逐步扩大使用用户的范围,从公司内部用户->忠诚度较高的种子用户->更大范围的活跃用户->所有用户。在此过程中,产品团队根据用户的反馈及时完善产品相关功能。此种发布方式,按照中国特色的叫法被冠以”灰度发布“、”灰度放量“、”分流发布“。

    关于“灰度发布”叫法的来源无从考察。只不过按照中国传统哲学的说法来看,很符合中国人中庸的思维模式:自然界所有的事物总是以对称、互补、和谐的形式存在,例如黑与白、阴与阳、正与负、福与祸。在二元对立的元素间存在相互过渡的阶段,所谓”祸兮福所倚,福兮祸所伏“。具体到黑与白,在非黑即白中间还有中间色——灰色。于是出现了很多关于灰色的说法:灰盒测试,灰色管理(极力推荐 任正非:管理的灰度),灰色收入,灰色地带等等。因此对于灰度发布实际上就是从不发布,然后逐渐过渡到正式发布的一个过程。

1、灰度发布的作用

  • 及早获得用户的意见反馈,完善产品功能,提升产品质量
  • 让用户参与产品测试,加强与用户互动
  • 降低产品升级所影响的用户范围
  • 。。。

2、灰度发布的步骤

  1)、定义目标

  2)、选定策略:包括用户规模、发布频率、功能覆盖度、回滚策略、运营策略、新旧系统部署策略等

  3)、筛选用户:包括用户特征、用户数量、用户常用功能、用户范围等

  4)、部署系统:部署新系统、部署用户行为分析系统(web analytics)、设定分流规则、运营数据分析、分流规则微调

  5)、发布总结:用户行为分析报告、用户问卷调查、社会化媒体意见收集、形成产品功能改进列表

  6)、产品完善

  7)、新一轮灰度发布或完整发布

3、常见问题

  3.1)、以偏概全

         1)、问题特征:

              a、选择的样本不具有代表性;

              b、样本具有代表性,但选择样本用户使用习惯并没有涵盖所有核心功能 
         2)、解决方案

              样本选择要多样化,样本的组合涵盖大部分核心功能

  3.2)、知识的诅咒

        ”知识的诅咒“的说法来自《粘住》中实验,具体可以自己搜索一下。我们自己对于自己开发的产品极为熟悉,于是乎想当然认为用户也应当能够理解产品的设计思路、产品的功能使用。

         1)、问题特征:

               a、结果没有量化手段;

               b、只依赖于用户问卷调查;

               c、没有web analytics系统;

               d、运营数据不全面,只有核心业务指标(例如交易量),没有用户体验指标

               e、对结果分析,只选择对发布有利的信息,对其他视而不见 
          2)、解决方案: 
               a、产品设计考虑产品量化指标 
               b、结果分析依据量化指标而不是感觉

  3.3)、发布没有回头路可走

        1)、问题特征:

              a、新旧系统用户使用习惯差异太大,没有兼容原有功能

              b、新旧系统由于功能差异太大,无法并行运行,只能强制升级

              c、新系统只是实现了旧系统部分功能,用户要完整使用所有功能,要在 在新旧系统切换

              d、新旧系统数据库数据结构差异太大,无法并行运行

         2)、解决方案:

              前期产品策划重点考虑这些问题,包括:

                  回滚方案、 新旧系统兼容方案、用户体验的一致性、用户使用习惯的延续性、新旧系统数据模型兼容性

  3.4)、用户参与度不够

         1)、问题特征:

                 a、指望用户自己去挖掘所有功能。对于一个产品,大部分用户经常只使用部分功能,用户大部分也很懒惰,不会主动去挖掘产品功能 
                 b、互动渠道单一 
                 c、陷入“知识的诅咒”,不尊重参与用户意见 
        2)、解决方案: 
                a、善待吃螃蟹的样本用户,包括给予参与测试的用户小奖励(例如MS给参与Win7测试用户正版License)、给用户冠以title 
                b、通过邮件、论坛、社区、Blog、Twitter等新媒体与用户形成互动 
                c、提供产品功能向导。在hotmail最近的升级后的功能tip,gmail的tip都有类似的产品功能导向。在产品中会提示类似于:你知道吗,xx还提供xx功能,通过它你可以xx 。

 

灰度发布,灰度放量,A/B Testing,A/B 测试,分流发布

4、灰度发布  VS.  A/B测试

    灰度发布于互联网公司常用A/B测试似乎比较类似,老外似乎并没有所谓的灰度发布的概念。按照wikipedia中对A/B测试的定义,A/B测试又叫:A/B/N Testing、Multivariate Testing,因此本质上灰度测试可以算作A/B测试的一种特例。只不过为了术语上不至于等同搞混淆,谈谈自己理解的两者的差异。

    灰度发布是对某一产品的发布逐步扩大使用群体范围,也叫灰度放量

    A/B测试重点是在几种方案中选择最优方案

   关于A/B测试可以参考这篇文章:A/B测试终极指南

5、灰度发布引擎

   对于一般的小系统并不需要单独的灰度发布引擎,可以参考A/B测试中做法,在页面javascript或服务器端实现分流的规则即可。但对于大型的互联网应用而言,单独的用于管理用户分流的发布引擎就很有必要了。“钱掌柜”分流发布模式 提到了原来阿里软件所使用的灰度发布引擎,设计思路具有普遍性,可以供参考

灰度发布,灰度放量,A/B Testing,A/B 测试,分流发布

6、参考文档

  “钱掌柜”分流发布模式

   百度百科:灰度发布

   A/B testing

   A/B测试终极指南

posted @ 2012-07-04 16:26 小马歌 阅读(11889) | 评论 (0)编辑 收藏
 
#!/bin/sh

defaultHost=//192.168.0.1/proj
defaultUserName=root
mountPath=/path/proj
host=$defaultHost
userName=$defaultUserName

if [ $# -eq 1 ]
then
    host=$1
    umount -l $mountPath
elif [ $# -eq 2 ]
then
    host=$1
    userName=$2
    umount -l $mountPath
elif [ $# -eq 3 ]
then
    host=$1
    userName=$2
    mountPath=$3
    umount -l $mountPath
fi
scmd="mount -t cifs -o user=$userName,password=workstation,rw,file_mode=0777,dir_mode=0777 $host $mountPath"
echo $scmd
eval $scmd
posted @ 2012-07-04 15:34 小马歌 阅读(218) | 评论 (0)编辑 收藏
 
随着互联网web2.0网站的兴起,非关系型的数据库现在成了一个极其热门的新领域,非关系数据库产品的发展非常迅速。而传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,例如:

 

1、High performance – 对数据库高并发读写的需求
web2.0网站要根据用户个性化信息来实时生成动态页面和提供动态信息,所以基本上无法使用动态页面静态化技术,因此数据库并发负载非常高,往往要达到每秒上万次读写请求。关系数据库应付上万次SQL查询还勉强顶得住,但是应付上万次SQL写数据请求,硬盘IO就已经无法承受了。其实对于普通的BBS网站,往往也存在对高并发写请求的需求,例如像JavaEye网站的实时统计在线用户状态,记录热门帖子的点击次数,投票计数等,因此这是一个相当普遍的需求。

2、Huge Storage – 对海量数据的高效率存储和访问的需求
类似Facebook,twitter,Friendfeed这样的SNS网站,每天用户产生海量的用户动态,以Friendfeed为例,一个月就达到了2.5亿条用户动态,对于关系数据库来说,在一张2.5亿条记录的表里面进行SQL查询,效率是极其低下乃至不可忍受的。再例如大型web网站的用户登录系统,例如腾讯,盛大,动辄数以亿计的帐号,关系数据库也很难应付。

3、High Scalability && High Availability- 对数据库的高可扩展性和高可用性的需求
在基于web的架构当中,数据库是最难进行横向扩展的,当一个应用系统的用户量和访问量与日俱增的时候,你的数据库却没有办法像web server和app server那样简单的通过添加更多的硬件和服务节点来扩展性能和负载能力。对于很多需要提供24小时不间断服务的网站来说,对数据库系统进行升级和扩展是非常痛苦的事情,往往需要停机维护和数据迁移,为什么数据库不能通过不断的添加服务器节点来实现扩展呢?

在上面提到的“三高”需求面前,关系数据库遇到了难以克服的障碍,而对于web2.0网站来说,关系数据库的很多主要特性却往往无用武之地,例如:

1、数据库事务一致性需求
很多web实时系统并不要求严格的数据库事务,对读一致性的要求很低,有些场合对写一致性要求也不高。因此数据库事务管理成了数据库高负载下一个沉重的负担。

2、数据库的写实时性和读实时性需求
对关系数据库来说,插入一条数据之后立刻查询,是肯定可以读出来这条数据的,但是对于很多web应用来说,并不要求这么高的实时性,比方说我(JavaEye的robbin)发一条消息之后,过几秒乃至十几秒之后,我的订阅者才看到这条动态是完全可以接受的。

3、对复杂的SQL查询,特别是多表关联查询的需求
任何大数据量的web系统,都非常忌讳多个大表的关联查询,以及复杂的数据分析类型的复杂SQL报表查询,特别是SNS类型的网站,从需求以及产品设计角度,就避免了这种情况的产生。往往更多的只是单表的主键查询,以及单表的简单条件分页查询,SQL的功能被极大的弱化了。

因此,关系数据库在这些越来越多的应用场景下显得不那么合适了,为了解决这类问题的非关系数据库应运而生,现在这两年,各种各样非关系数据库,特别是键值数据库(Key-Value Store DB)风起云涌,多得让人眼花缭乱。前不久国外刚刚举办了NoSQL Conference,各路NoSQL数据库纷纷亮相,加上未亮相但是名声在外的,起码有超过10个开源的NoSQLDB,例如:

Redis,Tokyo Cabinet,Cassandra,Voldemort,MongoDB,Dynomite,HBase,CouchDB,Hypertable, Riak,Tin, Flare, Lightcloud, KiokuDB,Scalaris, Kai, ThruDB,  ……

这些NoSQL数据库,有的是用C/C++编写的,有的是用Java编写的,还有的是用Erlang编写的,每个都有自己的独到之处,看都看不过来了,我(robbin)也只能从中挑选一些比较有特色,看起来更有前景的产品学习和了解一下。这些NoSQL数据库大致可以分为以下的三类:

一、满足极高读写性能需求的Kye-Value数据库:Redis,Tokyo Cabinet, Flare

高性能Key-Value数据库的主要特点就是具有极高的并发读写性能,Redis,Tokyo Cabinet, Flare,这3个Key-Value DB都是用C编写的,他们的性能都相当出色,但出了出色的性能,他们还有自己独特的功能:

1、Redis
Redis是一个很新的项目,刚刚发布了1.0版本。Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过10万次读写操作,是我知道的性能最快的Key-Value DB。

Redis的出色之处不仅仅是性能,Redis最大的魅力是支持保存List链表和Set集合的数据结构,而且还支持对List进行各种操作,例如从List两端push和pop数据,取List区间,排序等等,对Set支持各种集合的并集交集操作,此外单个value的最大限制是1GB,不像memcached只能保存1MB的数据,因此Redis可以用来实现很多有用的功能,比方说用他的List来做FIFO双向链表,实现一个轻量级的高性能消息队列服务,用他的Set可以做高性能的tag系统等等。另外Redis也可以对存入的Key-Value设置expire时间,因此也可以被当作一个功能加强版的memcached来用。

Redis的主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,并且它没有原生的可扩展机制,不具有scale(可扩展)能力,要依赖客户端来实现分布式读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。目前使用Redis的网站有github,Engine Yard。

2、Tokyo Cabinet和Tokoy Tyrant
TC和TT的开发者是日本人Mikio Hirabayashi,主要被用在日本最大的SNS网站mixi.jp上,TC发展的时间最早,现在已经是一个非常成熟的项目,也是Kye-Value数据库领域最大的热点,现在被广泛的应用在很多很多网站上。TC是一个高性能的存储引擎,而TT提供了多线程高并发服务器,性能也非常出色,每秒可以处理4-5万次读写操作。

TC除了支持Key-Value存储之外,还支持保存Hashtable数据类型,因此很像一个简单的数据库表,并且还支持基于column的条件查询,分页查询和排序功能,基本上相当于支持单表的基础查询功能了,所以可以简单的替代关系数据库的很多操作,这也是TC受到大家欢迎的主要原因之一,有一个Ruby的项目miyazakiresistance将TT的hashtable的操作封装成和ActiveRecord一样的操作,用起来非常爽。

TC/TT在mixi的实际应用当中,存储了2000万条以上的数据,同时支撑了上万个并发连接,是一个久经考验的项目。TC在保证了极高的并发读写性能的同时,具有可靠的数据持久化机制,同时还支持类似关系数据库表结构的hashtable以及简单的条件,分页和排序操作,是一个很棒的NoSQL数据库。

TC的主要缺点是在数据量达到上亿级别以后,并发写数据性能会大幅度下降,NoSQL: If Only It Was That Easy提到,他们发现在TC里面插入1.6亿条2-20KB数据的时候,写入性能开始急剧下降。看来是当数据量上亿条的时候,TC性能开始大幅度下降,从TC作者自己提供的mixi数据来看,至少上千万条数据量的时候还没有遇到这么明显的写入性能瓶颈。

这个是Tim Yang做的一个Memcached,Redis和Tokyo Tyrant的简单的性能评测,仅供参考

3、Flare
TC是日本第一大SNS网站mixi开发的,而Flare是日本第二大SNS网站green.jp开发的,有意思吧。Flare简单的说就是给TC添加了scale功能。他替换掉了TT部分,自己另外给TC写了网络服务器,Flare的主要特点就是支持scale能力,他在网络服务端之前添加了一个node server,来管理后端的多个服务器节点,因此可以动态添加数据库服务节点,删除服务器节点,也支持failover。如果你的使用场景必须要让TC可以scale,那么可以考虑flare。

flare唯一的缺点就是他只支持memcached协议,因此当你使用flare的时候,就不能使用TC的table数据结构了,只能使用TC的key-value数据结构存储。

二、满足海量存储需求和访问的面向文档的数据库:MongoDBCouchDB

面向文档的非关系数据库主要解决的问题不是高性能的并发读写,而是保证海量数据存储的同时,具有良好的查询性能。MongoDB是用C++开发的,而CouchDB则是Erlang开发的:

1、MongoDB
MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。他支持的数据结构非常松散,是类似json的bjson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

Mongo主要解决的是海量数据的访问效率问题,根据官方的文档,当数据量达到50GB以上的时候,Mongo的数据库访问速度是MySQL的10倍以上。Mongo的并发读写效率不是特别出色,根据官方提供的性能测试表明,大约每秒可以处理0.5万-1.5次读写请求。对于Mongo的并发读写性能,我(robbin)也打算有空的时候好好测试一下。

因为Mongo主要是支持海量数据存储的,所以Mongo还自带了一个出色的分布式文件系统GridFS,可以支持海量的数据存储,但我也看到有些评论认为GridFS性能不佳,这一点还是有待亲自做点测试来验证了。

最后由于Mongo可以支持复杂的数据结构,而且带有强大的数据查询功能,因此非常受到欢迎,很多项目都考虑用MongoDB来替代MySQL来实现不是特别复杂的Web应用,比方说why we migrated from MySQL to MongoDB就是一个真实的从MySQL迁移到MongoDB的案例,由于数据量实在太大,所以迁移到了Mongo上面,数据查询的速度得到了非常显著的提升。

MongoDB也有一个ruby的项目MongoMapper,是模仿Merb的DataMapper编写的MongoDB的接口,使用起来非常简单,几乎和DataMapper一模一样,功能非常强大易用。

2、CouchDB
CouchDB现在是一个非常有名气的项目,似乎不用多介绍了。但是我却对CouchDB没有什么兴趣,主要是因为CouchDB仅仅提供了基于HTTP REST的接口,因此CouchDB单纯从并发读写性能来说,是非常糟糕的,这让我立刻抛弃了对CouchDB的兴趣。

三、满足高可扩展性和可用性的面向分布式计算的数据库:Cassandra,Voldemort

面向scale能力的数据库其实主要解决的问题领域和上述两类数据库还不太一样,它首先必须是一个分布式的数据库系统,由分布在不同节点上面的数据库共同构成一个数据库服务系统,并且根据这种分布式架构来提供online的,具有弹性的可扩展能力,例如可以不停机的添加更多数据节点,删除数据节点等等。因此像Cassandra常常被看成是一个开源版本的Google BigTable的替代品。Cassandra和Voldemort都是用Java开发的:

1、Cassandra
Cassandra项目是Facebook在2008年开源出来的,随后Facebook自己使用Cassandra的另外一个不开源的分支,而开源出来的Cassandra主要被Amazon的Dynamite团队来维护,并且Cassandra被认为是Dynamite2.0版本。目前除了Facebook之外,twitter和digg.com都在使用Cassandra。

Cassandra的主要特点就是它不是一个数据库,而是由一堆数据库节点共同构成的一个分布式网络服务,对Cassandra的一个写操作,会被复制到其他节点上去,对Cassandra的读操作,也会被路由到某个节点上面去读取。对于一个Cassandra群集来说,扩展性能是比较简单的事情,只管在群集里面添加节点就可以了。我看到有文章说Facebook的Cassandra群集有超过100台服务器构成的数据库群集。

Cassandra也支持比较丰富的数据结构和功能强大的查询语言,和MongoDB比较类似,查询功能比MongoDB稍弱一些,twitter的平台架构部门领导Evan Weaver写了一篇文章介绍Cassandra:http://blog.evanweaver.com/articles/2009/07/06/up-and-running-with-cassandra/,有非常详细的介绍。

Cassandra以单个节点来衡量,其节点的并发读写性能不是特别好,有文章说评测下来Cassandra每秒大约不到1万次读写请求,我也看到一些对这个问题进行质疑的评论,但是评价Cassandra单个节点的性能是没有意义的,真实的分布式数据库访问系统必然是n多个节点构成的系统,其并发性能取决于整个系统的节点数量,路由效率,而不仅仅是单节点的并发负载能力。

2、Voldemort
Voldemort是个和Cassandra类似的面向解决scale问题的分布式数据库系统,Cassandra来自于Facebook这个SNS网站,而Voldemort则来自于Linkedin这个SNS网站。说起来SNS网站为我们贡献了n多的NoSQL数据库,例如Cassandar,Voldemort,Tokyo Cabinet,Flare等等。Voldemort的资料不是很多,因此我没有特别仔细去钻研,Voldemort官方给出Voldemort的并发读写性能也很不错,每秒超过了1.5万次读写。

从Facebook开发Cassandra,Linkedin开发Voldemort,我们也可以大致看出国外大型SNS网站对于分布式数据库,特别是对数据库的scale能力方面的需求是多么殷切。前面我(robbin)提到,web应用的架构当中,web层和app层相对来说都很容易横向扩展,唯有数据库是单点的,极难scale,现在Facebook和Linkedin在非关系型数据库的分布式方面探索了一条很好的方向,这也是为什么现在Cassandra这么热门的主要原因。

如今,NoSQL数据库是个令人很兴奋的领域,总是不断有新的技术新的产品冒出来,改变我们已经形成的固有的技术观念,我自己(robbin)稍微了解了一些,就感觉自己深深的沉迷进去了,可以说NoSQL数据库领域也是博大精深的,我(robbin)也只能浅尝辄止,我(robbin)写这篇文章既是自己一点点钻研心得,也是抛砖引玉,希望吸引对这个领域有经验的朋友来讨论和交流。

从我(robbin)个人的兴趣来说,分布式数据库系统不是我能实际用到的技术,因此不打算花时间深入,而其他两个数据领域(高性能NoSQLDB和海量存储NoSQLDB)都是我很感兴趣的,特别是Redis,TT/TC和MongoDB这3个NoSQL数据库,因此我接下来将写三篇文章分别详细介绍这3个数据库

posted @ 2012-06-28 14:28 小马歌 阅读(208) | 评论 (0)编辑 收藏
 
     摘要: 本文参考自官方的手册:http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-ConditionalOperators%3A%3C%2C%3C%3D%2C%3E%2C%3E%3D1 ) . 大于,小于,大于或等于,小于或等于$gt:大于$lt:小于$gte:大于或等于$lte:小于或等于例子:db.collectio...  阅读全文
posted @ 2012-06-28 14:15 小马歌 阅读(194) | 评论 (0)编辑 收藏
 
     摘要: 在前面的文章“mongodb 查询的语法”里,我介绍了Mongodb的常用查询语法,Mongodb的update操作也有点复杂,我结合自己的使用经验,在这里介绍一下,给用mongodb的朋友看看,也方便以后自己用到的时候查阅:注:在这篇文章及上篇文章内讲的语法介绍都是在mongodb shell环境内的,和真正运用语言编程(如java,php等)使用时,...  阅读全文
posted @ 2012-06-28 14:14 小马歌 阅读(4110) | 评论 (0)编辑 收藏
 
一、连接数据库主机
连接本地主机,端口为27017:
$connection = new Mongo();
连接远程主机,端口为默认端口:
$connection= new Mongo( "192.168.2.1" );
连接远程主机,端口为指定端口:
$connection = new Mongo( "192.168.2.1:65432" );
选择数据库,如果指定的数据库不存在,则会自动创建一个新的数据库,有2种方法:
$db = $connection->selectDB('dbname');
$db = $connection->dbname;
选择集合(collection),与使用关系型数据库中的表类似,有2种方法:
$collection = $db->selectCollection('people');
$collection = $db->people;
二、插入新文档(document)
collection对象用来执行信息管理,例如,想存储一个关于某人的信息,可以如下编码:
$person = array(
 'name' => 'Cesar Rodas',
 'email' => 'crodas@php.net',
 'address' => array(
  array(
   'country' => 'PY',
   'zip' => '2160',
   'address1' => 'foo bar'
  ),
  array(
   'country' => 'PY',
   'zip' => '2161',
   'address1' => 'foo bar bar foo'
  ),
 ),
 'sessions' => 0,
);
$safe_insert = true;
$collection->insert($person, $safe_insert);
$person_identifier = $person['_id'];
其中:
$safe_insert参数用于等待MongoDB完成操作,以便确定是否成功,默认值为false,当有大量记录插入时使用该参数会比较有用。
插入新文档后,MongoDB会返回一个记录标识。
三、更新文档
例如,更新上面已经创建的个人信息,增加sessions属性值,在第1个address处增加address2属性,删除第2个address,代码如下:
首先,定义一个filter(过滤器)告诉MongoDB要更新一个指定的文档
$filter = array('email' => 'crodas@php.net');
$new_document = array(
 '$inc' => array('sessions' => 1),
 '$set' => array(
   'address.0.address2' =>  'Some foobar street',
 ),
 '$unset' => array('address.1' => 1),
);
$options['multiple'] = false;
$collection->update(
 $filter,
 $new_document,
 $options
);
MongoDB也支持批量更新,与关系型数据库类似,可以更新给定条件的所有文档,如果想这么做的话,就需要设置options的multiple的值为true.
四、查询文档
定义一个符合给定标准的条件过滤器,通过使用查询选择器来获取文档。
例,通过e-mail address来获取信息:
$filter = array('email' => 'crodas@php.net');
$cursor = $collection->find($filter);
foreach ($cursor as $user) 
{
  var_dump($user);
}
例,获取sessions大于10的信息:
$filter = array('sessions' => array('$gt' => 10));
$cursor = $collection->find($filter);
例,获取没有设置sessions属性的信息:
$filter = array(
 'sessions' => array('$exists' => false)
);
$cursor = $collection->find($filter);
例,获取地址在PY并且sessions大于15的信息:
$filter = array(
 'address.country' => 'PY',
 'sessions' => array('$gt' => 10)
);
$cursor = $collection->find($filter);
有一个重要的细节需要注意,只有当需要结果的时候查询才会被执行,在第1个例子中,当foreach循环开始时,查询才被执行。
这是个很有用的特性,因为这可以通过在游标(cursor)中增加选项来取回结果,恰好在定义查询后,执行查询前这个时刻。例如,可以设置选项来执行分页,或者获取指定数目的匹配的文档。
$total = $cursor->total();
$cursor->limit(20)->skip(40);
foreach($cursor as $user) {
}
五、获取文档的聚类
MongoDB支持结果的聚类,类似于关系数据库,可以使用count,distinct和group等聚类操作。
聚类查询返回数组(array),而不是整个文档对象。
分组操作允许定义用Javascript编写的MongoDB服务器端功能,该操作执行分组属性。因为可以执行许多带有分组值的操作类型,所以会更灵活,但是相比SQL执行例如SUM(),AVG()等
简单的分组操作来说,这还是有些困难。
下面这个例子演示了如何获取国家的的地址列表,以及匹配地址的国家出现的次数:
$countries = $collection->distinct(
 array("address.country")
);
$result = $collection->group(
 
 array("address.country" => True),
 
 array("sum" => 0),    
    
 "function (obj, prev) { prev.sum += 1; }",
 
 array("session" => array('$gt' => 10))
);
六、删除文档
删除文档与获取或更新文档很类似。
$filter = array('field' => 'foo');
$collection->remove($filter);
要注意,默认所有符合条件的文档都会被删除,如果只想删除符合条件的第1个文档,那么在给remove函数的第二个参数赋值为true。
七、索引支持
有一个很重要的特点,使得决定选择MongoDB,而不是选择其它的类似的面向文档的数据库,这个特点就是对索引的支持,这和关系型数据库的表索引很类似,并不是所有的面向文档的数据库都
提供内置的索引支持。
使用MongoDB的创建索引功能可以避免在查询期间在所有文档中进行操作,这就象关系数据库中使用索引来避免全表查询一样。这可以加速那些涉及到索引属性的符合条件的文档的查询。
例如,如果想在e-mail地址属性上建立唯一的索引,如下所示:
$collection->ensureIndex(
 array('email' => 1),
 array('unique' => true, 'background' => true)
);
第1个数组参数描述将要成为索引的所有属性,可以是1个或多个属性。
默认情况下,索引的创建是一个同步操作,所以,如果文档数目很大的话,把索引的创建放在后台运行会是个好主意,就象上面例子所演示的。
只有一个属性的索引可能不够用,下面这个例子演示如何通过在2个属性上定义索引来加速查询。
$collection->ensureIndex(  
  array('address.country' => 1, 'sessions' => 1),
  array('background' => true)
);
每个索引的值定义了索引的顺序:1表示降序(descending),-1表示升序(ascending)
索引顺序在有排序选项的查询优化中是有用的,如下例所示:
$filter = array(    
 'address.country' => 'PY',
);
$cursor = $collection->find($filter)->order(
  array('sessions' => -1)
);
$collection->ensureIndex(
 array('address.country' => 1, 'sessions' => -1),
 array('background' => true)
);

 

 

八、实际应用
一些开发人员可能害怕使用一种新型的数据库,因为它和他们以前工作中用过的那些不同。
在理论上学习新事物不同于在实践中学习如何使用,所以,这部分内容将通过比较基于SQL的关系型数据库,比如MySQL,来解释如何用MongoDB来开发实际应用,这样就可以熟悉这两种途径
的不同。
例如,我们将构建一个blog系统,有用户,提交和评论功能。在使用关系型数据库的时候,你可以象下面这样通过定义表模式来实现它。


在MongoDB中实现同样的文档定义如下:
$users = array(
 'username' => 'crodas',   
 'name' => 'Cesar Rodas',
);
$posts = array(
 'uri' => '/foo-bar-post',
 'author_id' => $users->_id,
 'title' => 'Foo bar post',
 'summary' => 'This is a summary text',
 'body' => 'This is the body',
 'comments' => array(
  array(
   'name' => 'user',
   'email' => 'foo@bar.com',
   'content' => 'nice post'
  ) 
 )
);
你可能注意到,我们只用一个文档就代替了posts和comments两个表,这是因为comments是post文档的子文档。这样做使实现更简单,在你想存取发布内容和它的评论时,会节省查询数据库的时间。
为了更简洁,用户所做评论的细节可以和评论的定义合并,所以你可以用一个查询来获取所发布的内容,评论和用户这些信息。
$posts = array(
 'uri' => '/foo-bar-post',
 'author_id' => $users->_id,
 'author_name' => 'Cesar Rodas',
 'author_username' => 'crodas',
 'title' => 'Foo bar post',
 'summary' => 'This is a summary text',
 'body' => 'This is the body',
 'comments' => array(
  array(
   'name' => 'user',
   'email' => 'foo@bar.com',
   'comment' => 'nice post'
  ), 
 )
);
这意味着会存在一些重复信息,但现在磁盘空间比CPU的RAM要便宜得多,以空间换时间,网站访问者的耐心和时间更重要。如果你关注重复信息的同步,那么在更新author信息的时候,你可以执行下面这个更新查询来解决这个问题。
$filter = array(   
 'author_id' => $author['_id'],
);
$data = array(
 '$set' => array(
  'author_name' => 'Cesar D. Rodas',
  'author_username' => 'cesar',
 )
);
$collection->update($filter, $data, array(
  'multiple' => true)
);
以上是我们对数据模型的转换和优化,下面将重写一些用在MongoDB中的和SQL等价的查询。
SELECT * FROM posts
 INNER JOIN users ON users.id = posts.user_id
 WHERE URL = :url;
SELECT  * FROM comments WHERE post_id = $post_id;
首先,增加索引:
$collection->ensureIndex( 
 array('uri' => 1),
 array('unique' => 1, 'background')
);
$collection->find(array('uri' => '<uri>'));
INSERT INTO comments(post_id, name, email, contents)
 VALUES(:post_id, :name, :email, :comment);
$comment = array(   
 'name' => $_POST['name'],   
 'email' => $_POST['email'],   
 'comment' => $_POST['comment'],
);
$filter = array(
 'uri' => $_POST['uri'], 
);
$collection->update($filter, array(
 '$push' => array('comments' => $comment))
);
SELECT * FROM posts WHERE id IN (
 SELECT DISTINCT post_id FROM comments WHERE email = :email
);
首先,增加索引:
$collection->ensureIndex(
 array('comments.email' => 1),
 array('background' => 1)
);
$collection->find( array('comments.email' => $email) );
九、用MongoDB存储文件
MongoDB也提供许多超过基本数据库操作的特点。例如,它提供了在数据库中存储小文件和大文件的解决方案。
文件被自动分块(块)。如果MongoDB运行在自动分片(auto-sharded)环境,文件块也会被跨多个服务器复制。
有效地解决文件的存储是一个相当困难的问题,尤其是当你需要管理大量的文件时。把文件保存在本地文件系统中通常不是个好的方案。
一个困难的例子是YouTube必须有效地服务那些上百万视频的小图片,或者由Facebook为数十亿图片提供的高效运行服务。
MongoDB通过创建两个内部集合(collections)来解决这个问题:文件集合保存关于文件元数据的信息,块集合保存关于文件块的信息。
如果你想存储一个大的视频文件,你可以使用如下这样的代码:
$metadata = array(
 "filename" => "path.avi",
 "downloads" => 0,   
 "comment" => "This file is foo bar",   
 "permissions" => array(
  "crodas" => "write",  
  "everybody" => "read",
 )
);
$grid = $db->getGridFS();
$grid->storeFile("/file/to/path.avi", $metadata);
正如你所看到的,这很简单且容易理解。
十、Map-Reduce
Map-Reduce是一种处理大量信息的操作手段。map操作应用于每个文档并产生一套新的key-value数据对。reduce操作使用map功能产生的结果并产生基本每个key的单一结果。
MongoDB Map-Reduce功能可以应用到集合上用于数据转换,这和Hadoop很类似。
当map处理完成后,结果被保存并且通过键值(key value)被分组。对每个结果键(key),使用2个参数来调用reduce功能:键(key)及其所有值的数组。
为了更好地理解它的工作原理,我们假设有了前面定义过的blog的提交文档,接下来你想使每个提交的内容有一系列的tag,如果你想获得关于这些tag的统计情况,你只需要像下面这样计算一下即可:
首先定义map和reduce功能代码,
$map = new  MongoCode("function () {
  var i;
  for (i=0; i < this.tags.length; i++) {
  
   emit(this.tags[i], {count: 1});
  }
}");
$reduce = new MongoCode("function (key, values) {
  var i, total=0;
  for (i=0; i < values.length; i++) {
   total = values[i].count;
  }
  return {count: total}
}");
然后执行map-reduce命令:
$map_reduce = array(
 
 'out' => 'tags_info',
 
 'verbose' => true,
 
 'mapreduce' => 'posts',
 'map' => $map,
 'reduce' => $reduce,
);
$information = $db->command($map_reduce);
var_dump($information);
如果MongoDB运行在切片(sharded)环境,那么这个数据处理功能将会在所有shard节点上并行。
要知道执行map-reduce处理通常是很慢的。它的目的是把大量的数据分布在许多服务器上。所以,如果你有许多服务器,你就可以把这个操作分布在这些服务器上进行处理并获得结果,这会比在一台服务器上运行所需的时间要少得多。
建议在后台运行map-reduce处理,因为它们需要花比较长的时候才能完成。在这种情况下,如果通过Gearman来异步管理启动它是个不错的方法。
十一、Auto-sharding
在前面多次提到sharding,但你可能并不熟悉这个概念。
Data sharding是一种把数据分布在多个服务器上的数据库技术手段。
MongoDB只需要很少的配置就可完成auto-sharding。然而,安装和配置一个shard已超出本文章的范围。
下面这张图展示了工作在shard环境中的MongoDB,这样你会在你使用sharding时都发生了什么有个了解。


 十二、其它
正则表达式使用面面的格式:
"/<regex>/<flags>"
和SQL语句中的 username LIKE '%bar%'等价的方式如下:
<?php
$filter = array(
'username' => new MongoRegex("/.*bar.*/i"),
);
$collection->find($filter);
?>
在使用Regex时要小心,大多时候它不能使用索引,因此它将对整个数据扫描,所以比较好的方法是对文档的数目进行限制。
<?php
$filter = array(
'username' => new MongoRegex("/.*bar.*/i"),
'karma' => array('$gt' => 10),
);
$collection->find($filter);
?>
使用Regex可以完成如下这个复杂的查询:
<?php
$filter = array(
'username' => new MongoRegex("/[a-z][a-z0-9\_]+(\_[0-9])?/i"),
'karma' => array('$gt' => 10),
);
$collection->find($filter);
?>
posted @ 2012-06-25 17:13 小马歌 阅读(3937) | 评论 (0)编辑 收藏
 

ECSHOP2.7.2 本来是个不错的网店程序,但由于版权多出加密,有些需要去除版权的朋友会碰到一些困难,本人特整理分享最新版ecshop去处版权方法给大家分享:

1.删除顶部标题栏"Powered by Ecshop"信息:

使用文本编辑器(推荐Dreamweaver,UltraEdit,记事本编辑容易出错请勿用)打开 ecshop根目录/includes/lib_main.php, 找到如下代码:
/* 初始化“页面标题”和“当前位置” */
$page_title = $GLOBALS['_CFG']['shop_title'] . ' - ' . 'Powered by ECShop';
在这一句的Powered by ECShop就是标题栏的版权部分,可以删除或者改成你自己想显示的其他文字内容

2 .细心的朋友可能发现,按第一点删改版权后ECshop像发疯一样会在页面上随机出现Powered by ECShop文字,这是因为康盛公司的防盗版措施,我们还需要这一步骤操作

找到js/common.js文件
   该文件第261行到第353行代码删除。就是以下代码

  1.    onload = function()
  2. {
  3. var link_arr = document.getElementsByTagName(String.fromCharCode(65));
  4. var link_str;
  5. var link_text;
  6. var regg, cc;
  7. var rmd, rmd_s, rmd_e, link_eorr = 0;
  8. var e = new Array(97, 98, 99,
  9.                   100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
  10.                   110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
  11.                   120, 121, 122
  12.                   );
  13.    try
  14.    {
  15. for(var i = 0; i < link_arr.length; i++)
  16. {
  17.    link_str = link_arr.href;
  18.    if (link_str.indexOf(String.fromCharCode(e[22], 119, 119, 46, e[4], 99, e[18], e[7], e[14],
  19.                                           e[15], 46, 99, 111, e[12])) != -1)
  20.    {
  21.        if ((link_text = link_arr.innerText) == undefined)
  22.        {
  23.          throw "noIE";
  24.        }
  25.        regg = new RegExp(String.fromCharCode(80, 111, 119, 101, 114, 101, 100, 46, 42, 98, 121,
  26. 46, 42, 69, 67, 83, e[7], e[14], e[15]));
  27.        if ((cc = regg.exec(link_text)) != null)
  28.        {
  29.       if (link_arr.offsetHeight == 0)
  30.       {
  31.          break;
  32.       }
  33.       link_eorr = 1;
  34.       break;
  35.        }
  36.    }
  37.    else
  38.    {
  39.        link_eorr = link_eorr ? 0 : link_eorr;
  40.        continue;
  41.    }
  42. }
  43.    } // IE
  44.    catch(exc)
  45.    {
  46. for(var i = 0; i < link_arr.length; i++)
  47. {
  48.    link_str = link_arr.href;
  49.    if (link_str.indexOf(String.fromCharCode(e[22], 119, 119, 46, e[4], 99, 115, 104, e[14],
  50.                                               e[15], 46, 99, 111, e[12])) != -1)
  51.    {
  52.        link_text = link_arr.textContent;
  53.        regg = new RegExp(String.fromCharCode(80, 111, 119, 101, 114, 101, 100, 46, 42, 98, 121,
  54. 46, 42, 69, 67, 83, e[7], e[14], e[15]));
  55.        if ((cc = regg.exec(link_text)) != null)
  56.        {
  57.       if (link_arr.offsetHeight == 0)
  58.       {
  59.          break;
  60.       }
  61.       link_eorr = 1;
  62.       break;
  63.        }
  64.    }
  65.    else
  66.    {
  67.        link_eorr = link_eorr ? 0 : link_eorr;
  68.        continue;
  69.    }
  70. }
  71.    } // FF
  72.    try
  73.    {
  74. rmd = Math.random();
  75. rmd_s = Math.floor(rmd * 10);
  76. if (link_eorr != 1)
  77. {
  78.    rmd_e = i - rmd_s;
  79.    link_arr[rmd_e].href = String.fromCharCode(104, 116, 116, 112, 58, 47, 47, 119, 119,
  80. 119,46,
  81.                                                    101, 99, 115, 104, 111, 112, 46, 99, 111,
  82. 109);
  83.    link_arr[rmd_e].innerHTML = String.fromCharCode(
  84.                                     80, 111, 119, 101, 114, 101, 100,38, 110, 98, 115, 112,
  85. 59, 98,
  86.                                     121,38, 110, 98, 115, 112, 59,60, 115, 116, 114, 111,
  87. 110, 103,
  88.                                     62, 60,115, 112, 97, 110, 32, 115, 116, 121,108,101, 61,
  89. 34, 99,
  90.                                     111, 108, 111, 114, 58, 32, 35, 51, 51, 54, 54, 70, 70,
  91. 34, 62,
  92.                                     69, 67, 83, 104, 111, 112, 60, 47, 115, 112, 97, 110,
  93. 62,60, 47,
  94.                                     115, 116, 114, 111, 110, 103, 62);
  95. }
  96.    }
  97.    catch(ex)
  98.    {
  99.    }
  100. }

打开模板文件,例如默认的模板page_footer.lbi

位于模板文件夹的 library/page_footer.lbi

删除 {foreach from=$lang.p_y item=pv}{$pv}{/foreach}{$licensed}

4.上面的3步操作基本上完成了基本版权的去处,至于友情链接上的ecshop是在后台的友情链接项目内,自己修改或删除即可。logo也是在后台网店设置里面,上传你自己的logo.gif文件会把默认的ecshop logo替换掉。

.有的朋友可能还需要进一步去处后台版权,怎么去处呢,请继续看:

5.1 后台的ecshop 两张图片位置如下:

admin/images/ecshop_logo.gif

admin/images/login.png 请把这2张图片替换成你自己的图片,大小最好相同

5.2 右上角的“关于ECSHOP”文字去除

打开admin/templates/top.htm

删除: <li><a href="index.php?act=about_us" target="main-frame">{$lang.about}</a></li>

5.3 中部 ECSHOP 管理中心, 和底部的版权所有

打开language/zh_cn/admin/common.php

$_LANG['cp_home'] = 'ECSHOP 管理中心';
$_LANG['copyright'] = '版权所有 &copy; 2005-2009 上海商派网络科技有限公司,并保留所有权利。

×××××××××××××××××××××××××××××××××××××××××××××

上面是本人给大家整理的ecshop2.7.2去处版权的方法,希望对你有帮助


删除ECSHOP2.7.3后台左侧菜单中的云服务中心
2012-04-25 12:32

ECSHOP2.7.3后台左侧菜单中增加了一个“云服务器中心”,
若是给客户使用可能不是很美观,如果我想删除掉该怎么办捏?

本站为你提供如下操作教程:


打开ecshop2.7.3,
找到admin/cloud.php 文件。
搜索 cloud.ecshop.com
大概在60行 ,140行,228行
分别在每行前面加“//”注释掉,或者将整行删除,这样后台云中心菜单自动隐藏掉了。

还有个办法是在ECSHOP后台模板里修改,menu.htm,start.htm 搜索cloud.php?is_ajax=1 把整段JS 删除

(注不需要动ECSHOP模板文件的)

posted @ 2012-06-22 09:09 小马歌 阅读(1566) | 评论 (0)编辑 收藏
 

查看索引:
db.user_info.getIndexes();

 

建立索引:
db.user_info.ensureIndex({"name":1});

----------------------------------------------------------------------------------


mongodb 删除数据库

use test;

 db.dropDatabase();

 mongodb删除表

 db.mytable.drop();

----------------------------------------------------------------------------------

MongoDB用户权限分配的操作是针对某个库来说的。--这句话很重要。

 

1、 进入ljc 数据库:      

use ljc;              --ljc为数据库名称。

2、添加用户(读写权限,readOnly-->false):

 db.addUser("java","java");

3、 查看一下所有的用户

db.system.users.find();


{ "_id" : ObjectId("4e02a89fb841deb5fda3e5e2"), "user" : "java", "readOnly" : fa
lse, "pwd" : "59cf7cc156874cbd35cb00869126f569" }

4、用户授权。

db.auth("java","java");

1                                         显示为1 表示授权成功,0表示不成功。


 
5、 添加用户(只读权限,readOnly-->true):

db.addUser("java1","java1",true);
db.system.users.find();
{ "_id" : ObjectId("4e02a89fb841deb5fda3e5e2"), "user" : "java", "readOnly" : fa
lse, "pwd" : "59cf7cc156874cbd35cb00869126f569" }
{ "_id" : ObjectId("4e02aae6b841deb5fda3e5e3"), "user" : "java1", "readOnly" : t
rue, "pwd" : "fca6bda05c87a72cce0a4a6458d1e266" }

注意上面标红的位置的readOnly 只读于可写是有区别的。

 

6、更改密码(为已经存在的用户更改密码):

 db.addUser("java","java1");

 

7、删除用户:

db.system.users.remove({user:"java1"});

posted @ 2012-06-15 15:51 小马歌 阅读(333) | 评论 (0)编辑 收藏
仅列出标题
共95页: First 上一页 35 36 37 38 39 40 41 42 43 下一页 Last