宠辱不惊,看庭前花开花落;去留无意,望天空云卷云舒
2011-01-13Java,编程技术

没有评论
949 Views

二级域名的java实现

涉及到为用户提供一个二级域名功能,实现方法如下:

(1)首先要在域名服务商端做一个泛域名解析. 我用的是godaddy.com,就新建一个A记录(host=*,point to指向我的服务器的ip),这样所有二级域名都会转到我的服务器来了

(2)接着在web.xml配一个自已写的域名过滤器,

<filter>

<filter-name>URLFilter</filter-name>

<filter-class>com.yowob.commons.URLFilter</filter-class>

</filter>

<filter-mapping>

<filter-name>URLFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

过滤器的代码如下。这里先将二级域名和全球域名和用户ID的映射,保存在一个数据表里, 然后访问进来时对地址做一个判断, 再取出对应的用户ID. 再转一下就行了. 我的静态文件都在static目录,所以还加了一个static的判断。

比如: http://time.you.com/board/21 用time对应用户ID为6,则访问效果有 http://www.you.com/6/board/21相同, 不过地址栏还是显示http://time.you.com/board/21。

再比如:htttp://www.userdomain.com/board/21,这个是用户ID为6的全球域名,访问效果也和上面一样。

package com.yowob.commons;

import java.io.IOException;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import javax.servlet.Filter;

import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;

import org.apache.commons.lang.math.NumberUtils;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import com.yowob.Constants;

import com.yowob.dao.SiteDAO;

import com.yowob.dto.SiteDTO;

public class URLFilter implements Filter {

private static final Log log = LogFactory.getLog(URLFilter.class);

private static final String DOMAIN_END = “.” + Constants.DOMAIN; //.you.com

private static final Map<String, Long> NAME_MAP = new HashMap<String, Long>();

private static final Map<String, Long> DOMAIN_MAP = new HashMap<String, Long>();

@Override

public void init(FilterConfig filterConfig) throws ServletException {

log.info(“——————————init”);

SiteDAO siteDAO = new SiteDAO();

List<SiteDTO> list = siteDAO.getAll();

for (SiteDTO siteDTO : list) {

String name = siteDTO.getName();

if (StringUtils.isNotEmpty(name)) {

NAME_MAP.put(name, siteDTO.getId());

}

String domain = siteDTO.getDomain();

if (StringUtils.isNotEmpty(domain)) {

DOMAIN_MAP.put(domain, siteDTO.getId());

}

}

}

public static void updateName(String oldValue, String newValue, Long siteId) {

if (StringUtils.equals(oldValue, newValue)) {

return;

}

if (StringUtils.isNotEmpty(oldValue)) {

NAME_MAP.remove(oldValue);

}

if (StringUtils.isNotEmpty(newValue)) {

NAME_MAP.put(newValue, siteId);

}

}

public static void updateDomain(String oldValue, String newValue, Long siteId) {

if (StringUtils.equals(oldValue, newValue)) {

return;

}

if (StringUtils.isNotEmpty(oldValue)) {

DOMAIN_MAP.remove(oldValue);

}

if (StringUtils.isNotEmpty(newValue)) {

DOMAIN_MAP.put(newValue, siteId);

}

}

@Override

public void destroy() {

log.info(“——————————destroy”);

}

@Override

public void doFilter(ServletRequest servletRequest, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {

HttpServletRequest request = (HttpServletRequest) servletRequest;

String requestURI = request.getRequestURI();

String serverName = request.getServerName().toLowerCase();

String realURI = getRealRequestURI(serverName, requestURI);

request.getRequestDispatcher(realURI).forward(request, response);

}

private String getRealRequestURI(String serverName, String requestURI) {

if (Constants.WWW_DOMAIN.equals(serverName) || requestURI.startsWith(“/static/”) || Constants.DOMAIN.equals(serverName)) {

return requestURI;

}

if (serverName.endsWith(DOMAIN_END)) {

String secondDomain = serverName.substring(0, serverName.indexOf(“.”));

//网站id

if (NumberUtils.isNumber(secondDomain))

return getURI(secondDomain, requestURI);

//网站英文名

Long siteId = NAME_MAP.get(secondDomain);

if (siteId == null) {

//保留的二级域名

if (Constants.isPrivateSecondDomain(secondDomain)) {

return requestURI;

}

return “/message?msg=不存在二级域名” + secondDomain;

// throw new RuntimeException(“do not exist second domain: ” + secondDomain);

}

return getURI(siteId + “”, requestURI);

}

//域名

Long siteId = DOMAIN_MAP.get(serverName);

if (siteId == null) {

return requestURI;

} else {

return getURI(siteId + “”, requestURI);

}

}

private static String getURI(String siteId, String requestURI) {

if (requestURI.equals(“/”)) {

return “/” + siteId;

} else {

return “/” + siteId + requestURI;

}

}

}

其他一些小技巧:

(1)为了便于本机测试,可以修改windows 的hosts文件。我的如下:

127.0.0.1 localhost

127.0.0.1 you.com

127.0.0.1 www.you.com

127.0.0.1 time1.you.com

127.0.0.1 time2.you.com

127.0.0.1 6.you.com

127.0.0.1 www.bobo.com

(2)web页的各种地址则要注意相对路径的问题。主要考虑

首先设置<base href=”http://www.yowob.com/” />,或<base href=”http://www.yowob.com/6/” />其中地址最后要加一个/

然后页面中其他地址前面不加/,就是相对地址(以地址栏为基础)。加上/,则是绝对地址。

[转]百万级访问网站前期的技术准备

作者:一路凯歌
来源:http://zhiyi.us/

开了自己域名的博客,第一篇就得来个重磅一点的才对得起这4美金的域名。作为一个技术从业者十年,逛了十年发现有些知识东一榔头西一棒槌的得满世界 看个遍才整理出个头绪,那咱就系统点的从头一步一步的说,一个从日几千访问的小小网站,到日访问一两百万的小网站,怎么才能让它平滑的度过这个阶段,别在 技术上出现先天不足,写给一些技术人员,也写给不懂技术的创业者。

对互联网有了解的人都有自己的想法,有人就把想法付诸实现,做个网站然后开始运营。其实从纯网站技术上来说,因为开源模式的发展,现在建一个小网站 已经很简单也很便宜。当访问量到达一定数量级的时候成本就开始飙升了,问题也开始显现了。因为带宽的增加、硬件的扩展、人员的扩张所带来的成本提高是显而 易见的,而还有相当大的一部分成本是因为代码重构、架构重构,甚至底层开发语言更换引起的,最惨的就是数据丢失,辛辛苦苦好几年,一夜回到创业前。

减少成本就是增加利润。很多事情,我们在一开始就可以避免,先打好基础,往后可以省很多精力,少操很多心。

假设你是一个参与创业的技术人员,当前一穷二白,什么都要自己做,自己出钱,初期几十万的资金,做一个应用不是特别复杂的网站,那么就要注意以下几点:

一、开发语言

一般来说,技术人员(程序员)创业都是根据自己技术背景选择自己最熟悉的语言,不过考虑到不可能永远是您一个人写程序,这点还得仔细想想。无论用什么语言,最终代码质量是看管理,所以我们还是从纯语言层面来说实际一点。现在流行的javaphp.netpythonruby都 有自己的优劣,python和ruby,现在人员还是相对难招一些,性能优化也会费些力气,.net平台买不起windows server。java、php用的还是最多。对于初期,应用几乎都是靠前端支撑的网站来说,php的优势稍大一些,入门简单、设计模式简单、写起来快、 性能足够等,不过不注重设计模式也是它的劣势,容易变得松散,隐藏bug稍多、难以维护。java的优势在于整套管理流程已经有很多成熟工具来辅助,强类 型也能避免一些弱智BUG,大多数JAVA程序员比较注重设计模式,别管实不实际,代码格式看起来还是不错的。这也是个劣势,初学者可能太注重模式而很难 解决实际需求。

前端不只是html、css这类。整个负责跟用户交互的部分都是前端,包括处理程序。这类程序还是建议用php,主要原因就是开发迅速、从业人员广泛。至于后端例如行为分析、银行接口、异步消息处理等,随便用什么程序,那个只能是根据不同业务需求来选择不同语言了。

二、代码版本管理

如果开发人员之间的网络速度差不多,就SVN;比较分散例如跨国,就hg。大多数人还是svn的.

假设选了svn,那么有几点考虑。一是采用什么树结构。初期可能只有一条主干,往后就需要建立分支,例如一条开发分支,一条上线分支,再往后,可能 要每个小组一个分支。建议一开始人少时选择两条分支,开发和线上,每个功能本地测试无误后提交到开发分支,最后统一测试,可以上线时合并到上线分支。如果 喜欢把svn当做移动硬盘用,写一点就commit一次也无所谓,就是合并的时候头大一些,这些人可以自己建个分支甚至建立个本地代码仓库,随便往自己的 分支提交,测试完毕后再提交到开发分支上。

部署,可以手工部署也可以自动部署。手工部署相对简单,一般是直接在服务器上svn update,或者找个新目录svn checkout,再把web root给ln -s过去。应用越复杂,部署越复杂,没有什么统一标准,只要别再用ftp上传那种形式就好,一是上传时文件引用不一致错误率增加,二是很容易出现开发人员 的版本跟线上版本不一致,导致本来想改个错字结果变成回滚的杯具。如果有多台服务器还是建议自动部署,更换代码的机器从当前服务池中临时撤出,更新完毕后 再重新加入。

不管项目多小,养成使用版本管理的好习惯,最起码还可以当做你的备份,我的 http://zhiyi.us 虽然就是一个wordpress,可还是svn了,只改动一两句css那也是劳动成果。

三、服务器硬件

别羡慕大客户和有钱人,看看机房散户区,一台服务器孤独的支撑的网站数不清。如果资金稍微充足,建议至少三台的标准配置,分别用作web处理、数据 库、备份。web服务器至少要8G内存,双sata raid1,如果经济稍微宽松,或静态文件或图片多,则15k sas raid1+0。数据库至少16G内存,15k sas raid 1+0。备份服务器最好跟数据库服务器同等配置。硬件可以自己买品牌的底板,也就是机箱配主板和硬盘盒,CPU内存硬盘都自己配,也可以上整套品牌,也可 以兼容机。三台机器,市场行情6、7万也就配齐了。

web服务器可以既跑程序又当内存缓存,数据库服务器则只跑主数据库(假如是MySQL的话),备份服务器干的活就相对多一些,web配置、缓存配置、数据库配置都要跟前两台一致,这样WEB和数据库任意一台出问题,把备份服务器换个ip就切换上去了。备份策略,可以drbd,可以rsync,或者其他的很多很多的开源备份方案可选择。rsync最简单,放cron里自己跑就行。备份和切换,建议多做测试,选最安全最适合业务的,并且尽可能异地备份。

四、机房

三种机房尽量不要选:联通访问特别慢的电信机房、电信访问特别慢的联通机房、电信联通访问特别慢的移动或铁通机房。那网通机房呢?亲,网通联通N久 以前合并改叫联通了。多多寻找,实地参观,多多测试,多方打探,北京、上海、广州等各个主节点城市,还是有很多优质机房的,找个网络质量好,管理严格的机 房,特别是管理要严格,千万别网站无法访问了,打个电话过去才知道别人维护时把你网线碰掉了,这比DOS都头疼。自己扯了几根光纤就称为机房的,看您抗风 险程度和心理素质了。机房可以说是非常重要,直接关系到网站访问速度,网站访问速度直接关系到用户体验,我可以翻墙看风景,但买个网游vpn才能打开你这 个还不怎么知名的网站就有难度了。或许您网站的ajax很出色,可是document怎么也不ready,一些代码永远绝缘于用户。

五、架构

初期架构一般比较简单,web负载均衡+数据库主从+缓存+分布式存储+队列。大方向上也确实就这几样东西,细节上也无数文章都重复过了,按照将来 会有N多WEB,N多主从关系,N多缓存,N多xxx设计就行,基本方案都是现成的,只是您比其他人厉害之处就在于设计上考虑到缓存失效时的雪崩效应、主 从同步的数据一致性和时间差、队列的稳定性和失败后的重试策略、文件存储的效率和备份方式等等意外情况。缓存总有一天会失效,数据库复制总有一天会断掉, 队列总有一天会写不进去,电源总有一天会烧坏。根据墨菲定律,如果不考虑这些,网站早晚会成为茶几。

六、服务器软件

Linux、nginx、php、mysql,几乎是标配,我们除了看名字,还得选版本。Linux发行版众多,只要没特殊要求,就选个用的人最多的,社区最活跃的,配置最方便的,软件包最全最新的,例如debianubuntu。 至于RHEL之类的嘛,你用只能在RHEL上才能运行的软件么?剩下的nginx、php、mysql、activemq、其他的等等,除非你改过这些软 件或你的程序真的不兼容新版本,否则尽量版本越新越好,版本新,意味着新特性增多、BUG减少、性能增加。总有些道听途说的人跟你说老的版本稳定。所谓稳 定,是相对于特殊业务来说的,而就一个php写的网站,大多数人都没改过任何服务器软件源代码,绝大多数情况是能平稳的升级到新版本的。类似于jdk5到 jdk6,python2到python3这类变动比较大的升级还是比较少见的。看看ChangeLog,看看升级说明,结合自己情况评估一下,越早升级 越好,别人家都用php6写程序了这边还php4的逛游呢。优秀的开源程序升级还是很负责任的,看好文档,别怕。

以上这六点准备完毕,现在我们有了运行环境,有了基本架构骨架,有了备份和切换方案,应该开始着手设计开发方面的事情了。开发方面的事情无数,下一篇会先说一些重点。
原文地址

七、数据库

几乎所有操作最后都要落到数据库身上,它又最难扩展(存储也挺难)。对于mysql,什么样的表用myisam,什么样的表用innodb,在开发 之前要确定。复制策略、分片策略,也要确定。表引擎方面,一般,更新不多、不需要事务的表可以用myisam,需要行锁定、事务支持的,用innodb。 myisam的锁表不一定是性能低下的根源,innodb也不一定全是行锁,具体细节要多看相关的文档,熟悉了引擎特性才能用的更好。现代WEB应用越来 越复杂了,我们设计表结构时常常设计很多冗余,虽然不符合传统范式,但为了速度考虑还是值得的,要求高的情况下甚至要杜绝联合查询。编程时得多注意数据一 致性。

复制策略方面,多主多从结构也最好一开始就设计好,代码直接按照多主多从来编写,用一些小技巧来避免复制延时问题,并且还要解决多数据库数据是否一致,可以自己写或者找现成的运维工具。

分片策略。总会有那么几个表数据量超大,这时分片必不可免。分片有很多策略,从简单的分区到根据热度自动调整,依照具体业务选择一个适合自己的。避免自增ID作为主键,不利于分片。

用存储过程是比较难扩展的,这种情形多发生于传统C/S,特别是OA系统转换过来的开发人员。低成本网站不是一两台小型机跑一个数据库处理所有业务的模式,是机海作战。方便水平扩展比那点预分析时间和网络传输流量要重要的多的多。

NoSQL。这只是一个概念。实际应用中,网站有着越来越多的密集写操作、上亿的简单关系数据读取、热备等,这都不是传统关系数据库所擅长的,于是 就产生了很多非关系型数据库,比如Redis/TC&TT/MongoDB/Memcachedb等,在测试中,这些几乎都达到了每秒至少一万次 的写操作,内存型的甚至5万以上。例如MongoDB,几句配置就可以组建一个复制+自动分片+failover的环境,文档化的存储也简化了传统设计库 结构再开发的模式。很多业务是可以用这类数据库来替代mysql的。

八、缓存。

数据库很脆弱,一定要有缓存在前面挡着,其实我们优化速度,几乎就是优化缓存,能用缓存的地方,就不要再跑到后端数据库那折腾。缓存有持久化缓存、 内存缓存,生成静态页面是最容易理解的持久化缓存了,还有很多比如varnish的分块缓存、前面提到的memcachedb等,内存缓 存,memcached首当其冲。缓存更新可用被动更新和主动更新。被动更新的好处是设计简单,缓存空了就自动去数据库取数据再把缓存填上,但容易引发雪 崩效应,一旦缓存大面积失效,数据库的压力直线上升很可能挂掉。主动缓存可避免这点但是可能引发程序取不到数据的问题。这两者之间如何配合,程序设计要多 动脑筋。

九、队列。

用户一个操作很可能引发一系列资源和功能的调动,这些调动如果同时发生,压力无法控制,用户体验也不好,可以把这样一些操作放入队列,由另几个模块 去异步执行,例如发送邮件,发送手机短信。开源队列服务器很多,性能要求不高用数据库当做队列也可以,只要保证程序读写队列的接口不变,底层队列服务可随 时更换就可以,类似Zend Framework里的Zend_Queue类,java.util.Queue接口等。

十、文件存储。

除了结构化数据,我们经常要存放其他的数据,像图片之类的。这类数据数量繁多、访问量大。典型的就是图片,从用户头像到用户上传的照片,还要生成不 同的缩略图尺寸。存储的分布几乎跟数据库扩展一样艰难。不使用专业存储的情况下,基本都是靠自己的NAS。这就涉及到结构。拿图片存储举例,图片是非常容 易产生热点的,有些图片上传后就不再有人看,有些可能每天被访问数十万次,而且大量小文件的异步备份也很耗费时间。

为了将来图片走cdn做准备,一开始最好就将图片的域名分开,且不用主域名。很多网站都将cookie设置到了.domain.ltd,如果图片也在这个域名下,很可能因为cookie而造成缓存失效,并且占多余流量,还可能因为浏览器并发线程限制造成访问缓慢。

如果用普通的文件系统存储图片,有一个简单的方法。计算文件的hash值,比如md5,以结果第一位作为第一级目录,这样第一级有16个目录。从0 到F,可以把这个字母作为域名,0.yourimg.com到f.yourimg.com(客户端dns压力会增大),还可以扩展到最多16个NAS集群 上。第二级可用年月例如,201011,第三级用日,第四级可选,根据上传量,比如am/pm,甚至小时。最终的目录结构可能会是 e/201008/25/am/e43ae391c839d82801920cf.jpg。rsync备份时可以用脚本只同步某年某日某时的文件,避免计 算大量文件带来的开销。当然最好是能用专门的分布式文件系统或更专业点的存储解决方案。

下面,我们要谈谈代码了。

这一系列的最后一篇写给普通编程人员,如果不感兴趣可直接看本文最后几段。开始设计代码结构之前,先回顾一下之前准备过的事情:我们有负载均衡的WEB服务器,有主从DB服务器并可能分片,有缓存,有可扩展的存储。在组织代码的各个方面,跟这些准备息息相关,我一二三的列出来分别说,并且每一条都以“前面讲到”这个经典句式开头,为了方便对照。

别着急看经典句式,我思维跳跃了,插一段。实际开发中,我们总会在性能和代码优雅性上作折中。对于当今的计算机和语言解释器,多几层少几层对象调 用、声明变量为Map还是HashMap这种问题是最后才需要考虑的问题,永远要考虑系统最慢的部分,从最慢的部分解决。例如看看你用的ORM是不是做了 很多你用不到的事情,是不是有重复的数据调用。我们做的是web应用开发,不是底层框架API,代码易读易懂是保证质量很重要的一方面,你的程序是为了什 么而设计,有不同的方法……算了,这个话题另起一篇文章来说,扯远了,想交流可关注我的微博 http://t.sina.com.cn/liuzhiyi,咱继续……

前面讲到,WEB 服务器是要做负载均衡的,图片服务器是要分开的。对于这点,代码在处理客户端状态时,不要把状态放到单机上,举例,不要用文件session,嗯,常识。 如果有可能,最好在一开始就做好用户单点认证的统一接口,包括跨域如何判断状态、静态页面如何判断状态,需要登录时的跳转和返回参数定义,底层给好接口, 应用层直接就用(可参考GAE的 user服务)。登录方面的设计要考虑移动设备的特性,比如电脑可以用浮动层窗口,但NOKIA自带的浏览器或UCWEB就无法处理这种表现形式,程序一 定既能处理AJAX请求又能直接通过URL来处理请求。图片服务器分开,资源文件最好也布局到图片服务器,也就是WEB服务器只服务动态程序。虽然开发测 试时稍微复杂(因为需要绝对URI才能访问),但将来页面前端优化上会轻松许多,并且你的WEB服务器IO优化也轻松许多。程序引用资源文件时,要有一个 统一的处理方法,在方法内部可以自动完成很多事情,例如将css/js根据组合,拼成一个文件,或者自动在生成的URI后面加上QUERYSTRING, 如果将来前端用了缓存服务,那生成QUERYSTRING是最简单的刷新服务端缓存和客户端缓存的办法。

前面讲到, 数据库会有复制,可能会多主多从,可能会分片。我们程序在处理数据的过程中,最好能抽象出来单独放做一层。拿现在流行的MVC模式来说,就是在M层下方再 放一个数据层,这个数据层不是通常所说的JDBC/PDO/ActiveRecord等,而是你自己的存取数据层,仅对外暴露方法,隐藏数据存取细节。这 个数据层内部不要怕写的难看,但一定要提供所有的数据存储功能,其他任何层次不要看到跟数据库打交道的字眼。之所以这样做,是因为在单关系数据库的情况 下,可能会SELECT…JOIN…或直接INSERT…INTO…,可你可能会将一些表放到key-value数据库里存储,或者分片,这么做之后原来 的语句和方式要全部改变,如果过于分散,则移植时会耗费很大精力,或得到一个很大的Model。在数据层面的设计上,尽量避免JOIN查询,我们可以多做 冗余,多做缓存,每种数据尽量只需要一次查询,然后在你的程序里面进行组合。对于比较复杂的数据组合,在实时性要求不高的情况下,可采用异步处理,用户访 问时只取处理后的结果。在对于主键的处理上,避免使用自增ID,可以用一定规则生成的唯一值当做主键,这种主键是最简单的分片分布策略。即使用自增ID, 也最好用一个自增ID发生器,否则从数据库不小心被写了一下,那主键很容易冲突。

前面讲到,咱数据库前面还有某些缓存挡着。别把mysql的query cache当缓存,应用稍复杂的时候QUERY CACHE反而会成为累赘。缓存跟数据库和业务结合的很紧密,正因为跟业务关系紧密,所以这点没有放之四海而皆准的方法。但我们还是有一些规则可参照。规 则一:越接近前端,缓存的颗粒度越大。例如在WEB最前端缓存整个页面,再往后一层缓存部分页面区域,再往后缓存区域内的单条记录。因为越靠近后端,我们 的可操作性越灵活,并且变化最多的前端代码也比较方便编写。在实践中,因为产品需求变化速度非常快,迭代周期越来越短,有时很难将Controller和 Model分的那么清楚,Controller层面处理部分缓存必不可免,但要保证如果出现这种情况,Controller所操作的缓存一定不要影响其他 数据需求方,也就是要保证这个缓存数据只有这一个Controller在用。规则二:没有缓存时程序不能出错。在不考虑缓存失效引发的雪崩效应时,你的程 序要有缓存跟没缓存一个样,不能像新浪微博一样,缓存一失效,粉丝微博全空,整个应用都乱套了。在缓存必不可少的情况下,给用户出错信息都比给一个让人误 解的信息强。规则三,缓存更新要保证原子性或称作线程安全,特别是采用被动缓存的方式时,很可能两个用户访问时导致同一个缓存被更新,通常情况这不是大问 题,可缓存失效后重建时很可能是引发连锁反应的原因之一。规则四:缓存也是有成本的。不只是技术成本,还有人工时间成本。如果一个功能使用缓存和不使用, 在可预见的访问量情况下区别微小,但使用缓存会使复杂度增加,那就不用,我们可以加个TODO标注,在下次迭代的时候加上缓存处理。

前面讲到,文件存储是独立的,那么所有的文件操作就都是远程调用。可以在文件服务器上提供一个很简单的RESTful接口,也可以提供xmlrpc 或json serveice,WEB服务器端所生成和处理的文件,全部通过接口通知文件服务器去处理,WEB服务器本身不要提供任何文件存储。你会发现很多大网站的 上传图片跟保存文章是分两步完成的,就是基于这个原因。

以上几条“前面讲到”,其实无数人都讲过,我也只是结合前几篇文章用自己的话重复了一遍,真正分析起来精髓很简单——除了良好的功能逻辑分层,我们 还要为数据库存储、缓存、队列、文件服务等程序外层资源调用单独设计接口,你可以把你的程序想象成是运行在 Amazon EC2 上并用他的所有web service服务,你的数据库就是它的SimpleDB,你的队列就是他的SQS,你的存储就是他的S3,唯一不同是amazon的接口是远程调用,你的是内部调用。

将支撑服务接口化,意味着将MySQL更换到PostgreSQL不需要更改业务处理程序,移植团队甚至不需要跟业务开发团队过多沟通;意味着业务开发团队是对接口编程而不是对数据库编程;意味着不会因为某个业务开发人员的失误而拖垮性能。

对程序扫盲不感兴趣的直接看这里——

产品设计完了,程序框架搭完了,可能有矛盾在这个节骨眼儿产生了。不断有产品设计抱怨说他的创意没实现到预期效果,有程序员抱怨说产品设计不切实 际。这种抱怨多缘于产品人员不懂技术,技术人员不理解产品。从广义上来讲,产品包含市场策略、营销手段、功能设计,产品和技术在争论时往往把焦点放在功能 上,而实际重点是,实现这个功能所消耗的成本跟能这个功能带来的利益能否换算,能否取其轻重。若可以,争议解决。若不能,则抛硬币看运气。因为一个功能的 加强而引发指标井喷,或因项目拖延而导致贻误战机的例子比比皆是。激进的决策者注重利益,保守的决策者注重损失,聪明的决策者会考虑这个问题是否真的那么 严重。

关系到未来的事情谁都说不准,要不怎么说创业一半靠运气呢。不过总有能说的准的事情,那就得靠数据说话。

没有100%也有99.9%的网站安装了访问统计代码,连我的 http://zhiyi.us 也不例外,新闻联播也总说科学决策科学发展的。有了统计,能确定的事情就很多了。例如,可以根据来源-目标转化率来分析哪类渠道的人均获取成本低,根据来 源-内容访问猜测用户跳出率原因,根据用户点击行为判断链接位置是否合理等。将数据以不同方式组合起来,找到内在联系,分析内因外因,制定对应策略,减少 拍脑门决策。靠数据支撑运营是个非常专业的事情,虽然不懂深奥的数学模型不会复杂的公式计算,渐渐学会因为A所以B,因为A和B所以C还是相对简单的。

全系列完毕。老话,大半夜连抽烟带码字的挺伤身,转载请注明出处

文章来源:

http://zhiyi.us/internet/thinking-twice-before-building-your-site-one.html
http://zhiyi.us/internet/thinking-twice-before-building-your-site-two.html
http://zhiyi.us/internet/thinking-twice-before-building-your-site-final.html

2010-08-05WEB前端

没有评论
1,027 Views

提高程序执行效率,Web开发技巧30条

目前的Web应用程序都趋于复杂化,从用户的角度而言,如何提高用户操作的响应速度,加快程序的执行效率,是Web开发人员应考虑的问题。

  目前的Web应用程序愈发的复杂化,包括拥有富客户端以及大量的JavaScript编码等等,从用户角度而言,让页面加载得更快、对用户的操作响应得更及时,能够给用户提供更为友好的体验,这就需要开发人员应提高应用程序的执行效率,以下是关于提高程序执行效率的小技巧。

  1.尽量避免使用DOM。当需要反复使用DOM时,先把对DOM的引用存到JavaScript本地变量里再使用。使用设置innerHTML的方法来替换 document.createElement/appendChild()方 法。

  2.eval()有问题,new Fuction()构造函数也是,尽量避免使用它们。

  3.拒绝使用with语句。 它会导致当你引用这个变量时去额外的搜索这样的一个命名空间,with里的代码在编译时期是完全未知的。

  4.使用 for()循环替代for…in循 环。因为for…in循环在开始循环之前需要Script引擎创建一个含有所有可循环属性的 List,需要多检查一次。

  5.把try-catch语句放在循环外面,不要放在循环里面,因为异常是很少发生的,放在外面避免每次都要执行它们。

  6.甚至圣经里都提到过这个 – 不要全局的。全局变量的生命周期贯穿整个脚本的生命周期,而本地变量的存在范围随着本地命名空间的销毁而消失。当在函数或其它地方引用一个全局变量时,脚 本引擎需要搜索整个全局命名空间。

  7.fullName += ‘John’; fullName += ‘Holdings’;执行速度快于fullName += ‘John’ + ‘Holdings’;

  8.如果你需要把多个字符串连接起来,最好是把他们做成一个数组,然后调用join()方法实现这个操作。这种方式在生成HTML片段时尤其有效。

  9.对于简单的任务,最好使用基本操作方式来实现,而不是使用函数调用实现。例如val1 < val2 ? val1 : val2;执行速度快于Math.min(val1, val2);,类似的,myArr.push(newEle);慢于myArr[myArr.length] = newEle;

   10.将函数的引用作为参数传递到setTimeout()和setInterval()里优于将函数名作为字符串参数传递(硬编码)。例如,setTimeout(”someFunc()”, 1000)执行效率慢于setTimeout(someFunc, 1000)

  11.当进行遍历操作时避免使用DOM操作。通过像getElementsByTagName()这 种方法得到的DOM元素队列都是动态的;有可能在你还没有对它遍历完成时,它已经被改变。这有可能导致死循环。

  12.当你对对象的成员 (属性或方法)进行反复操作时,先存储对它们的引用。例如var getTags = document.getElementsByTagName; getTags(’div’);

  13.在任何的代码段里,在局部变量范围外存放一个这个局部变量的引用。例如

  • function foo(arr) {  
  • var a = ’something’;  
  • //变量 ‘a’ 对于下面的一段就是范围外变量,这个变量的引用在很多情况下会有用处。  
  • for (var i = 0, j = a, loopLen = arr.length; i < loopLen; i++) {  
  • //do something  
  • }  
  •   14.for(var i=0; i < someArray.length; i++) {…}的执行效率慢于for (var i=0, loopLen=someArray.length; i< i++)>

      15.在HTTP头信息里加入缓存控制过期和最大存活时间标记。

    6.优化CSS。要使用方式,而不要使用@import方式。请参考这个优秀的文档 http://www.slideshare.net/stubbornella/object-oriented-css。

      17.使用CSS技术来优化图片资源。关于Web前段优化,欢迎访问:改善用户体验 Web前端优化策略总结

      18.用GZip方式压缩.js和.css文件。如果你使用的是Apache,在 .htaccess 里设置压缩方式,你的HTML, XML和JSON也同时会被压缩。

      AddOutputFilterByType DEFLATE text/html text/css text/plain text/xml application/x-javascript application/json

      19.使用JavaScript压缩工具。除了使用YUI和JSMin外。

      20.优化每个页面上的各种资源,把它们拆分到各个子域上,这么它们就能够并行下载。

      21.将CSS样式表放在页面的最顶端,这样能方便包括IE在内的浏览器进行解析。

      22.尽量将DOM结构保持的越简单越好。DOM的体积会影响相关的操作效率,像查找, 遍历,DOM改动都有影响。document.getElementsByTagName(’*’).length这 个值越小越好。

      23.注意你使用的选择器。例如,如果你想获取一个ul下的直接子元素,使用jQuery(”ul > li”)而不要使用jQuery(”ul li”)

      24.当切换元素的可见性时(display),请记住:element.css({display:none})的 速度快于element.hide() 和 element.addClass(’myHiddenClass’)。 除非在一个循环里,我选择element.addClass(’myHiddenClass’), 这样会使代码更简洁 – 不要使用inline CSS和JavaScript。

      25.当你使用完对DOM的引用变量后,要把它置为NULL。

      26.使用AJAX时,GET的执行效率高于POST。所以要尽量使用GET方式。只是要注意一点,IE只允许你用GET传送2K的数据。

      27.小心使用脚本动画。没有硬件的支持,动画会执行的很慢。尽量避免使用那些没有实际价值的动画效果。

      28.如果你的background-image对于这个图片的容器太小的话,请避免使 用background-repeat。如果你的背景图片需要来回填充很多次才能充满背景,那么将background-repeat属性设置成 background-image 和repeat-x 或 repeat-y来 达到填充背景的效果的做法是不明智的,这种填充方式的效率特别的低。你应该尝试使用一个足够大的图片来做background-image并 且使用background-repeat: no-repeat。

      29.布局时不要使用

    在浏览器完全把它画出来之前需要反复绘制好几次。因为DOM中

    是很少见的一种之后输出的会影响之前输出的显示效果的元素。对于表格数据来说,你可 以使用table-layout:fixed; 这是一种更有效的现实算法,根据CSS 2.1技术说明,这种写法可以让表格一行一行的输出。

      30.尽可能的使用原始JavaScript。限制JavaScript框架的使用。

    [转]WP新站之安装后必做的10件事

    3D街头涂鸦1

    首先说明一下,大家不要有以为,虽然这个标题很熟悉,但却是另外一篇新的文章,我翻译的那篇文章在这里:10件安装WordPress后需要做的事。这是一个系列的新手教程,希望能通过这个系列的新手教程,帮助那些刚刚接触使用WordPress的朋友。

    当你按照五分钟搭建属于你的WordPress的教程属于你自己的Blog后,肯定会觉得原来搭建一个属于自己的Blog是这么的容易的。当然,我们还需要对其进行些简单的配置,以使我们的WordPress(以下简称WP)博客更加完善。

    以下的10项配置,是我列出的对于一个WP新站必做的10件事。你可以依照顺序一件一件的去完成它,当然也似相当easy的。

    一、更改管理员密码并管理博客的写作者

    WP在安装后,会随机设置一个相当晦涩难记的密码,所以,你要做的第一件事就是把这个难记的密码修改成一个对你来说比较容易记忆的。

    你也可以在“用户”(User)面板中添加、删除、编辑博客作者的信息。

    注解:这点在2.8中有了改变,使用原始密码登陆后,会有提示要修改密码,WordPress越来越智能了。

    二、为日志增加永久链接(Permalinks)

    WP默认的日志链接(例如:www.leemunroe.com/?p=396)形式对于用户访问和搜索引擎索引都是相当的不友好的。

    当然你可以修改永久链接并在其中加入某些日志的关键词使链接更为友好。(例如:www.leemunroe.com/25-hot-female-web-designers)

    1.进入“设置”(Setting) –> “永久链接”(Permalinks);

    2.在“通用设置”(Common Setting)中选择“自定义结构”(Custom Structure);

    3.输入 %postname%/ ;

    4.为了使链接更加美观你也可以为它加上分类标签,输入 %category%/%postname%/ 即可。
    10-thing-wp-01-thumb

    三、上传并使用主题

    1.下载或设计一个你喜欢的主题;

    2.将主题解压释放至文件夹 “wp-content” –> “themes”中;

    3.在“外观”(Appearance) –> “主题”(Themes)中激活它。(单击即可激活)

    四、增加“分类”(Categories)并修改其默认值

    WP默认的分类标签是相当不×的,名曰:“未分类”(Uncategories)。当你发表一篇新的日志却忘记了增加分类标签时,你希望WP默认给你加上一个什么标签呢?如果是我,则倾向于使用News或类似的分类标签。

    1.进入“日志”(Post) –> “分类”(Categories);

    2.点击“未分类”并修改它;

    3.当然在此你还可以增加其他的博客分类标签。

    五、使用 Akismet

    Akismet是什么?如果你的Blog开放了评论系统,那么相信我,你将会收到很多烦人的垃圾评论。那么这时,Akismet就有用武之地了。

    我要告诉你的是,Akismet已经整合进了WP,所以你只需激活它即可使用。

    1.在管理员页面进入“插件”页面激活Akismet;

    2.为了完成Akismet你需要申请一个WP的API key。当然你可以很方便的在Wordpress.com上申请到并在Profile页面获取它。
    10-thing-wp-02-thumb

    六、安装Google XML Sitemaps

    如果你希望你的日志更容易更快的被主流搜索引擎索引,那么你就需要使用Google XML Sitemaps来为你的网站生成一个完成的XML-Sitemap。当然,它会随着你发布新日志而自动修改。

    猛击此处安装Google XML Sitemaps插件

    首先,你需要使用你的Google账户登入到Google Webmaster Central。在首页,会有一个验证你Blog站点的链接。依照Google的说明,一步一步的操作即可。

    验证完毕后,你就可以猛击Add Sitemap将你的Blog站点的URL加入其中。格式应该为:http://www.yoursite.com/sitemap.xml
    10-thing-wp-03-thumb1

    七、安装WordPress数据备份插件

    经常备份数据是一个好习惯。以免由于服务器的和自我的误操作的问题,而导致数据的丢失。

    你可以使用WordPress Database Backup插件来定时备份你的Blog数据。插件默认是每周将备份数据发送至你的邮箱。所以当你激活插件以后,不需要你其他的任何操作就可以使用了。

    猛击此处安装WordPress Database Backup插件,你还可以从Pro Blog Design上获取完整的自动备份教程。
    10-thing-wp-04-thumb1

    八、测试你的Blog

    只有发布了一定数量的各种格式的日志,你才能彻底的了解你的Blog的状态。

    你可以手动的一篇一篇的发表日志,也可以通过导入sample post collection from WP Candy来节省你测试的时间。

    通过导入这些简单的日志组合(工具>导入>WordPress),将使你的Blog拥有一些简单的日志并包含评论,“父/子”分类标签和格式等。这将使你修改Blog主题更加的容易,彻底。

    九、将Blog的RSS导入Feedburner

    Blog的RSS的日志输出数,是否全文输出等,都可以再“设置”(Setting) –> “阅读”(Reading)中修改。

    设置完成之后,你可以将你的Blog的RSS加入到Feedburner中。Feedburner将为你的RSS提供一个实时的服务状态,当你发布新日志时,它会及时的将更新上传至服务器。以供订阅者及时阅读。

    当你第一次使用Feedburner时,记得要在注册后,修改你所使用主题中的RSS订阅链接。将下列代码增加至主题文件首尾head标签之间即可。

    1.<LINK title="Feed Title" href="YOUR FEEDBURNER URL" type=application/rss+xml rel=alternate>

    10-thing-wp-05-thumb

    十、使用站点分析

    我建议使用Google Analytics来管理和统计站点的访问量。当然你也可以选择其他的站点分析服务网站比如MintStatCounter

    补充项

    1、设置合适的日志插图尺寸

    设置一个与Blog内容区域相协调的插图尺寸。

    “设置”(Setting) –> “媒体”(Media)

    2、设置Blog的副标题(tagline)

    你使用的主题或许不会显示副标题,但是在RSS输出中则会正常输出。

    “设置”(Setting) –> “常规”(General)

    原文连接:http://www.problogdesign.com/wordpress/10-things-to-do-after-installing-wordpress/

    [转]10件安装WordPress后需要做的事

    这又是一篇介绍安装WordPress之后需要做的事情,这是一个系列教程,Wopus系统能通过这个教程让各位菜鸟能学到东西,各位在看教程的过程中有任何疑问,欢迎留言。

    一、预防垃圾留言
    不知道从什么时候开始,博客成为了大家做广告绝好的地方,垃圾留言滚滚而来,而WordPress又是出了名的对搜索引擎很友好的程序,加上很多朋友不知道nofollow,所以,大家就开始和垃圾留言做斗争了。

    默认的反垃圾程序Akismet需要一个API KEY,这样可以共享一个反垃圾的数据库,但这个KEY需要在WordPress.com注册,当然,这个网站在有些时候是无法打开的,但这个插件确实需要一个KEY才有用,所以大家在安装WordPress之后,需要先注册这,获得一个API KEY,其实这个KEY是可以共享的,所以,找相熟的朋友分享一个就OK。

    目前位置,我见过的拦截垃圾留言最的博客是百万级的,一个博客,有这么多垃圾留言,不容易!

    二、更改博客的永久链接形式
    WordPress安装成功之后,默认的永久链接形式:http://xxx.com/?p=xxx,这种永久链接形式对搜索引擎并不友好。做好的链接形式很多人都认为是自定义的伪静态链接,而且现在绝大多数的博客都是在使用这种永久链接形式,所以也就推荐给大家,这里有伪静态链接形式的详细说明,点击查看

    这里需要说明一下,请确定,使用的空间是支持伪静态的,(mod_rewriter。)

    (既然说到了伪静态,这里就多说几句吧,希望能大家能有一点帮助。当伪静态链接很少被大家使用的时候,这种链接形式确实很受搜索引擎青睐,但当所有的都是伪静态的时候,搜索引擎就不喜欢了,就说到这里,其他的大家自己去想吧。)

    三、改进WordPress缓存
    随着WP的不断更新,不记得从哪个版本开始了,或者从WordPress被大家使用以来就开始了,都说WordPress的执行效率低,所以改善执行效率就是一个很大很大的事情,所以就有了缓存插件,这里不具体介绍缓存插件,但可以明确一点,缓存插件确实有用。

    四、创建博客地图
    方便搜索引擎的抓取,这个非常必要,通常,大家都使用这个插件:Google XML Sitemap

    五、给博客烧录Feed
    修改博客默认的feed地址,尽量托管到第三方。当前比较注明的有FeedburnerFriendfeed、国内的Feedsky

    六、增加统计代码
    国内的统计有很多,一般的博客用cnzz51啦就ok,还有量子恒道,当然还有就是大仙:Google统计,至于为啥要加统计代码,相信各位都清楚。

    七、提交博客到相关网站
    除了以上的苦练“内功“之外,也要积极的把博客推广出去,向各个搜索引擎提交是很必须的。

    八、创建 robots.txt
    关于这点,推荐Wopus以前的两篇文章:搜索引擎统一:Robots文件标准WordPress搜索引擎优化之robots.txt优化

    九、找一款好的主题
    看人,第一印象太重要了,博客也是,所以安装好博客之后,尽快找到一款好的WordPress主题,也是很关键的,当然,有爱好的朋友,可以自己设计。

    十、开始好好写内容吧
    再好的设置,再好的优化,再好的主题,再好的用户体验,都需要有好的内容来支持,所以,内容才是王道!
    当然,记得把自己好好通过about页面好好介绍一番,这个方便交流和沟通,也是很必须的。

    一个WordPress做好以上十点,足能做好一个好的博客。各位不要只看,更要动手做。另外,欢迎各位分享经验。

    返回顶部