追随自己的热情,做真实的自己,Follow your passion,stay true to yourself.

『置顶』大中型网站架构技术浅析

貌似有点儿标题党了 -_-# ..想写这一系列文章很久了,但一直提不起劲写。五一抽空写了下,just分享一下自己的一些心得,不会对部分技术深入探讨,大牛们勿喷。陆续更新中...

已更新:

  • 缓存机制与使用
  • web 安全
  • 实时通信

阅读全文…

『Mark』提问的智慧

我们只是毫无歉意地敌视那些提问前不愿思考、不做自己家庭作业的人。这种人就象时间无底洞──他们只知道索取,不愿意付出,他们浪费了时间,这些时间本可用于其它更有趣的问题或更值得回答的人。我们将这种人叫做 “失败者(loser)” (由于历史原因,我们有时将“loser”拼写为“lusers” 。)

我们意识到许多人只是想使用我们写的软件,他们对学习技术细节没有兴趣。对大多数人而言,计算机只是种工具,是种达到目的的手段而已。他们有自己的生活并且有更要紧的事要做,我们承认这点,也从不指望每个人都对这些让我们着迷的技术问题感兴趣。不过,我们回答问题的风格是为了适应那些真正对此有兴趣并愿意主动参与解决问题的人,这一点不会变,也不该变。如果连这都变了,我们就会在自己能做得最好的事情上不再那么犀利。

阅读全文…

『Mark』浅谈“用力不用脑“

有太多人,只知道羡慕别人的成就,却看不见别人的汗水,这已经被无数鸡汤文提到;那么也有不少人,汗水付出也很多,加班很辛苦,累的七死八活,但是依然没 有什么太好的成绩,我想说,这里除了部分人运气不佳,大部分是“用力不用心”(或者说“用力不用脑”),白白耽误自己的青春

阅读全文…

大中型网站技术架构浅析 - 实时通信

本文所讲述的『实时通信』主要围绕浏览器端和服务器端之间的实时通信。大中型网站技术架构浅析 系列之一。

实时通信主要分3大类:

轮询(Polling)

阅读全文…

做一件很苦但不后悔的事

啃词典

啃词典 , 一件绝对苦B但不后悔的事

3月底从逛出来,在家憋了一个多月,3点睡、11点多起来(这不就是印度时间般的作息),每天重复捣腾着 『产品设计』->『开发』->『测试』->『bug fixed』->『运维』->『数据处理(编辑)』,一人身兼n职,有时候还要考虑推广的事宜,处理备案等琐碎的事,过中还遇到各种不顺利。

有多累多苦B也许只有自己才知道,熬到今天我都佩服自己,虽则如此但我从不后悔做这么一个决定。

阅读全文…

大中型网站技术架构浅析 - 缓存机制与使用

对于一个大中型网站来说,缓存有多重要,肯定不言而喻啦。

阅读全文…

程序员需要掌握的web安全知识

关于最近网站安全状况,看下乌云上某大厂的漏洞列表就知道了.

触目惊心吧,这仅仅是被曝光的,未被曝光的就更不好说了...

作为一名程序员,掌握的一些基本web安全知识,是很有必要的,下面列举一些常见的安全漏洞和对应的防御措施。

阅读全文…

『Mark』程序员面试什么最重要?

非常同意这博主的观点,而自己一直以来都以 性格 > 经验 > 基础 > 算法 这准则去面试别人。没有最好的人才,只有最适合的人才!

程序员面试一直是社区乐于讨论的热门话题。我自己从06年实习以来,先后经历了4家软件公司,全部是外企,其中有世界500强的通信企业,有从事期权期货交易的欧洲中等规模的金融公司,也有为大型汽车制造商开发Android智能汽车的新兴公司。跨入IT行业以来,我在求职过程中经历过多次面试,最近两年也有过多次面试别人的经验。我感觉现在到了对这个问题发表自己看法的时候,这篇文章是我站在面试官角度对于程序员面试问题的一个阶段性反思和经验总结。

阅读全文…

『Mark』精益创业(Lean Startup)

看了Robbin写的精益创业,深有感受,其中大部分观点都总结得很棒,创业不容易,尽量少走点弯路。

创业是在极端不确定情况下开发新产品或者新服务。在创业早期,谁是客户,客户认为什么东西有价值都是未知的。

精益创业总结起来就是用3个动词驱动3个名词的循环迭代过程:IPD -> BML ,即:

idea -> (build) -> product -> (measure) -> data -> (learn) 

建立validated learning,然后推动下一轮迭代。精益之于创业,等同敏捷之于开发,都强调快速迭代,小步前进,测试(测量)驱动。每次精益产品循环的一个过程都是从未经证实的假设 -> 经证实的认知

精益迭代 (Build -> Measure -> Learn)

Lean Startup Lifecycle

(想法)-> 构建 ->(产品)-> 测量 ->(数据)-> 认知 

阅读全文…

『Mark』List of Known Scalable Architecture

For most Architects, "Scale" is the most illusive aspect of software architectures. Not surprisingly, it is also one of the most sort-out goals of todays software design. However, computer scientists do not yet know of a single architecture that can scale for all scenarios. Instead, we design scalable architectures case by case, composing known scalable patterns together and trusting our instincts. Simply put, building a scalable system has become more an art than a science.

We learn art by learning masterpieces, and scale should not be different! In this post I am listing several architectures that are known to be scalable. Often, architects can use those known scalable architectures as patterns to build new scalable architectures.

  1. LB (Load Balancers) + Shared nothing Units - This model includes a set of units that does not share anything with each other fronted with a load balancer that routes incoming messages to a unit based on some criteria (round-robin, based on load etc.). A unit can be a single node or a cluster of tightly coupled nodes. As the Load balancer, users can use DNS round robin, hardware load balancers, or software load balancers. It is also possible to build a hierarchy of load balancers that includes combination of above load balancers. The article, "The Case for Shared Nothing Architecture" by Michael Stonebraker, discusses these architectures

阅读全文…

使用daemontools监控Zookeeper服务

daemontools(http://cr.yp.to/daemontools.html)是一个管理UNIX下服务的工具集。supervise监视一个服务。它启动一个服务、当服务停掉时它会重起服务。

Zookeeper在运行过程中,如果出现一些无法处理的异常,会直接退出进程,也就是所谓的快速失败(fail fast)模式。daemontools 能够帮助你监控ZK进程,一旦进程退出后,能够自动重启进程,从而使down掉的机器能够重新加入到集群中去。

阅读全文…

Zookeeper使用上的注意事项

前段时间为Guang.com引入了Zookeeper,主要用于存储一些动态config/data,分布式锁,负载均衡,服务器监控等。现在,mark down一下zookeeper使用的注意事项和一些总结。

阅读全文…

【产品想法】向熟人借款的功能

借款页面

前天,一个朋友的同学问他借一笔数目不小的钱,这朋友稍微犹豫了一下还是将钱转过去了。由此萌生了向熟人借款这功能的想法。

WoW, 支付宝的新功能?No啦,这只是我YY出来的向熟人借款借款页面。

阅读全文…

关于Chrome第三方插件的安全隐患

Chrome打开的网易 最近网易、豆瓣都经常会出现一些奇奇怪怪的广告、视频,恶心死了,特别是视频,但想想以一个标榜有态度和一个标榜小清新的网站来说怎么可能投放这么2的广告,所以抽空就check一下。

阅读全文…

关于反爬虫和恶意攻击的一些策略和思路

前段时间Guang.com经常受到恶意spider攻击,疯狂抓取网站内容,一系列机器人spam发广告,对网站性能有较大影响。

下面我说说一些反恶意spider和spam的策略和思路。

1. 通过日志分析来识别恶意爬虫/攻击

阅读全文…

Cache Reload机制设计和实现(防止cache失效引发雪崩)

大概半年前,Guang.com曾发生一次由于首页部分cache失效,导致网站故障。

故障分析:

当时逛正在做推广,流量突然暴增,QPS达到5000+,当首页部分cache失效时,需要查询DB, 但由于这部分业务逻辑很复杂导致这SQL包含多表join、groupby、orderby等,执行需要1s,产生的大量临时表,in-memory都装不下,变成on-disk的临时表,但当时放临时表的disk分区容量只有20G,很快disk也爆了,结果显然网站打不开了。

总结为几点:

  • SQL语句优化不足
  • MYSQL tmp_table_size 配置太小
  • disk分区不合理/tmpdir路径配置不合理
  • 部门间沟通不足,大型推广前没事先打招呼。

临时解决措施:

由于当时持续大量用户访问,查询DB一直hang住,导致cache一直无法set回去,首页那cache一直处于miss状态,恶性循环,雪崩了。

当时我们立马采取以下措施:

  • 调整MYSQL tmp_table_size, 关于tmp_table_size 请看下面详细描述。
  • 修改MYSQL临时表保存路径(tmpdir)到较大分区
  • 简化业务逻辑,修改SQL,重新部署。

临时表使用内存(tmp_table_size):当我们进行一些特殊操作如需要使用临时表才能完成的join,Order By,Group By 等等,MySQL 可能需要使用到临时表。当我们的临时表较小(小于 tmp_table_size 参数所设置的大小)的时候,MySQL 会将临时表创建成内存临时表,只有当 tmp_table_size 所设置的大小无法装下整个临时表的时候,MySQL 才会将该表创建成 MyISAM 存储引擎的表存放在磁盘上。不过,当另一个系统参数 max_heap_table_size 的大小还小于 tmp_table_size 的时候,MySQL 将使用 max_heap_table_size 参数所设置大小作为最大的内存临时表大小,而忽略 tmp_table_size 所设置的值。而且 tmp_table_size 参数从 MySQL 5.1.2 才开始有,之前一直使用 max_heap_table_size.

长期解决措施:终于到本文的重点Cache Reload机制设计和实现

在讲Cache Reload机制设计和实现之前,先看看cache更新方式:

  1. 是缓存time out,让缓存失效,重查。(被动更新)
  2. 是由后端通知更新,一量后端发生变化,通知前端更新。(主动更新)

前者适合实时性不高,但更新频繁的;后者适合实时性要求高,更新不太频繁的应用。

Cache Reload mechanism 设计:

根据逛当时业务需求,选择被动更新方式,但这种方式的弊端是当cache失效那个点,刚好遇上高并发的话,就会发生上述的雪崩情况。

所以我在想这种使用率高的cache,就不用设置time out或time out设置足够大,然后按业务需求时间间隔定期reload/refresh cache data from DB,这cache就不会出现失效情况,也不出现雪崩现象。

下图是guang.com 关于Cache Reload的一小部分架构: 部分架构图

主要2个step:

  1. 将有需要reload cache 的wrapper保存到redis Hash.
  2. 部署在Daemon server上的CacheReloadJob,每分钟去redis拿需要reload的cache的hashmap,判断是否到时间refresh cache,如果到,通过Reflection call relevant method 重新reload data和reset 这个cache。

Cache Reload mechanism 实现:

set memcached with reload mechanism if necessary:

/**
 * <h2>set cache with reload mechanism </h2>
 * <h3>Example:</h3>
 * <p>
 * MethodInvocationWrapper wrapper = new MethodInvocationWrapper();<br>
 * wrapper.setMethodName("getProductList");<br>
 * wrapper.setObjectName("productService");<br>
 * wrapper.setArgs(new Object[] { null,0,1 });<br>
 * wrapper.setParameterTypes(new Class[] { Product.class,int.class,int.class});
 * </p>
 * 
 * <h3>NOTE:</h3>
 * Make sure the Args have been Serializable and the service has been marked the name, like "@Service("productService")"
 *
 * @param key
 * @param expiredTime 过期时间,如果reloadable=true, 此时间建议为 24*60*60 一天.
 * @param value
 * @param reloadable 是否reload
 * @param durationTime reload 时间间距,单位 ms
 * @param wrapper
 * @return
 * @author Kenny Qi
 */
public boolean set(String key, int expiredTime, Object value,boolean reloadable, long durationTime, MethodInvocationWrapper wrapper) {
    if(reloadable){
        wrapper.setWriteTime(System.currentTimeMillis());
        wrapper.setDuration(durationTime);
        wrapper.setKey(key);
        wrapper.setExpiredTime(expiredTime);
        objectHashOperations.put(RedisKeyEnum.CACHE_RELOAD.getKey(), key, wrapper);
    }

    if(value==null) return false;
    try {
        return memcachedClient.set(key, expiredTime, value);
    } catch (Exception e) {
        logger.warn(e.getMessage(), e);
        return false;
    } 
}

CacheReloadJob:

public class CacheReloadJob {

    private static Logger logger = LoggerFactory.getLogger(CacheReloadJob.class);
    @Autowired
    MyXMemcachedClient myXMemcachedClient;

    @Resource(name="objectHashOperations")
    private HashOperations<String, String, MethodInvocationWrapper> objectHashOperations;

    public void reloadCache(){
        logger.info("Try to reload cache");
        Map<String, MethodInvocationWrapper>  map = objectHashOperations.entries(RedisKeyEnum.CACHE_RELOAD.getKey());
        ThreadFactory tf = new NamedThreadFactory("CACHE_RELOAD_THREADPOOL");
        ExecutorService threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), tf);
        for (String key: map.keySet()) {
            final MethodInvocationWrapper wrapper = map.get(key);
            if(wrapper.getWriteTime()+wrapper.getDuration()>System.currentTimeMillis()){//刷新时间大于当前时间
                threadPool.execute(new Runnable() {
                    @Override
                    public void run() {
                        refreshCache(wrapper);
                    }
                });
            }
        }

        logger.info("completed with reloaded cache");
    }

    private void refreshCache(MethodInvocationWrapper wrapper){
        Object object = ReflectionUtils.invokeMethod(SpringContextHolder.getBean(wrapper.getObjectName()), wrapper.getMethodName(), wrapper.getParameterTypes(), wrapper.getArgs());
        myXMemcachedClient.set(wrapper.getKey(), wrapper.getExpiredTime(), object);
        wrapper.setWriteTime(System.currentTimeMillis());
        objectHashOperations.put(RedisKeyEnum.CACHE_RELOAD.getKey(), wrapper.getKey(), wrapper);
    }

}

Redis 存储结构(更多Redis 的应用场景,请看Redis 在电商中的实际应用场景 ):

redis> HSET cache:reload:memcached <memcache_key> <MethodInvocationWrapper>
OK
redis> HGETALL cache:reload:memcached

后记

如果要做的更人性化点,后续可以在网站后台管理系统 增加cache reloadable 的管理工具(删除、修改刷新间隔等)。

阅读全文…

Redis 在电商中的实际应用场景

话说使用Redis已经有好一段时间,趁有点时间,结合Guang.com 使用经验,总结一下Redis 在社会化电商网站的实际应用场景。文笔较差,各位看官,凑合着看下吧。

阅读全文…

『Mark』Trident - a high-level abstraction for realtime computation

Trident is a new high-level abstraction for doing realtime computing on top of Storm. It allows you to seamlessly intermix high throughput (millions of messages per second), stateful stream processing with low latency distributed querying. If you're familiar with high level batch processing tools like Pig or Cascading, the concepts of Trident will be very familiar – Trident has joins, aggregations, grouping, functions, and filters. In addition to these, Trident adds primitives for doing stateful, incremental processing on top of any database or persistence store. Trident has consistent, exactly-once semantics, so it is easy to reason about Trident topologies.

阅读全文…

『Mark』知名网站的技术发展历程

总共有两篇,分别发表在《程序员》杂志的5月刊和6月刊,暂时还只能公开第一篇,第一篇中介绍了一些Alexa排名较前的网站的技术发展历程,第二篇总结了这些网站是如何来应对可伸缩性、可用性、高性能以及低成本的挑战的。

互联网已经发展多年,其中不凡脱颖而出的一些网站,这些网站多数都已存在了接近10年或10年以上,在这么多年的发展过程中,除了业务上面临的挑战外,在技术上也面临了很多的挑战。在这篇文章中,我挑选了一些Alexa排名较前的网站(http://www.alexa.com/topsites),看看它们在技术是如何应对业务发展过程中的挑战的(由于一个网站需要很多方面的技术支撑,这里不可能全部覆盖,这里更多的是着重在其主要业务的网站的相关技术),所有的资料全部来源于网上,如有错误欢迎指正。

阅读全文…

『Mark』A Distributed Systems Reading List

Introduction

I often argue that the toughest thing about distributed systems is changing the way you think. The below is a collection of material I've found useful for motivating these changes.

Thought Provokers

Ramblings that make you think about the way you design. Not everything can be solved with big servers, databases and transactions.

阅读全文…