paulwong

#

聊聊架构

什么是系统架构?

从字面上理解,系统架构是系统的框架结构,是系统进行抽象之后的一个草图。它包含了系统中各个抽象组件的协作方式。


为什么需要架构?

好的架构能够降低系统的创造和维护成本,特别是维护成本。一个系统的创造成本低,而维护的成本大,特别是互联网应用,一般情况下把一个系统搞上线只需要一个月,但是有的系统搞下线缺需要几个月,而维护则需要数年。好的设计师不会在系统上线后对系统进行大的修改,从而减少系统的维护成本。

如果区分创造和维护两个阶段的话,架构师分为系统架构师和维护架构师,架构新的系统的是系统架构师,而维护老系统的则是维护架构师,程序员大多数愿意做新系统不愿意维护老系统,因为感觉没什么技术含量,但是维护老的系统反而更难,因为老系统的重构和改进更加复杂,维护架构师不仅需要读懂老系统架构设计,还要在不影响老系统功能的情况下,进行功能新增和重构。我的一位同事在对一个旧的系统进行重构之前,读了几个星期的代码,然后才开始设计改进方案。

架构设计的目标

设计的目标围绕着降低成本这个需求进行。设计的目标非常多,不同的系统架构目标也不一致,但是我觉得比较重要的架构目标有以下几个,可扩展性,灵活性和可插入性。

可扩展性,新的功能容易加入到系统里,降低创造成本。
灵活性,一处修改不会波及其他的地方,降低维护成本。
可插入性,同样的功能可方便的替换,降低创造和维护成本。
那么如何实现这三个目标

提高可扩展性:把不易变的抽象出来。抽象层要比实现层要更稳定,抽象层的变化要少。把变化的集中起来,比如把容易变化的功能放在单独一个系统或者一个模块里。
灵活性:模块化,每个模块相互独立,减少模块之间的藕合度,修改不会互相传递。
提高可插入性:模块化,服务化。
如何开始架构

当一块新业务放在你面前时,如何进行系统架构?我觉得需要进行以下几个步骤的思考:

业务分析:输出业务架构图,这个系统里有多少个业务模块,从前台用户到底层一共有多少层。
系统划分:根据业务架构图输出系统架构图,需要思考的是这块业务划分成多少个系统,可能一个系统能支持多个业务。基于什么原则将一个系统拆分成多个系统?又基于什么原则将两个系统合并成一个系统?
系统分层:系统是几层架构,基于什么原则将一个系统进行分层,分成多少层?
模块化:系统里有多少个模块,哪些需要模块化?基于什么原则将一类代码变成一个模块。

posted @ 2014-11-28 23:06 paulwong 阅读(333) | 评论 (0)编辑 收藏

单元测试、集成测试和系统测试的不同之处[转]



首先,他们的测试方法不同:

单元测试属于白盒测试;

集成测试属于灰盒测试的范畴;


系统测试属于黑盒测试。





其次,他们的考察范围不同,也就是他们测试的重点不同:

单元测试主要测试单元内部的数据结构、逻辑控制、异常处理等等;

集成测试主要测试模块之间的接口和接口数据传递的关系,以及模块组合后的整体功能;

系统测试主要测试整个系统相对于需求的符合度。




再次,他们的基准不同:

单元测试评估的主要是逻辑覆盖率;

集成测试评估的主要是接口覆盖率;

系统测试评估的是测试用例对需求规格的覆盖率。

posted @ 2014-11-21 09:09 paulwong 阅读(361) | 评论 (0)编辑 收藏

SPRING-SESSION

     摘要: HTTP SESSION的管理通常是由容器来做,但如果是在PAAS环境下,服务器不能做变更,则需要由WEB应用来做处理HTTP SESSION。同样,如果是分布式的环境下,SESSION的管理也会带来性能问题。SPRING推出了处理SESSION的框架:SPRING-SESSION。 SPRING会重写HTTP SESSION的那一套,使用SESSION也同样还是用 Code ...  阅读全文

posted @ 2014-11-19 18:23 paulwong 阅读(6373) | 评论 (1)编辑 收藏

知乎上关于BI商业智能的几点探讨

1、BI与数据仓库(DW)之间的关系是怎么样的?

回答这个问题有一个很恰当的比喻,房子和地基——数据仓库是BI的地基:数据仓库将数据抽取过来,清洗完,整合到主题域和多维模型里,然后BI就可以基于主题域和多维模型做各种分析了。如果这个地基(数据仓库)没做好,整个房子(BI项目)就很容易倒塌。


2、BI系统主要是为了帮助企业解决什么样的问题?如何解决?

1)以前发生了什么——可以用固定报表、各种图标、仪表盘、计分卡等实现;

2)为什么发生——可以用例外分析、即席查询、OLAP分析和数据挖掘实现;

3)现在发生了什么——可以用EII技术、预警和自动激发短信等工具来实现;

4)将来会发生什么——可以用预测分析、数据挖掘等来实现;

5)控制未来发展的方向,将活动控制到正确的道路上来——可以用过程分析、过程监控、统计过程控制(SPC)等实现。

从另一方面来看,可以这样看:

支持战略决策,通过数据反映宏观和公司的运营状况,帮助领导做出正确的战略决策,起到参谋的作用。

优化业务,通过数据与业务的结合,发现可优化的环节和总结出优化方法,提高运营效率和公司输出。

业务管控,业务模式成熟后,通过BI系统与其它系统对接,打通,形成循环,通过数据化管理,保证业务运营行在正确的轨道上。


3、大数据、云计算和商业智能这三者的关系到底如何,以后的发展前景有什么看法?

云计算:着重于存储(物理内存,存储)

大数据:着重于数据,在云计算的基础上将数据整合与存储

商业智能:在大数据的基础上,进行数据建模,数据挖掘,然后在Dashboard上展示出规律



4、BI中的多维数据模型和OLAP的实用价值在哪?

1)让分析人员可以快速地从不同的角度感知数据的情况。 在数据量大且维度指标众多的情况下,人的记忆力往往有限,只能记住某些方面,无法客观地了解全局多个角度,OLAP可以提供帮助

2)在决策时,可以方便让参与决策的人员(不一定是专业分析人员)汇聚讨论的焦点。 通过维度组合及条件过滤,很容易抽丝剥茧,验证各自的想法。 而对静态的固定报表,由于无法深入下去,所以讨论往往没有达到关键点就作罢

原文出自FineBI商业智能解决方案官网 www.finebi.com 

posted @ 2014-11-19 14:00 paulwong 阅读(415) | 评论 (0)编辑 收藏

分布式调度QUARTZ+SPRING

使用SPRING的定时任务框架,如果是在分布式的环境下,由于有多台节点,会产生相同的任务,会被多个节点执行,这时需引入分布式的QUARTZ。
触发器:存放时间排程
任务:蔟业务代码
排程器:负责调度,即在指定的时间执行对应的任务

如果是分布式QUARTZ,则各个节点会上报任务,存到数据库中,执行时会从数据库中取出触发器来执行,如果触发器的名称和执行时间相同,则只有一个节点去执行此任务。
如果此节点执行失败,则此任务则会被分派到另一节点执行。

quartz.properties
#============================================================================
#
 Configure JobStore  
#
 Using Spring datasource in quartzJobsConfig.xml
#
 Spring uses LocalDataSourceJobStore extension of JobStoreCMT
#
============================================================================
org.quartz.jobStore.useProperties=true
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 5000
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.txIsolationLevelReadCommitted = true
 
# Change this to match your DB vendor
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
 

#============================================================================
#
 Configure Main Scheduler Properties  
#
 Needed to manage cluster instances
#
============================================================================
org.quartz.scheduler.instanceId=AUTO
org.quartz.scheduler.instanceName=MY_CLUSTERED_JOB_SCHEDULER
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false


#============================================================================
#
 Configure ThreadPool  
#
============================================================================
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true


web-schedule-applicationcontext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mongo
="http://www.springframework.org/schema/data/mongo"
    xsi:schemaLocation
="http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context-3.0.xsd
          http://www.springframework.org/schema/data/mongo
          http://www.springframework.org/schema/data/mongo/spring-mongo-1.3.xsd
          http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
>


    <!-- 增加定时器配置 -->
    <!-- 线程执行器配置,用于任务注册 -->
    <bean id="executor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
         <property name="corePoolSize" value="10" />
         <property name="maxPoolSize" value="100" />
         <property name="queueCapacity" value="500" />
    </bean>

    <!-- 设置调度 -->
    <bean id="webScheduler"
        class
="org.springframework.scheduling.quartz.SchedulerFactoryBean">

        <property name="configLocation" value="classpath:/properties/config/quartz.properties" />
        <property name="dataSource" ref="dataSourceCMS" />
        <property name="transactionManager" ref="txManager" />

        <!-- This name is persisted as SCHED_NAME in db. for local testing could 
            change to unique name to avoid collision with dev server 
-->
        <property name="schedulerName" value="quartzScheduler" />

        <!-- Will update database cron triggers to what is in this jobs file on 
            each deploy. Replaces all previous trigger and job data that was in the database. 
            YMMV 
-->
        <property name="overwriteExistingJobs" value="true" />

        <property name="startupDelay" value="5"/>
        <property name="applicationContextSchedulerContextKey" value="applicationContext" />
        <property name="jobFactory">
            <bean class="com.tcl.project7.boss.common.scheduling.AutowiringSpringBeanJobFactory" />
        </property>
        
        <property name="triggers">
              <list>
                       <ref bean="springQuertzClusterTaskSchedulerTesterTigger" />
              </list>
         </property>
        <property name="jobDetails">
            <list>
                <ref bean="springQuertzClusterTaskSchedulerTesterJobDetail" />
            </list>
        </property>
         <property name="taskExecutor" ref="executor" />

    </bean>


    
    
    
    <!-- 触发器 -->
    <bean id="springQuertzClusterTaskSchedulerTesterTigger" class="common.scheduling.PersistableCronTriggerFactoryBean">
        <property name="jobDetail" ref="springQuertzClusterTaskSchedulerTesterJobDetail"/>
        <property name="cronExpression" value="* * * * * ?" />    
    </bean>
    
    <bean id="springQuertzClusterTaskSchedulerTesterJobDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
        <property name="jobClass" value="common.scheduling.SpringQuertzClusterTaskSchedulerTester" />
        
        <!-- fail-over 重写执行失败的任务,default=false -->
        <property name="requestsRecovery" value="false"/>
    </bean>
    
    
    
</beans>


JOB文件:SpringQuertzClusterTaskSchedulerTester.java
package common.scheduling;

import java.util.Date;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;

import com.tcl.project7.boss.common.util.UrlUtil;
import com.tcl.project7.boss.common.util.time.TimeUtils;
/**
 * <p>Title:SpringQuertzClusterTaskSchedulerTester</p>
 * <p>Description:
 * 应为要持久化等特性操作,需要继承 QuartzJobBean
 * <br>由于要被持久化,所以不能存放xxxxManager类似对象,
 * 只能从每次从QuartzJobBean注入的ApplicationContext 中去取出
 *
 * </p>    
 *
 *
 
*/
public class SpringQuertzClusterTaskSchedulerTester extends QuartzJobBean {
    
    private static Logger logger = LoggerFactory.getLogger(SpringQuertzClusterTaskSchedulerTester.class);
    
    @Autowired
    private UrlUtil urlUtil;
    
    
    protected void executeInternal(JobExecutionContext arg0)
            throws JobExecutionException {
        logger.info("------" + TimeUtils.formatTime(new Date()) + "------" + urlUtil.getNginxHost());
        System.out.println("------" + TimeUtils.formatTime(new Date()) + "------" + urlUtil.getNginxHost());
    }
    
}


如果JOB中有需要调用SPRING的BEAN,则需要此文件AutowiringSpringBeanJobFactory.java
package common.scheduling;

import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;

/**
 * Autowire Quartz Jobs with Spring context dependencies
 * 
@see http://stackoverflow.com/questions/6990767/inject-bean-reference-into-a-quartz-job-in-spring/15211030#15211030
 
*/
public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
    
    private transient AutowireCapableBeanFactory beanFactory;
 
    public void setApplicationContext(final ApplicationContext context) {
        beanFactory = context.getAutowireCapableBeanFactory();
    }
 
    @Override
    protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
        final Object job = super.createJobInstance(bundle);
        beanFactory.autowireBean(job);
        return job;
    }
}


由于JOB需要存储到数据库中,会产生PROPERTY的问题,需剔除JOB-DATA,需此文件PersistableCronTriggerFactoryBean.java
package common.scheduling;

import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailAwareTrigger;

/**
 * Needed to set Quartz useProperties=true when using Spring classes,
 * because Spring sets an object reference on JobDataMap that is not a String
 * 
 * 
@see http://site.trimplement.com/using-spring-and-quartz-with-jobstore-properties/
 * 
@see http://forum.springsource.org/showthread.php?130984-Quartz-error-IOException
 
*/
public class PersistableCronTriggerFactoryBean extends CronTriggerFactoryBean {
    @Override
    public void afterPropertiesSet() {
        super.afterPropertiesSet();
 
        //Remove the JobDetail element
        getJobDataMap().remove(JobDetailAwareTrigger.JOB_DETAIL_KEY);
    }
}


建表语句,MYSQL:quartzTables.sql
#
# Quartz seems to work best with the driver mm.mysql-2.0.7-bin.jar
#
In your Quartz properties file, you'll need to set 
# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#

DROP TABLE IF EXISTS QRTZ_JOB_LISTENERS;
DROP TABLE IF EXISTS QRTZ_TRIGGER_LISTENERS;
DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;


CREATE TABLE QRTZ_JOB_DETAILS
  (
    JOB_NAME  VARCHAR(200) NOT NULL,
    JOB_GROUP VARCHAR(200) NOT NULL,
    DESCRIPTION VARCHAR(250) NULL,
    JOB_CLASS_NAME   VARCHAR(250) NOT NULL,
    IS_DURABLE VARCHAR(1) NOT NULL,
    IS_VOLATILE VARCHAR(1) NOT NULL,
    IS_STATEFUL VARCHAR(1) NOT NULL,
    REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
    JOB_DATA BLOB NULL,
    PRIMARY KEY (JOB_NAME,JOB_GROUP)
);

CREATE TABLE QRTZ_JOB_LISTENERS
  (
    JOB_NAME  VARCHAR(200) NOT NULL,
    JOB_GROUP VARCHAR(200) NOT NULL,
    JOB_LISTENER VARCHAR(200) NOT NULL,
    PRIMARY KEY (JOB_NAME,JOB_GROUP,JOB_LISTENER),
    FOREIGN KEY (JOB_NAME,JOB_GROUP)
        REFERENCES QRTZ_JOB_DETAILS(JOB_NAME,JOB_GROUP)
);

CREATE TABLE QRTZ_TRIGGERS
  (
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    JOB_NAME  VARCHAR(200) NOT NULL,
    JOB_GROUP VARCHAR(200) NOT NULL,
    IS_VOLATILE VARCHAR(1) NOT NULL,
    DESCRIPTION VARCHAR(250) NULL,
    NEXT_FIRE_TIME BIGINT(13) NULL,
    PREV_FIRE_TIME BIGINT(13) NULL,
    PRIORITY INTEGER NULL,
    TRIGGER_STATE VARCHAR(16) NOT NULL,
    TRIGGER_TYPE VARCHAR(8) NOT NULL,
    START_TIME BIGINT(13) NOT NULL,
    END_TIME BIGINT(13) NULL,
    CALENDAR_NAME VARCHAR(200) NULL,
    MISFIRE_INSTR SMALLINT(2) NULL,
    JOB_DATA BLOB NULL,
    PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (JOB_NAME,JOB_GROUP)
        REFERENCES QRTZ_JOB_DETAILS(JOB_NAME,JOB_GROUP)
);

CREATE TABLE QRTZ_SIMPLE_TRIGGERS
  (
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    REPEAT_COUNT BIGINT(7) NOT NULL,
    REPEAT_INTERVAL BIGINT(12) NOT NULL,
    TIMES_TRIGGERED BIGINT(10) NOT NULL,
    PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP)
        REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_CRON_TRIGGERS
  (
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    CRON_EXPRESSION VARCHAR(200) NOT NULL,
    TIME_ZONE_ID VARCHAR(80),
    PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP)
        REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_BLOB_TRIGGERS
  (
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    BLOB_DATA BLOB NULL,
    PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP)
        REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_TRIGGER_LISTENERS
  (
    TRIGGER_NAME  VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    TRIGGER_LISTENER VARCHAR(200) NOT NULL,
    PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_LISTENER),
    FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP)
        REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP)
);


CREATE TABLE QRTZ_CALENDARS
  (
    CALENDAR_NAME  VARCHAR(200) NOT NULL,
    CALENDAR BLOB NOT NULL,
    PRIMARY KEY (CALENDAR_NAME)
);



CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
  (
    TRIGGER_GROUP  VARCHAR(200) NOT NULL, 
    PRIMARY KEY (TRIGGER_GROUP)
);

CREATE TABLE QRTZ_FIRED_TRIGGERS
  (
    ENTRY_ID VARCHAR(95) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    IS_VOLATILE VARCHAR(1) NOT NULL,
    INSTANCE_NAME VARCHAR(200) NOT NULL,
    FIRED_TIME BIGINT(13) NOT NULL,
    PRIORITY INTEGER NOT NULL,
    STATE VARCHAR(16) NOT NULL,
    JOB_NAME VARCHAR(200) NULL,
    JOB_GROUP VARCHAR(200) NULL,
    IS_STATEFUL VARCHAR(1) NULL,
    REQUESTS_RECOVERY VARCHAR(1) NULL,
    PRIMARY KEY (ENTRY_ID)
);

CREATE TABLE QRTZ_SCHEDULER_STATE
  (
    INSTANCE_NAME VARCHAR(200) NOT NULL,
    LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
    CHECKIN_INTERVAL BIGINT(13) NOT NULL,
    PRIMARY KEY (INSTANCE_NAME)
);

CREATE TABLE QRTZ_LOCKS
  (
    LOCK_NAME  VARCHAR(40) NOT NULL, 
    PRIMARY KEY (LOCK_NAME)
);


INSERT INTO QRTZ_LOCKS values(
'TRIGGER_ACCESS');
INSERT INTO QRTZ_LOCKS values(
'JOB_ACCESS');
INSERT INTO QRTZ_LOCKS values(
'CALENDAR_ACCESS');
INSERT INTO QRTZ_LOCKS values(
'STATE_ACCESS');
INSERT INTO QRTZ_LOCKS values(
'MISFIRE_ACCESS');


commit;


参考:
http://wenku.baidu.com/view/82e3bcbdfd0a79563c1e7223.html

Quartz集成springMVC 的方案二(持久化任务、集群和分布式)
http://blog.csdn.net/congcong68/article/details/39256307















posted @ 2014-11-14 18:46 paulwong 阅读(14909) | 评论 (0)编辑 收藏

为你下一个项目准备的 50 个 Bootstrap 插件

     摘要: Bootstrap是快速开发Web应用程序的前端工具包。它是一个CSS和HTML的集合,它使用了最新的浏览器技术,给你的Web开发提供了时尚的版式,表单,buttons,表格,网格系统等等。本文向你推荐 50 个 Bootstrap 的插件,可以考虑在你下一个项目中使用它们。1. Bootstrap Multiselect 2. Bootstrap Dialog 3. Boot...  阅读全文

posted @ 2014-11-12 14:34 paulwong 阅读(1605) | 评论 (0)编辑 收藏

Redis 集群解决方案 Codis

https://github.com/wandoulabs/codis

Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有明显的区别 (不支持的命令列表), 上层应用可以像使用单机的 Redis 一样使用, Codis 底层会处理请求的转发, 不停机的数据迁移等工作, 所有后边的一切事情, 对于前面的客户端来说是透明的, 可以简单的认为后边连接的是一个内存无限大的 Redis 服务.

Codis 由四部分组成:

  • Codis Proxy   (codis-proxy)

  • Codis Manager (codis-config)

  • Codis Redis   (codis-server)

  • ZooKeeper

codis-proxy 是客户端连接的 Redis 代理服务, codis-proxy 本身实现了 Redis 协议, 表现得和一个原生的 Redis 没什么区别 (就像 Twemproxy), 对于一个业务来说, 可以部署多个 codis-proxy, codis-proxy 本身是无状态的.

codis-config 是 Codis 的管理工具, 支持包括, 添加/删除 Redis 节点, 添加/删除 Proxy 节点, 发起数据迁移等操作. codis-config 本身还自带了一个 http server, 会启动一个 dashboard, 用户可以直接在浏览器上观察 Codis 集群的运行状态.

codis-server 是 Codis 项目维护的一个 Redis 分支, 基于 2.8.13 开发, 加入了 slot 的支持和原子的数据迁移指令. Codis 上层的 codis-proxy 和 codis-config 只能和这个版本的 Redis 交互才能正常运行.

Codis 依赖 ZooKeeper 来存放数据路由表和 codis-proxy 节点的元信息, codis-config 发起的命令都会通过 ZooKeeper 同步到各个存活的 codis-proxy.

Codis 支持按照 Namespace 区分不同的产品, 拥有不同的 product name 的产品, 各项配置都不会冲突.

目前 Codis 已经是稳定阶段,目前豌豆荚已经在使用该系统。

架构:

Snapshot1

特性:

  • 自动平衡

  • 使用非常简单

  • 图形化的面板和管理工具

  • 支持绝大多数 Redis 命令,完全兼容 twemproxy

  • 支持 Redis 原生客户端

  • 安全而且透明的数据移植,可根据需要轻松添加和删除节点

  • 提供命令行接口

  • RESTful APIs

安装:

  • Install go

  • go get github.com/wandoulabs/codis

  • cd codis

  • ./bootstrap.sh

  • make gotest

  • cd sample

  • follow instructions in usage.md

界面截图:

Dashboardmain

Migratemigrate

Slotsslots

posted @ 2014-11-09 09:28 paulwong 阅读(2522) | 评论 (0)编辑 收藏

樂視 TV 載入 4K 片點解咁快?CDN 網絡解構

經過幾次搶購,相信有些 unwire 讀者已經買到 Letv X50 Air 超級智能電視,在家享受它的豐富內容,以及準備欣賞 HKTV 直播劇集了吧。

而它提供的內容中,最吸引的肯定是 4K 影片及劇集。相信大家都知道,4K 內容檔案本身容量十分大,還要透過網絡進行串流,一般情況也會「窒下窒下」,但為何在 X50 Air 上會如此順暢?以下小編就為大家解構一下:

letvcdn

 

好了,謎底揭曉!

其實很多時候欣賞串流內容(streaming)時要等,是因為 cache 時間十分長,導致影響載入時候。

而 Letv 就採用了 CDN(Content Delivery / Distribution Network;內容傳遞網路)網路,它的總承載量比單一骨幹最大的頻寬還要大,而且有異地備援,萬一某個伺服器出現故障,系統就會自動調用其他鄰近地區的伺服器資源,所以可靠度極之接近 100%;

就算沒有故障時,樂視香港的 CDN 網絡亦可有效回避繁忙擠塞的網絡,並自動尋找距離用家最接近的快取伺服器接收內容,因此可以改善內容存取速度,大大縮短下載時間,自然可以用串流網絡,順暢欣賞極致 4K 影片內容啦。

posted @ 2014-11-07 17:03 paulwong 阅读(353) | 评论 (0)编辑 收藏

15 个用于布局和 UI 增强的 jQuery 插件

有非常非常多的 jQuery 插件,这些插件可以简化你的 Web 应用开发。今天我们向你推荐 15 个用于布局和 UI 增强的 jQuery 插件。

Superscrollorama

jQuery File Upload Demo

jQuery Knob

jQuery Complexify

rcarousel

turn.js

jQuery HiddenPosition

Fancy Input

pickadate.js

Cool Kitten

stellar.js

windows

Infinite Scrolling

Autobrowse jQuery Infinite scrolling plugin using Ajax

jScrollPane

posted @ 2014-11-07 08:48 paulwong 阅读(327) | 评论 (0)编辑 收藏

软件架构师应具备的十大特点

如果有人问你,作为一个软件架构师需要哪些特质的话,你会怎么回答?从技术层面上讲,架构师的技术要求是首位的。除此之外在做人处事方面,更有魅力的架构师则更受欢迎。 
最近有个同事问我,是什么成就了一个架构师。下文就是我的回答,适用于各个技术领域。其中我故意不考虑企业架构相关的问题。 

 

1、了解相关领域的技术知识 

在你想要成为架构师的相关技术领域,必须具备扎实的专业知识和过人的本领。 

2、超强的分析、设计能力 

不管怎样,具备很强的分析和设计能力都是必杀技。另外就是能够运用设计模式方式解决各种各样的问题。 

3、编码与验证性测试(POC) 

熟悉该组织整个技术栈,并能使用各层的技术熟练地编码。 
能快速实现验证性测试。 

4、架构设计的实力 

能为原始需求提供架构方案。 
考虑周全:工具和框架的采用、安全性、性能和扩展性、依赖关系、集成、效益。 
熟悉软件开发生命周期(SDLC):需求、分析、设计、测试、打包、部署。 

5、建模语言或工具 

能使用不同的建模语言或工具,向其他架构师、开发者、项目经理等人,阐述架构。 

6、架构框架 

能证明架构的可行性,包括其业务、应用、数据、基础设置方面。 
了解TOGAF和ZACHMAN框架就更好了。 

7、沟通能力 

能与开发人员、测试人员、商业分析师、上级经理沟通无阻,无论在口头上和书面上。 

8、布道 

能讲解该行业的市场、技术知识。 
能为全队提供培训课程。 

9、销售、甚至售前 

能参与售前工作(尤其对于软件服务业):制定技术方案、使用各种预算工具估计方案的规模和成本、与销售对象互动。 

10、演讲技巧 

优秀的演讲技巧,有助于以下活动:华丽的计划书和技术文档、PPT演讲、布道。

posted @ 2014-11-05 12:55 paulwong 阅读(329) | 评论 (0)编辑 收藏

仅列出标题
共112页: First 上一页 39 40 41 42 43 44 45 46 47 下一页 Last