Quantcast
Channel: IT社区推荐资讯 - ITIndex.net
Viewing all 15843 articles
Browse latest View live

NoSQL数据库的出现及选择哪种NoSQL数据库

$
0
0

    在没有NOSQL数据时,关系型数据库一直是数据持久化的唯一选择,比较典型的关系型数据库有SQL Server、Oracle,MySQL,DB2.做.NET开发的同学一般会选择SQL Server,做JAVA的可能会偏向Oracle,MySQL,Python则是PostgreSQL或MySQL等等。过去很长一段时间内,关系数据库的健壮性已经在多数应用程序中得到证实。我们可以使用这些传统数据库良好的控制并发操作、事务等等。然而如果传统的关系型数据库一直这么可靠,那么为什么还会出现NOSQL呢?NoSQL之所以生存并得到发展,是因为它做到了传统关系型数据库做不到的事!

 

关系型数据库中存在的问题

我们使用的高级编程语言如Java、.Net.python等语言他们都有一个共同的特性——面向对象。但是我们所使用数据库MySQL、PostgreSQL、Oracle以及SQL Server他们同样有一个共同的特性——关系型数据库。这里就牵扯到了“Impedance Mismatch”这个术语:存储结构是面向对象的,但是数据库却是关系的,所以在每次存储或者查询数据时,我们都需要做转换。

 

应用程序规模的变大

随着互联网的逐渐发展,越来越多的业务数据和访问能力让服务器承受着巨大的负担为了解决这个问题我们可以通过扩展:一种是纵向扩展,即购买更好的机器,更大的磁盘空间、更多的内存等等;另一种是横向扩展,即购买更多的机器组成集群,搭建分布式服务器,在巨大的规模下,纵向扩展发挥的作用并不是很大。首先单机器性能提升需要巨额的开销并且有着性能的上限,在Google和Facebook这种规模下,永远不可能使用一台机器支撑所有的负载。鉴于这种情况,我们需要新的数据库,因为关系数据库并不能很好的运行在集群上。

 

NoSQL 数据库特点

不再使用SQL语言

一般为开源项目

为集群运行而生

弱结构化——不会严格的限制数据结构类型

 

NoSQL数据库的类型

NoSQL可以大体上分为4个种类:键-值对数据库、列族/大表数据库、文档数据库以及 图形数据库。下面就一览这些类型的特性:

 

一、 键-值对数据库

键值数据库就像在传统语言中使用的哈希表。你可以通过key来添加、查询或者删除数据,鉴于使用主键访问,所以会获得不错的性能及扩展性虽然具备高度可扩展性,但却无法帮助开发人员顺畅处理复杂数据集。如果大家需要进行磁盘备份、分布式散列表并通过一致性对数据内容加以检查,那么上述方案既具备良好的规模化能力、又能提供出色的处理速度。然而如果我们需要通过某个键来获取另一个键、进而访问第三个键以查询相关值,那么问题就会变得不易处理了

代表产品:Couchbase、Riak、Redis、Memcached

案列:Youtube (Memcached)、Twitter (Redis)、StackOverFlow (Redis)、GitHub (Riak)

适用的场景

储存用户信息,比如会话、配置文件、参数、购物车等等。这些信息一般都和ID(键)挂钩,这种情景下键值数据库是个很好的选择。

不适用场景

1. 取代通过键查询,而是通过值来查询。Key-Value数据库中根本没有通过值查询的途径。

2. 需要储存数据之间的关系。在Key-Value数据库中不能通过两个或以上的键来关联数据。

3. 事务的支持。在Key-Value数据库中故障产生时不可以进行回滚。

 

二、列族/大表数据库

这是键-值数据库的一种更为先进的表现形式。从本质上讲,其中的键与值 存在一定程度的复合。我们可以将其视为一套贯穿多维数组的散列映射。基本每一个列都容纳着一行数据。举个例子,如果我们有一个Person类,我们通常会一起查询他们的姓名和年龄而不是薪资。这种情况下,姓名和年龄就会被放入一个列族中,而薪资则在另一个列族中。

 

代表产品:Cassandra、HBase

案列:Instagram (Cassandra),NASA (Cassandra),Yahoo!(HBase)

适用的场景

1. 日志信息。因为我们可以将数据储存在不同的列中,每个应用程序可以将信息写入自己的列族中。

2. 社交平台。我们储存每个信息到不同的列族中。

不适用场景

1. 需要ACID事务。

2. 数据之间的关系与数据本身的重要性不相上下

 

三、文档数据库

面向文档数据库会将数据以文档的形式储存。每个文档都是自包含的数据单元,是一系列数据项的集合。每个数据项都有一个名称与对应的值,值既可以是简单的数据类型,如字符串、数字和日期等;也可以是复杂的类型,如有序列表和关联对象。数据存储的最小单位是文档,同一个表中存储的文档属性可以是不同的,数据可以使用XML、JSON或者JSONB等多种形式存储。文档数据库属于自然而然的发展趋势。从集群化到数据访问,文档数据库与键-值数据库几乎完全一致;惟一的区别在于,文档数据库能够理解所存储数据中的文档内容。”换句话来说,文档数据库会可以将值作为JSON、而JSON文档中的元素则能够通过检索轻松进行查询与搜索。

代表产品:MongoDB、CouchDB、Couchbase

案列:SAP (MongoDB)

适用的场景

1. 文档信息存储。企业环境下,每个应用程序都有不同的日志信息。文档数据库数据库并没有固定的模式,所以我们可以使用它储存不同的信息。

2. 分析。鉴于它的弱模式结构,不改变模式下就可以储存不同的度量方法及添加新的度量。

不适用场景

在不同的文档上添加事务。文档数据库数据库并不支持文档间的事务

 

四、图形数据库

形数据库并不太关注数据规模或者可用性,而主要针对我们的数据之间存在怎样的相关性以及用户需要如何执行计算任务。正如Neo Technologies公司(主要产品为Neo4j数据库)产品工程高级主管Philip Rathle所说,图形数据库的威力主要体现在“数据集在本质上存在关联且非表格形式的情况下。其首要数据访问模式采用事务型机制,即OLTP/记录系统而非批量处理机制……请大家记住,图形数据库允许以事务性方式执行关联性操作,这一点在关系型数据库管理系统领域只能通过批量处理来完成。”

代表产品:Neo4J

案列:Adobe(Neo4J)

适用的场景

1. 在一些关系性强的数据中

2. 推荐引擎。如果我们将数据以图的形式表现,那么将会非常有益于推荐的制定

不适用场景

不适合的数据模型。图数据库的适用范围很小,因为很少有操作涉及到整个图。



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐




如何做一个程序员尊敬的产品经理

$
0
0

产品是孩子

一直以来,产品经理(PM)和程序员(DEV)好像都是冤家。自己以前也是做技术的,很能够理解DEV们的小心思,他们其实是很鄙视PM的(或许没有鄙视那么严重,至少是认为PM不那么厉害吧! 目测10%以上的DEV心里都有过这个念头:老子以后写代码写腻了也能去做PM)。DEV会觉得,PM的需求只需要3分钟拍脑袋想出来的,但是自己却需要花3天时间去实现,这是什么道理,更气人的是,未来的某一天,PM可能告诉自己某个地方得改,改回到原来需求描述的那样。DEV总是被PM整疯掉,万千**马在心中奔腾。

网上不是流传这样一个段子么:

程序员跟产品经理一起看电视。每个节目看到一半程序员就换台,看到一半就换台,几次之后产品经理终于忍无可忍的咆哮:老子刚看出点意思你就换刚看出点意思你就换,到底还让不让人看啦?!程序员淡定的盯着电视道:你半路改需求的时候我可没吱过声。

为什么会出现DEV鄙视PM的情况?我根据自己经历,猜想可能会有如下一些原因吧。大家也可以补充。

  • 有些计算机专业毕业生是因为自身技术水平差才选择了PM岗位。DEV一想,曾经某几个自己的同学,因为编码能力差找不到技术类工作才会做PM,类比一下,自己的PM同事应该也是菜鸟。
  • 一些有产品思维的DEV会怀疑PM的决策。产品思维并不是只有PM有的,正所谓“人人都是产品经理”,只要你留心观察生活都能够锻炼出些许产品思维,这些“先进”的DEV可能会觉得PM的决策不够明智。(话说回来,虽然人人都是产品经理,但是真正最专业的还是专业的产品经理。就像人人都会吐槽,但只有少数人才能将吐槽转化为需求并为它实现的整个生命过程负责。)

那么,如何做一个不被DEV鄙视的产品经理呢?这样做好像有点跪舔的嫌疑?其实不是的啦。在我看来,有以下经历或特质的PM会让DEV刮目相看,从前到后,吸引力依次递减。

  • 有过较为成功的创业经历。如果你曾经带领过一个团队创业并小有成就,那么足以证明你的商业眼光。
  • 拥有DEV只能仰望的人脉或市场操纵能力。程序员常年跟计算机打交道,所以对于与自己互补的人情练达的人群还是比较欣赏的。
  • 是部门所在产品的元老级人物。这只有拼时间拼资历了,一个伴随公司成长的35岁PM,一般都很让25岁的程序员尊重。
  • 具备不输于普通工程师的技术能力。千万不要让技术觉得你是因为技术太烂才退而求其次做了PM,至少得让他知道PM不是什么人都能做的。

猜猜我想向哪个方向发展。这是一个需要思考的人生命题。

想第一时间看到本站更新?请订阅RSS: 花痴痴的网站 | 女程序员园地

原创文章,转载请注明:转载自 花痴痴的网站 | 女程序员园地

本文链接地址:如何做一个程序员尊敬的产品经理

pacemaker+corosync+drbd实现postgresql高可用

$
0
0
之前做过postgresql+regmgr+pgbouncer的组合,实现三台(主、备、见证)服务器实现postgresql的高可用,这种方式主要使用regmgr配置流复制,利用postgresql的流复制进行主备同步,然后使用pgbouncer绑定第三个ip地址对外提供服务,当主库宕机后,regmgr的见证服务会通知备库执行相关failover的脚本,而脚本里除了提供触发提升备库为主库的命令外,还提供发送更改pgbouncer配置并重启pgbouncer的命令,进而pgbouncer后端的数据库链接指向新的主库,而对外提供服务的ip不变。这种防守的优点是配置较为简单,流复制的备库还能提供一些查询服务,但备库提升为主库后,原来的主库需要使用regmgr重新生成主库,还要开启regmgr监控进程,因此故障只能切换一次,然后进行人工干预(虽然此步骤也可以写成脚本实现自动切换,但我感觉最好还是手工提升,避免来回切换造成数据丢失)。这两天实验了下centos6.4 x-64下的pacemaker+corosync+drbd来实现postgresql的高可用。

1.环境配置
需要2台服务器,我的虚拟机配置如下:
[root@pgtest3 ~]# more /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
10.1.1.12 pgtest3
10.1.1.13 pgtest4
保证pgtest4的/etc/hosts配置也相同

配置互信:
[root@pgtest3 ~]# ssh-keygen -t rsa  #直接回车,免密码输入
[root@pgtest4 ~]# ssh-keygen -t rsa  #直接回车,免密码输入
[root@pgtest3 ~]# ssh-copy-id -i .ssh/id_rsa.pub root@pgtest4
[root@pgtest4 ~]# ssh-copy-id -i .ssh/id_rsa.pub root@pgtest3

配置时间同步:
可以使用ntp时间服务器同步,略

关闭linux 防火墙和selinux(两台都要)
[root@pgtest3 ~]# chkconfig iptables off
[root@pgtest3 ~]# service iptables stop
[root@pgtest3 ~]# setenforce 0
setenforce: SELinux is disabled
[root@pgtest3 ~]# getenforce 
Disabled
[root@pgtest3 ~]# vim /etc/selinux/config 
SELINUX=disabled

安装yum源:
[root@pgtest3 ~]# wget http://download.Fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
cp epel-release-6-8.noarch.rpm pgtest4:/root/
epel-release-6-8.noarch.rpm                                                                         100%   14KB  14.2KB/s   00:00   
[root@pgtest3 ~]# rpm -ivh epel-release-6-8.noarch.rpm
warning: epel-release-6-8.noarch.rpm: Header V3 RSA/SHA256 Signature, key ID 0608b895: NOKEY
Preparing...                ########################################### [100%]
   1:epel-release           ########################################### [100%]

[root@pgtest3 ~]# rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6
[root@pgtest3 ~]#  rpm -ivh http://elrepo.org/elrepo-release-6-5.el6.elrepo.noarch.rpm
Retrieving http://elrepo.org/elrepo-release-6-5.el6.elrepo.noarch.rpm
warning: /var/tmp/rpm-tmp.sxApyt: Header V4 DSA/SHA1 Signature, key ID baadae52: NOKEY
Preparing...                ########################################### [100%]
   1:elrepo-release         ########################################### [100%]

[root@pgtest3 ~]# yum list

另外本地光盘最好也插上,然后配置本地iso源:
[root@pgtest3 ~]# mount /dev/cdrom /media
[root@pgtest3 ~]# more /etc/yum.repos.d/CentOS-Base.repo 
[c6-media]
name=CentOS-$releasever - Media
baseurl=file:///media/
gpgcheck=0
enabled=1

这些都准备好了,就可以安装相关软件了

2.安装corosync(两台节点都需要)
corosync是类似于heatbeat的openais的集群消息组件,用于集群底层的消息传递,上层使用pacemaker进行集群资源管理。
yum install -y corosync

修改配置文件
[root@pgtest3 corosync]# vim /etc/corosync/corosync.conf
[root@pgtest3 corosync]# cat corosync.conf
# Please read the corosync.conf.5 manual page
compatibility: whitetank

totem {
     version: 2
     secauth: on
     threads: 0
     interface {
          ringnumber: 0
          bindnetaddr: 192.168.1.0  #心跳的网段,建议心跳用心跳线连接,并和局域网的ip隔离,我这里是虚拟     #机,就没有采用另外的私有网段隔离
          mcastaddr: 226.94.1.1  #组播地址,这个可以不陪着
          mcastport: 5405
          ttl: 1
     }
}

logging {
     fileline: off
     to_stderr: no
     to_logfile: yes
     to_syslog: yes
     logfile: /var/log/cluster/corosync.log  #日志的输出文件
     debug: off
     timestamp: on
     logger_subsys {
          subsys: AMF
          debug: off
     }
}

amf {
     mode: disabled
}

service { 
    ver: 0
    name: pacemaker  #上层集群管理服务,这里设置为pacemaker

aisexec {   
    user: root  #用户
    group: root #组
}

注意:红色的都需要进行配置

生成密钥文件:
[root@pgtest3 corosync]# cd /etc/corosync
[root@pgtest3 corosync]#  corosync-keygen 

然后把配置文件和密钥文件都传输到pgtest4上:
[root@pgtest3 corosync]#  scp authkey corosync.conf pgtest4:/etc/corosync/

3.Pacemaker 安装与配置(两个节点都需要配置)

[root@pgtest3 corosync]# yum install -y pacemaker
安装好pacemaker后,还需要安装crmsh,这是集群管理的命令行工具:
[root@pgtest3 ~]#  wget  http://download.openSUSE.org/repositories/network:/ha-clustering:/Stable/CentOS_CentOS-6/x86_64/crmsh-2.0+git46-1.1.x86_64.rpm
[root@pgtest3 ~]#  rpm -ivh crmsh-2.0+git46-1.1.x86_64.rpm
warning: crmsh-2.0+git46-1.1.x86_64.rpm: Header V3 RSA/SHA1 Signature, key ID 17280ddf: NOKEY
error: Failed dependencies:
     pssh is needed by crmsh-2.0+git46-1.1.x86_64
     redhat-rpm-config is needed by crmsh-2.0+git46-1.1.x86_64
安装依赖包(这两个包在本地光盘可以找到):
[root@pgtest3 ~]# yum install pssh redhat-rpm-config
[root@pgtest3 ~]# rpm -ivh crmsh-2.0+git46-1.1.x86_64.rpm
warning: crmsh-2.0+git46-1.1.x86_64.rpm: Header V3 RSA/SHA1 Signature, key ID 17280ddf: NOKEY
Preparing...                ########################################### [100%]
   1:crmsh                  ########################################### [100%]
成功安装后,crm命令可以进入命令行
启动coresync,由于我们已经配置了corosync.conf里配置了service,pacemaker会被包含进coresync里进行启动:
[root@pgtest3 ~]# service coresync start

4.安装drbd
[root@pgtest3 ~]# yum -y install drbd84 kmod-drbd84
配置drbd
[root@pgtest3 ~]# cat /etc/drbd.conf 
# You can find an example in  /usr/share/doc/drbd.../drbd.conf.example

include "drbd.d/global_common.conf";
include "drbd.d/*.res";

[root@pgtest3 ~]# ls /etc/drbd.d/
global_common.conf   r0.res

其中global_common.conf是全局配置,r0.res是定制的资源配置

[root@pgtest3 ~]# cat /etc/drbd.d/global_common.conf
global { 
usage-count no;  
# minor-count dialog-refresh disable-ip-verification 
common { 
handlers { 
pri-on-incon-degr "/usr/lib/drbd/notify-pri-on-incon-degr.sh; /usr/lib/drbd/notify-emergency-reboot.sh; echo b > /proc/sysrq-trigger ; reboot -f"; 
pri-lost-after-sb "/usr/lib/drbd/notify-pri-lost-after-sb.sh; /usr/lib/drbd/notify-emergency-reboot.sh; echo b > /proc/sysrq-trigger ; reboot -f"; 
local-io-error "/usr/lib/drbd/notify-io-error.sh; /usr/lib/drbd/notify-emergency-shutdown.sh; echo o > /proc/sysrq-trigger ; halt -f"; 
# fence-peer "/usr/lib/drbd/crm-fence-peer.sh"; 
# split-brain "/usr/lib/drbd/notify-split-brain.sh root"; 
# out-of-sync "/usr/lib/drbd/notify-out-of-sync.sh root"; 
# before-resync-target "/usr/lib/drbd/snapshot-resync-target-lvm.sh -p 15 -- -c 16k"; 
# after-resync-target /usr/lib/drbd/unsnapshot-resync-target-lvm.sh; 
startup { 
# wfc-timeout degr-wfc-timeout outdated-wfc-timeout wait-after-sb 
options { 
# cpu-mask on-no-data-accessible 
disk { 
# size max-bio-bvecs on-io-error fencing disk-barrier disk-flushes 
# disk-drain md-flushes resync-rate resync-after al-extents 
# c-plan-ahead c-delay-target c-fill-target c-max-rate 
# c-min-rate disk-timeout 
on-io-error detach; #同步错误的做法是分离 
net { 
# protocol timeout max-epoch-size max-buffers unplug-watermark 
# connect-int ping-int sndbuf-size rcvbuf-size ko-count 
# allow-two-primaries cram-hmac-alg shared-secret after-sb-0pri 
# after-sb-1pri after-sb-2pri always-asbp rr-conflict 
# ping-timeout data-integrity-alg tcp-cork on-congestion 
# congestion-fill congestion-extents csums-alg verify-alg 
# use-rle 
cram-hmac-alg "sha1"; #设置加密算法sha1 
shared-secret "mydrbdlab"; #设置加密key 
}

[root@pgtest3 ~]# cat /etc/drbd.d/r0.res 
resource r0{
        on pgtest3{
                device          /dev/drbd1;
                disk            /dev/sdb1;
                address         10.1.1.12:7788;
                meta-disk       internal;
        }
        on pgtest4{
                device          /dev/drbd1;
                disk            /dev/sdb1;
                address         10.1.1.13:7788;
                meta-disk       internal;
        }
}

创建drbd meta(两个节点执行):
[root@pgtest3 drbd.d]# drbdadm create-md r0
Writing meta data...
initializing activity log
NOT initializing bitmap
New drbd meta data block successfully created.

创建块设备(两个节点执行):
[root@pgtest3 drbd.d]# mknod /dev/drbd1 b 147 0

启动drbd服务(两个节点执行):
[root@pgtest3 drbd.d]#  service drbd start

数据同步(一个节点执行):
[root@pgtest3 drbd.d]#  drbdadm -- --overwrite-data-of-peer primary r0

格式化并挂载:
[root@pgtest3 drbd.d]# mkfs.ext4 /dev/drbd1
[root@pgtest3 ~]# mkdir /r0
[root@pgtest3 ~]# mount /dev/drbd1 /r0/

[root@pgtest3 ~]# /etc/init.d/drbd status
drbd driver loaded OK; device status:
version: 8.4.4 (api:1/proto:86-101)
GIT-hash: 74402fecf24da8e5438171ee8c19e28627e1c98a build by root@pgtest3, 2014-06-08 16:17:34
m:res  cs         ro                 ds                 p  mounted  fstype
1:r0   Connected  Primary/Secondary  UpToDate/UpToDate  C

如果要到备库上挂载:
[root@pgtest3 ~]# umount /r0/
[root@pgtest3 ~]# drbdadm secondary r0
[root@pgtest4 ~]# drbdadm primary r0
[root@pgtest4 ~]# mkdir /r0
[root@pgtest4 ~]# mount /dev/drbd1 /r0/

设置drbd自启动关闭(因为启动是需要用集群来管理的):
[root@pgtest3 init.d]# chkconfig drbd off
[root@pgtest4 init.d]# chkconfig drbd off

5.在两台机器上都安装pg,并把PG_DATA目录放到drbd的文件夹/r0下,然后设置开机自启动:
[pg@pgtest3 data]$ cp /opt/soft/postgresql-9.3.4/contrib/start-scripts/linux /etc/init.d/postgresql
设置pgdata等参数
[root@pgtest3 init.d]# chkconfig --add postgresql
[root@pgtest3 init.d]# chkconfig postgresql off
保证两个节点都能挂载/r0目录,并且能正常启动

配置crmsh 资源管理
两个节点都要关闭drbd
[root@pgtest3 ~]#  service drbd stop 
Stopping all DRBD resources: .

[root@pgtest3 ~]# chkconfig drbd off

6.进入crm进行配置:
增加drbd资源:
[root@pgtest3 ~]# crm
Cannot change active directory to /var/lib/pacemaker/cores/root: No such file or directory (2)
crm(live)# configure
crm(live)configure# property stonith-enabled=false  #设置stonith-enabled关闭,不使用外部设备控制
crm(live)configure# property no-quorum-policy=ignore #设置法定人数,由于只有两个节点,所以为ignore
crm(live)configure# verify #验证配置是否合法
Cannot change active directory to /var/lib/pacemaker/cores/root: No such file or directory (2)
Cannot change active directory to /var/lib/pacemaker/cores/root: No such file or directory (2)
Cannot change active directory to /var/lib/pacemaker/cores/root: No such file or directory (2)
#报这个错的话创建/var/lib/pacemaker/cores/root这个文件夹就可以了
crm(live)configure# commit #提交,写入cib配置中
crm(live)configure# primitive postgresql  ocf:heartbeat:drbd params drbd_resource=r0 op start timeout=240 op stop timeout=100 op monitor role=Master interval=20 timeout=30 op monitor role=Slave interval=30 timeout=30 #配置drbd资源,资源名定义为postgresql,也可以定义为别的
crm(live)configure#  ms ms_postgresql postgresql meta master-max=1 master-node-max=1 clone-max=2 clone-node-max=1 notify=true #配置主备库资源,ms_postgresql为名字,postgresql为drbd资源名
crm(live)configure# show #查看配置
node pgtest3
node pgtest4
primitive postgresql drbd \
     params drbd_resource=r0 \
     op start timeout=240 interval=0 \
     op stop timeout=100 interval=0 \
     op monitor role=Master interval=20 timeout=30 \
     op monitor role=Slave interval=30 timeout=30
ms ms_postgresql postgresql \
     meta master-max=1 master-node-max=1 clone-max=2 clone-node-max=1 notify=true
property cib-bootstrap-options: \
     dc-version=1.1.8-7.el6-394e906 \
     cluster-infrastructure="classic openais (with plugin)" \
     expected-quorum-votes=2 \
     stonith-enabled=false \
     no-quorum-policy=ignore

crm(live)configure# quit
There are changes pending. Do you want to commit them (y/n)? y #提示保存,或者commit再退出
bye

[root@pgtest3 ~]#  crm status
Cannot change active directory to /var/lib/pacemaker/cores/root: No such file or directory (2)
Last updated: Mon Jun  9 14:14:31 2014
Last change: Mon Jun  9 14:10:12 2014 via cibadmin on pgtest3
Stack: classic openais (with plugin)
Current DC: pgtest3 - partition with quorum
Version: 1.1.8-7.el6-394e906
2 Nodes configured, 2 expected votes
2 Resources configured.


Online: [ pgtest3 pgtest4 ]

Master/Slave Set: ms_postgresql [postgresql]
     postgresql:0     (ocf::heartbeat:drbd):     Slave pgtest3 (unmanaged) FAILED
     postgresql:1     (ocf::heartbeat:drbd):     Slave pgtest4 (unmanaged) FAILED

Failed actions:
    postgresql_stop_0 (node=pgtest3, call=18, rc=5, status=complete): not installed
    postgresql_stop_0 (node=pgtest4, call=18, rc=5, status=complete): not installed

这一步一直报错,找不到原因,两台机器重启下就好了。
    
增加文件系统资源:
[root@pgtest3 ~]# crm
Cannot change active directory to /var/lib/pacemaker/cores/root: No such file or directory (2)
crm(live)# configure
crm(live)configure# primitive pgstore ocf:heartbeat:Filesystem params device=/dev/drbd1 directory=/r0 fstype=ext4 op start timeout=60 op stop timeout=60 
crm(live)configure# verify
crm(live)configure# colocation pgstore_with_ms_postgresql inf: pgstore ms_postgresql:Master #colocation 是排列的意思,这一步是让资源 pgstore和资源ms_postgresql:Master放在一个节点上启动
crm(live)configure# order pgstore_after_ms_postgresql mandatory: ms_postgresql:promote pgstore:start
#这一步是排序,让ms_postgresql资源先promote提升备机,然后pgstroe资源启动,也就是drbd文件系统启动
crm(live)configure# verify
crm(live)configure# commit
crm(live)configure#  show
node pgtest3
node pgtest4
primitive mystore Filesystem \
     params device="/dev/drbd1" directory="/r0" fstype=ext4 \
     op start timeout=60 interval=0 \
     op stop timeout=60 interval=0
primitive postgresql drbd \
     params drbd_resource=r0 \
     op start timeout=240 interval=0 \
     op stop timeout=100 interval=0 \
     op monitor role=Master interval=20 timeout=30 \
     op monitor role=Slave interval=30 timeout=30
ms ms_postgresql postgresql \
     meta master-max=1 master-node-max=1 clone-max=2 clone-node-max=1 notify=true
colocation mystore_with_ms_postgresql inf: mystore ms_postgresql:Master
order mystore_after_ms_postgresql Mandatory: ms_postgresql:promote mystore:start
property cib-bootstrap-options: \
     dc-version=1.1.8-7.el6-394e906 \
     cluster-infrastructure="classic openais (with plugin)" \
     expected-quorum-votes=2 \
     stonith-enabled=false \
     no-quorum-policy=ignore

增加postgresql资源
crm(live)configure# primitive pgresource lsb:postgresql #增加postgresql的
crm(live)configure# colocation pg_with_pgstore inf: pgresource pgstore     
#这一步让postgresql服务和pgstore资源也就是drbd文件系统绑定在一台节点上启动

增加vip资源:
crm(live)configure# primitive vip ocf:heartbeat:IPaddr params ip=10.1.1.200 nic=eth1 cidr_netmask=255.255.255.0  #增加vip的ip地址为10.1.1.200,并在eth1网卡上启动
crm(live)configure# colocation vip_with_ms_pgdrbd inf: ms_postgresql:Master vip 
#这一步让vip资源和ms_postgresql的主节点资源绑定在一台节点启动
crm(live)configure# verify
crm(live)configure# commit
    


查看集群状态:
[root@pgtest4 ~]# crm status
Last updated: Mon Jun  9 21:43:58 2014
Last change: Mon Jun  9 20:29:54 2014 via cibadmin on pgtest4
Stack: classic openais (with plugin)
Current DC: pgtest4 - partition with quorum
Version: 1.1.8-7.el6-394e906
2 Nodes configured, 2 expected votes
5 Resources configured.


Online: [ pgtest3 pgtest4 ]

Master/Slave Set: ms_postgresql [postgresql]
     Masters: [ pgtest4 ]
     Slaves: [ pgtest3 ]
pgresource     (lsb:postgresql):     Started pgtest4
pgstore     (ocf::heartbeat:Filesystem):     Started pgtest4
vip     (ocf::heartbeat:IPaddr):     Started pgtest4

6.测试高可用性
先查看哪台是主库:
[root@pgtest3 ~]# ps -ef|grep post
pg        2876     1  0 08:42 ?        00:00:00 /opt/pgsql/bin/postmaster -D /r0/data
pg        2882  2876  0 08:42 ?        00:00:00 postgres: logger process             
pg        2884  2876  0 08:42 ?        00:00:00 postgres: checkpointer process       
pg        2885  2876  0 08:42 ?        00:00:05 postgres: writer process             
pg        2886  2876  0 08:42 ?        00:00:00 postgres: wal writer process         
pg        2887  2876  0 08:42 ?        00:00:00 postgres: autovacuum launcher process   
pg        2888  2876  0 08:42 ?        00:00:00 postgres: archiver process           
pg        2889  2876  0 08:42 ?        00:00:00 postgres: stats collector process    
root      5866  3302  0 13:23 pts/2    00:00:00 grep post
此时连接数据库正常:
[root@pgtest3 ~]# psql -h 10.1.1.200 -U pg postgres -p 5433
postgres=# SELECT count(*) from tbl_cost_align ;
 count 
-------
     5
(1 row)

[root@pgtest3 ~]# crm
crm(live)# node
crm(live)node# standby pgtest3 
此时命令行查询会阻塞一会,然后就可以再次正常查询了,再看集群状态已经漂移到pgest4上了:
[root@pgtest4 ~]# crm status
Last updated: Tue Jun 10 13:30:06 2014
Last change: Tue Jun 10 13:24:11 2014 via crm_attribute on pgtest3
Stack: classic openais (with plugin)
Current DC: pgtest3 - partition with quorum
Version: 1.1.8-7.el6-394e906
2 Nodes configured, 2 expected votes
5 Resources configured.


Node pgtest3: standby
Online: [ pgtest4 ]

 Master/Slave Set: ms_postgresql [postgresql]
     Masters: [ pgtest4 ]
     Stopped: [ postgresql:1 ]
 pgresource (lsb:postgresql): Started pgtest4
 pgstore (ocf::heartbeat:Filesystem): Started pgtest4
 vip (ocf::heartbeat:IPaddr): Started pgtest4

[root@pgtest4 ~]# ps -ef|grep post
pg       25610     1  0 13:24 ?        00:00:00 /opt/pgsql/bin/postmaster -D /r0/data
pg       25611 25610  0 13:24 ?        00:00:00 postgres: logger process             
pg       25614 25610  0 13:24 ?        00:00:00 postgres: checkpointer process       
pg       25615 25610  0 13:24 ?        00:00:00 postgres: writer process             
pg       25616 25610  0 13:24 ?        00:00:00 postgres: wal writer process         
pg       25617 25610  0 13:24 ?        00:00:00 postgres: autovacuum launcher process   
pg       25618 25610  0 13:24 ?        00:00:00 postgres: archiver process           
pg       25619 25610  0 13:24 ?        00:00:00 postgres: stats collector process    
root     25684 25622  0 13:24 pts/1    00:00:00 grep post

[root@pgtest4 ~]# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda1             7.7G  6.6G  771M  90% /
tmpfs                 499M   18M  481M   4% /dev/shm
/dev/sda3             7.6G  4.8G  2.5G  66% /postgres
/dev/drbd1            5.0G  575M  4.2G  12% /r0

[root@pgtest4 ~]# ifconfig 
eth0      Link encap:Ethernet  HWaddr 08:00:27:A5:50:BA  
          inet addr:10.0.2.15  Bcast:10.0.2.255  Mask:255.255.255.0
          inet6 addr: fe80::a00:27ff:fea5:50ba/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:4 errors:0 dropped:0 overruns:0 frame:0
          TX packets:18 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:791 (791.0 b)  TX bytes:1563 (1.5 KiB)

eth1      Link encap:Ethernet  HWaddr 08:00:27:34:CC:C4  
          inet addr:10.1.1.13  Bcast:10.1.1.255  Mask:255.255.255.0
          inet6 addr: fe80::a00:27ff:fe34:ccc4/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:147105 errors:0 dropped:0 overruns:0 frame:0
          TX packets:95266 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:21927610 (20.9 MiB)  TX bytes:13961871 (13.3 MiB)

eth1:0   Link encap:Ethernet  HWaddr 08:00:27:34:CC:C4  
          inet addr:10.1.1.200  Bcast:10.1.1.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

同样的,可以直接重启一台机器或者关闭网卡测试,服务都能很快进行切换。

总结:
使用pacemaker+drbd+corosync实现postgresql的高可用,配置稍复杂,另外只能一台机器提供服务,另外一台只能做容灾,机器稍显浪费,但比起rhcs实现更加简洁,但优点是如果主库出现故障,主备可以来回往复的切换,不需要人工干预,这点比repmgr+pgbouncer实现更好些,生产中用什么方式,我建议是用此方案再加一台流复制做备库,这样可以保证数据有更好的保护。

TOC之关键链项目管理遇到软件工程7原则

$
0
0

编著者:张克强    微博: 张克强-敏捷307


软件工程7原则简介

美国著名软件工程专家鲍伊姆(B.W.Boehm,也又另译为勃姆)在总结软件工程准则和信条的基础上,于1983年提出软件工程的7条基本原则,也是软件项目管理应该遵循原则。勃姆认为,这7条原则是确保软件产品质量和开发效率的最小集合,相互独立但结合得相当完备。

1. Manage using a phased life-cycle plan. 用分阶段的生命周期计划来管理
2. Perform continuous validation. 进行持续的确认
3. Maintain disciplined product control. 坚持有纪律的产品控制
4. Use modern programming practices. 利用现代编程实践
5. Maintain clear accountability for results. 维护对结果的清晰责任追究
6. Use better and fewer people. 使用少而精的人员
7. Maintain a commitment to improve the process. 保持提升过程的承诺


约束理论TOC的关键链项目管理

关键链项目管理(Critical Chain Project Management,CCPM)方法是Eliyahu Goldratt博士在其小说体专著《关键链》(Critical Chain)中提出的一种新的方法,其支持者们认为,这是一种全新的、革命性的思维方式,可以有效地缩短工期,提高项目满足进度与预算约束的能力;但是也有人认为,CCPM的独特性仅仅体现在这一术语上。---摘自百度百科

关键链被用来替代 关键路径分析方法。关键链区别于关键路径的主要特征如下:
使用资源依赖 缺乏寻求最佳方案的方法。这意味着一个“足够好”的解决方法已经足够了,因为: 就目前所知,没有任何分析方法能找到一个绝对的最佳的(比如,总体的最短关键链)。 估算上的固有的不确定性,远远大于最优和接近最优(即“足够好”的解决方案)之间的差异。 插入缓冲 项目缓冲(Project Buffer,缩写为PB) 输入缓冲(Feeding Buffer,缩写为FB) 资源缓冲(Resource Buffer,缩写为RB) 监测项目的进展和缓冲的使用率,而不是规划个别任务的进展速度。 ---摘自百度百科

讨论的缘起

@TOC中国 发了条微博 :1.项目的客户为什么需要设定里程碑? 2.客户希望用里程碑达到什么目的?
     张克强-敏捷307:好多项目管理类和软件工程的书都是这么说的。toc如何破?

     TOC中国:回复 @张克强-敏捷307:回复 @张克强-敏捷307:破什么?

     张克强-敏捷307:《关键链》对此有新做法,我以为你会提,你是要提否?

张克强-敏捷307:回复 @TOC中国:在软件开发领域,请查看鲍伊姆-软件工程七原则,发表于上世纪80年代初。

然后,我找到个介绍鲍伊姆-软件工程七原则的网络文章,做了推荐: 

@张克强-敏捷307 勃姆的软件工程7条基本原则-文章页-PChome手机版  http://t.cn/Rv6ah88  @TOC中国

开始争论

拯救与逍遥:不同层次的管理人员必须严格按照计划各尽其职地管理软件开发与维护工作,绝不能受顾客或上级人员的影响而擅自背离预定计划。【第一条就是自说自话了。】
            张克强-敏捷307:怎么自说自话了?scrum是符合此条的
拯救与逍遥:SCRUM说了“绝不能受顾客或上级人员的影响而擅自背离预定计划”?
        Glen-Wang:一切经PO
        张克强-敏捷307:sprint backlog的修改是需各方同意的,注意原文中的“擅自”
 
拯救与逍遥:一方面说 “不成功的软件项目中约有一半左右源自计划不周”,另一面有说“绝不能受顾客或上级人员的影响而擅自背离预定计划”。 这不是逻辑混乱吗?加上“擅自”不过是留个退路的修辞。如果了解过TOC的 CCPM 项目管理方式,就会知道基于严格里程碑计划的复杂项目,必将失败。(6月9日 17:23)
      张克强-敏捷307:回复 @拯救与逍遥:我认为其逻辑很正常。计划不好,项目容易会失败;未经各方同意修改计划,更容易失败。另,scrum的review meeting实质上是里程碑评审,忠实的满足了此条软工原则。 (6月9日 18:27)

张克强-敏捷307:回复 @拯救与逍遥:你要是用toc能证明软工原则是错的,或者已经过时,你就是新一代软工大师。如果你真有所得,建议写成论文,有道理的话,发表出来,想来轰动世界。以上我是认真的,绝非嘲讽。(6月9日 18:36)
     拯救与逍遥:回复 @张克强-敏捷307:我就问一个问题,每个里程碑都按时达成是整个plan按时达成的充分条件 还是 必要条件?至于ccpm项目管理方式已经被收入到pmbok中了,论文早已轮不到我这样的后生晚辈写了。 (6月9日 18:51)
              张克强-敏捷307:你这问题本身不恰当。pmbok是如何说ccpm的?有链接否?
             张克强-敏捷307:pmbok收ccpm可并不一定说明软工原则失效,项目管理与软件工程有重合,但不等同
             拯救与逍遥:我是在pmbok上看到过,不过说的很简略。具体哪里要问下pmp专家了  @京东PMO蔡德辉 。网上有更多详细的介绍,搜一下吧。有本toc的企管小说《关键链》讲这个,有兴趣还可以参加近期上海的ccpm的培训班。
            李凯-社会化营销:回复 @拯救与逍遥:这里其实存在两种不同的假设:里程碑思维里,大概拖延症,早完成隐瞒不报,多任务下带来的时间延长等问题是完全可以消除或控制的,进一步就是保护局部就等于保护全局。而TOC是承认这些不确定性的,因此其对应之策是保护影响全局的关键路径,对其他局部采取宽松政策。(6月9日 19:12)

分析

张克强-敏捷307:我认为关键链是考虑了资源瓶颈的关键路径,软件项目矩阵管理其实已经覆盖了关键链的要点,而且关键链下并不是完全取消里程碑,而是识别了更关键的里程碑。我精读过此书 [嘻嘻]// @拯救与逍遥:有本toc的企管小说《关键链》
拯救与逍遥:那克强认为ccpm相对于传统方式的特点在哪里呢? 
张克强-敏捷307:我已经说了啊,其效果在软件领域不会明显,在积累大量数据的建筑领域也不会明显,在其它领域我估计效果会不错
         赵智平_极普TOC:CCPM,1颠覆了关键路径CPM,2去除学生综合症及帕金森综合症对项目的影响,3设置缓冲因应不确定性并给出预警机制
拯救与逍遥:在软件领域不明显的理由是?
张克强-敏捷307:在软件开发领域,矩阵管理,敏捷团队,cmmi,各类模型等等已经覆盖并超越了关键链,建筑领域类似
         拯救与逍遥:这个逻辑好奇怪// @张克强-敏捷307:在软件开发领域
         张克强-敏捷307:回复 @拯救与逍遥:锦上添花 vs. 雪中送炭啊!
         李凯-社会化营销:因为对这些方法不懂,所以只能问最基本的问题:这些方法的追求目标是不是与CCPM并不完全一致,实际上还超越了它?
           张克强-敏捷307:窃以为大目标是一致的,这些覆盖并超越了ccpm// @李凯-社会化营销:因为对这些方法不懂
                 李凯-社会化营销:那么大目标是什么呢?超越的部分又是哪些?这是一个值得学习的突破口  
赵智平_极普TOC:软件开发的最大不确定性是什么?是完成任务的时间?软件需求?CCPM处理的最大不确定性是任务时间
张克强-敏捷307:敏捷迭代开发利用时间箱,别的行业很难模仿
赵智平_极普TOC:为何要迭代?因为可以锁定需求?需求被锁定,不确定性为任务的时间?// @张克强-敏捷307:敏捷迭代开发利用时间箱,别的行业很难模仿
张克强-敏捷307:反过来,锁定时间,拥抱变化// @赵智平_极普TOC:为何要迭代?
赵智平_极普TOC:以时间缓冲(余量)决定可接受的需求变化,或可引用缓冲侵蚀做决策;需求是最大的不确定性,小批量逐次确认// @张克强-敏捷307:反过来,锁定时间,拥抱变化  
            张克强-敏捷307:nod,好多toc术语,敏捷骚年一般不喜欢 [嘻嘻]
            深圳老曲:ccpm中对人性的解释(不良多工、帕金森定律、学生综合症、墨菲定律等)可以用于敏捷的导入,但ccpm本身缺乏对软件开发实践的支持。 // @张克强-敏捷307:nod,好多toc术语,敏捷骚年一般不喜欢 [嘻嘻]
            赵智平_极普TOC:CCPM可以支持的最大不确定性是任务时间及有限度地"拥抱"变化// @深圳老曲: ccpm中对人性的解释
                         深圳老曲:ccpm以及传统的项目管理,背后的假设都是项目的内容、工期、质量是能够同时兼顾的。在软件工程领域,这个假设是是不成立的,所以敏捷则是固定时间、保证质量,首先交付价值最高的功能。
                        赵智平_极普TOC:如果我懂SDBR及C#,需求已使用UML定义,可以使用CCPM管理开发进度吗?
                        深圳老曲:可惜的是,包括UML在内的几乎所有方法,都不能清晰、准确地把需求定义出来,特别是比较大或没有参考对象的项目。 



作者:zhangmike 发表于2014-6-11 6:19:31 原文链接
阅读:59 评论:0 查看评论

每天自动备份mysql脚本

$
0
0

定时执行脚本:
1、执行

crontab -e

00 00 * * * /bin/bash yourpath/mysqlbak.sh

2、打开自动执行文件

vi /etc/crontab

在etc中加入如下内容,让其自动执行任务。

00 00 * * * root /mysqlbak.sh

以上两个 00    00    *    *    *  为每天的凌晨自动执行脚本

分 时 日 月 周 命令

M: 分钟(0-59)。每分钟用*或者 */1表示
H:小时(0-23)。(0表示0点)
D:天(1-31)。
m: 月(1-12)。
d: 一星期内的天(0~6,0为星期天)。

每五分钟执行    */5 * * * *
每小时执行      0 * * * *
每天执行        0 0 * * *
每周执行        0 0 * * 0
每月执行        0 0 1 * *
每年执行        0 0 1 1 *
重启cron

/etc/rc.d/init.d/crond restart

or

service crond restart

详细请看crond的wiki
http://zh.wikipedia.org/wiki/Cron
mysqlback.sh
#!/bin/bash
#功能说明:本功能用于备份数据库
#编写日期:2010/12/06
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/local/mysql/bin
export PATH
#数据库用户名
dbuser=’root’
#数据库密码
dbpasswd=’123456′
#数据库名,可以定义多个数据库,中间以空格隔开,如:test test1 test2
dbname=’test1 test2′
#备份时间
backtime=`date +%Y%m%d%H%M%S`
#日志备份路径
logpath=’/second/backup’
#数据备份路径
datapath=’/second/backup’
#日志记录头部
echo ‘”备份时间为${backtime},备份数据库表 ${dbname} 开始” >> ${logpath}/mysqllog.log
#正式备份数据库
for table in $dbname; do
source=`mysqldump -u ${dbuser} -p${dbpasswd} ${table}> ${logpath}/${backtime}.sql` 2>> ${logpath}/mysqllog.log;
#备份成功以下操作
if [ "$?" == 0 ];then
cd $datapath
#为节约硬盘空间,将数据库压缩
tar jcf ${table}${backtime}.tar.bz2 ${backtime}.sql > /dev/null
#删除原始文件,只留压缩后文件
rm -f ${datapath}/${backtime}.sql
echo “数据库表 ${dbname} 备份成功!!” >> ${logpath}/mysqllog.log
else
#备份失败则进行以下操作
echo “数据库表 ${dbname} 备份失败!!” >> ${logpath}/mysqllog.log
fi
done

这里有一篇介绍
MySQL数据库备份的10个教程

http://www.linuxde.net/2012/03/9379.html

作者:u011986449 发表于2014-6-10 23:30:23 原文链接
阅读:90 评论:0 查看评论

一部新的电影上映,片源是如何分发到各电影院的?

$
0
0
先说一下电影片源都有什么媒介,通过不同的媒介,如何分发到电影院就很清楚了。
胶片拷贝:需要人把拷贝送到影院,重量有十几公斤一个,所以有一些朋友在很早之前会看到跑片的人员,当时成本高,两三个影院共用一个拷贝,这是最传统的电影院放映模式,胶片拷贝对应的就是胶片放映机。传统胶片拷贝就是把洗印出来的那种胶卷,把胶片放在传统胶片放映机上将每格画面快速连在一起形成画面,一个胶片拷贝根据影片长度一般都有4、5盘胶卷,放映胶片拷贝时,就需要旁边专门有一个人随时等候,在一盘胶片即将放完的时候在另外一台放映机上放上第二盘胶片等候放映,以此类推。胶片电影发展一百多年来,现在电影的拍摄,很多导演还是喜欢胶片的质感,(诺兰大神是胶片的死忠)

数字拷贝:进入电脑时代,数字拷贝已经成为趋势,通过移动硬盘把片源拷贝到对应的数字放映机里,一般发行公司会根据发行需要快递过硬盘到全国的影院,影院收到硬盘后会进行下载,然后将文件放在数字放映机上输入密钥进行放映。一般一部数字电影拷贝根据片长的时间,画质的选择,硬盘容量也不一样。

卫星传输: 通过卫星传输下载,片商通过卫星传输以一点对多点,且可以同时向遍布全国各地的影院传输,成本不会随着影院数量的增加而上涨,而且对影院的地域分布没有太大要求。目前卫星宽带可达30M/S,一部200G左右的影片,约1个多小时即可完成传输。此外,发行商可以根据需要任意选择传输影院的范围。(有可能是未来趋势)

网络光纤传输:光纤网络传输也是电影数字拷贝可选择的传输方式之一。现在一般用户的带宽名义上是10M-20M,如果要接入一条独享20M的光纤,一部200G影片的下载时间也需要数小时,而且月租金要6000元,还要算上下载设备的磨损费和电费。这个费用与快递和卫星相比,并不划算,且网络传输需要从中央平台到各影院终端,都达到一定的带宽水平。(除非全国网络光纤已经普及,目前这在国内显然无法普及实现)

优劣势

胶片拷贝发行费用最高,每一次的技术革新,发行成本就会降低,现在数字拷贝的播放连续性和成本是它的优势,中途不会有胶片电影换拷贝时跳帧的现象,而胶片拷贝如果放映场次过多,就会出现刮伤,噪点等现象,并且,胶片的成本比数字的要大很多。

卫星传播和光纤传输需要相应的硬件设备支持,主要看影院怎么选择,未来硬件设备铺设完毕,整体发行费用会降下来。



— 完 —
本文作者: Tim

【知乎日报】 你都看到这啦,快来点我嘛 Σ(▼□▼メ)

此问题还有 10 个回答,查看全部。
延伸阅读:
电影《白鹿原》为什么延期上映?
中国的独立电影,如果不能上映,如何收回成本?

MongoDB的日常维护管理

$
0
0

主要介绍了日常运行维护的管理工具

MongoDB的日常维护包括使用配置文件,设置访问控制,Shell交互,系统监控和管理,数据库日常备份和恢复

启动和停止MongoDB

启动后可以通过数据库的IP加端口号访问Web形式数据库。

配置文件

通过使用拂去配置文件的方式启动数据库实例,在bin文件夹下创建并编辑mongodb.config(名字可以随意)
事例加上 dbpath =/data/db/
启动时加上 --f 参数,并且指向配置文件即可。

使用Daemon方式启动

为什么我们使用Daemon方式?当我们关闭数据库服务的session端口的时候,MongoDB的服务也随之终止,这样是十分不安全的。通过守护进程的方式,启动即可。
添加 --fork 参数,这里必须指定存储日志的文件,即为启动 --logpath 参数。
事例如下

./mongod.exe --dbpath = D:\MongoDB  --logpath = D:\MongoDB\log\mongodb50.log   --fork
常见的mongod的参数说明
  • dbpath:数据文件存放路径
  • logpath: 存放的日志文件
  • bind_ip :对外的服务绑定IP,一般为空,面对所有的IP开放
  • port: fork 以后台Daemon的形式启动该服务,web管理端在其上加1000
  • journal: 开启日志功能,通过保存操作日志来降低单机故障的恢复时间,
  • config :当参数行十分多的时候,使用这个参数来设定参数文件的位置
关闭数据库
  • 直接使用Control+C来中断
  • 在connect连接状态下,可以切换到admin数据,后直接在库中发送db.shutdownServer()指令终止MongoDB实例。
  • Unix下发送Kill -2 PID 或者 Kill -15 PID来终止进程
 ps aux|grep mongod
    kill -2 (yourPID)
    ps aux|grep mongod

注意:不能使用kill -9 PID 杀死进程,这样可能导致MongoDB数据库损坏。

访问数据库

  • 绑定iP地址 ——bind_ip
    //MongoDB 可以限制只允许某一特定IP 来访问,只要在启动时加一个参数bind_ip 即可,如下:
    [root@mongodb01 /home/mongo/mongodb-2.0.2/bin]$ ./mongod --bind_ip 192.168.1.61
  • 设置监听端口 ——port
    //将服务端监听端口修改为27018:
    [root@mongodb01 /home/mongo/mongodb-2.0.2/bin]$ ./mongod --bind_ip 192.168.1.61 --port 27018
    //(报错代码)端户访问时不指定端口,会连接到默认端口27017,对于本例会报错,代码如下:
    [root@mongodb01 /home/mongo/mongodb-2.0.2/bin]$ ./mongo 192.168.1.50
    MongoDB shell version: 2.0.2
    connecting to: 192.168.1.61/test
    Sun Apr 14 21:45:26 Error: couldn't connect to server 192.168.1.50 shell/mongo.js:81 exception: connect failed
  • 使用用户名和密码登陆 ——启动时使用--auth参数
    //先启用系统的登录验证模块, 只需在启动时指定 auth 参数即可,代码如下:
    [root@mongodb01 /home/mongo/mongodb-2.0.2/bin]$ ./mongod --auth
启动认证

默认有个admin数据库,在admin.system.users中保存的用户比其他的数据库设置的用户权限更大。在未添加admin.system.users用户的权限的的情况下, 客户端无需任何认证就可以连接到数据库,并且可以对数据库进行任何操作,只有在admin.system.users添加了用户,启动--auth参数才会起作用。

1.建立系统root用户

>db.addUser("root","123456")>db.auth("root","123456")

2.建立只读权限用户

>db.addUser("user_reader","1234567",true)

添加只读权限的用户只需添加第三个参数,true。

使用命令行操作

MongoDB不仅可以交互,还可以执行指定的JavaScript文件,执行指定的命令片段,使用Linux Shell。

1.通过eval参数执行指定的语句
查询test库的t1集合的记录有多少:

db.t1.find()
{ "_id" : ObjectId("4f8ac746b2764d3c3e2cafbb"), "num" : 1 }
{ "_id" : ObjectId("4f8ac74cb2764d3c3e2cafbc"), "num" : 2 }
{ "_id" : ObjectId("4f8ac74eb2764d3c3e2cafbd"), "num" : 3 }
{ "_id" : ObjectId("4f8ac751b2764d3c3e2cafbe"), "num" : 4 }
{ "_id" : ObjectId("4f8ac755b2764d3c3e2cafbf"), "num" : 5 }
db.t1.count()
5

通过使用--eval参数直接执行ti的集合中的数

$./mongo.exe  --eval  "printjson(db.t1.count())"
MongoDB shell version: 2.0.2
connecting to: test
5

2.使用js文件执行文件内容

$cat t1_count.js
var count = db.t1.count();
printjson('count of t1 is: '+count);

显示为:

 $./mongo t1_count.js
MongoDB shell version: 2.0.2
connecting to: test"count of t1 is: 5"

Tips:通过--quiet参数屏蔽部分登陆信息,使结果更清晰

$ ./mongo --quiet t1_count.js"count of t1 is: 5"

进程管理

查看活动进程
> db.currentOp()>db.$cmd.sys.inprog.findOne()   //$cmd调用外部函数

显示如下:

> db.currentOp()
{"inprog" : [
                {"opid" : 630385,  "active" : true,"lockType" : "read","waitingForLock" : false,"secs_running" : 0,"op" : "query","ns" : "test","query" : {"count" : "t1","query" : {

                                },
                                "fields" : {

                                }
                        },
                        "client" : "127.0.0.1:51324","desc" : "conn","threadId" : "0x7f066087f710","connectionId" : 7,"numYields" : 0
                }
        ]
}>

代码解释:

  • opid:操作进程号
  • op: 操作类型(query ,update ,etc)
  • ns: 命名空间(namespace),操作对象
  • query :显示操作的具体内容
  • lockType: 锁的类型,指明是写锁还是读锁
结束进程
> db.killOp(630385)
{ "info" : "attempting to kill op" }

我们查看下:

> db.currentOp()
{ "inprog" : [ ] }>

监控系统的状态和性能

使用serverStatus命令可以获取到运行中的MongoDB服务器统计信息,下面我们来执行命令,查看MongoDB服务器的统计信息(不同平台或不同版本的键会有所不同),代码如下:

> db.runCommand({"serverStatus":1})
{"host" : "lindenpatservermongodb01","version" : "2.0.2","process" : "mongod","uptime" : 6003,"uptimeEstimate" : 5926,"localTime" : ISODate("2012-04-15T11:02:21.795Z"),"globalLock" : {"totalTime" : 6002811172,"lockTime" : 24867,"ratio" : 0.000004142559092311891,"currentQueue" : {"total" : 0,"readers" : 0,"writers" : 0
                },"activeClients" : {"total" : 0,"readers" : 0,"writers" : 0
                }
        },"mem" : {"bits" : 64,"resident" : 52,"virtual" : 1175,"supported" : true,"mapped" : 160,"mappedWithJournal" : 320
        },"connections" : {"current" : 1,"available" : 818
        },"extra_info" : {"note" : "fields vary by platform","heap_usage_bytes" : 341808,"page_faults" : 14
        },"indexCounters" : {"btree" : {"accesses" : 1,"hits" : 1,"misses" : 0,"resets" : 0,"missRatio" : 0
                }
        },"backgroundFlushing" : {"flushes" : 100,"total_ms" : 13,"average_ms" : 0.13,"last_ms" : 1,"last_finished" : ISODate("2012-04-15T11:02:19.010Z")
        },"cursors" : {"totalOpen" : 0,"clientCursors_size" : 0,"timedOut" : 0
        },"network" : {"bytesIn" : 1729666458,"bytesOut" : 1349989344,"numRequests" : 21093517
        },"opcounters" : {"insert" : 5,"query" : 8,"update" : 0,"delete" : 0,"getmore" : 0,"command" : 21093463
        },"asserts" : {"regular" : 0,"warning" : 0,"msg" : 0,"user" : 0,"rollovers" : 0
        },"writeBacksQueued" : false,"dur" : {"commits" : 30,"journaledMB" : 0,"writeToDataFilesMB" : 0,"compression" : 0,"commitsInWriteLock" : 0,"earlyCommits" : 0,"timeMs" : {"dt" : 3073,"prepLogBuffer" : 0,"writeToJournal" : 0,"writeToDataFiles" : 0,"remapPrivateView" : 0
                }
        },"ok" : 1
}>
数据导出与导入  mongoexportmongoinport

使用mongoexport导出数据
先看数据:

> db.t1.find()
{ "_id" : ObjectId("4f8ac746b2764d3c3e2cafbb"), "num" : 1 }
{ "_id" : ObjectId("4f8ac74cb2764d3c3e2cafbc"), "num" : 2 }
{ "_id" : ObjectId("4f8ac74eb2764d3c3e2cafbd"), "num" : 3 }
{ "_id" : ObjectId("4f8ac751b2764d3c3e2cafbe"), "num" : 4 }
{ "_id" : ObjectId("4f8ac755b2764d3c3e2cafbf"), "num" : 5 }>
使用代码:
./mongoexport.exe -d test -c t1 -o t1.dat
connected to: 127.0.0.1
exported 5 records
[root@mongodb01 /home/mongo/mongodb-2.0.2/bin]$ ls
bsondump  mongodump    mongoimport   mongosniff  t1_count.js
mongo     mongoexport  mongorestore  mongostat   t1.dat
mongod    mongofiles   mongos        mongotop    testfiles.txt
[root@mongodb01 /home/mongo/mongodb-2.0.2/bin]$ cat t1.dat
{ "_id" : ObjectId("4f8ac746b2764d3c3e2cafbb"), "num" : 1 }
{ "_id" : ObjectId("4f8ac74cb2764d3c3e2cafbc"), "num" : 2 }
{ "_id" : ObjectId("4f8ac74eb2764d3c3e2cafbd"), "num" : 3 }
{ "_id" : ObjectId("4f8ac751b2764d3c3e2cafbe"), "num" : 4 }
{ "_id" : ObjectId("4f8ac755b2764d3c3e2cafbf"), "num" : 5 }

./mongoexport.exe -d test -c t1 -o t1.dat 使用参数说明

  • -d: 指明使用的数据库
  • -c: 指明导出的集合,这里是t1
  • -o: 导出的数据名,这里的数据名默认使用相对路径,也可以使用绝对路径。

导出的数据格式的是JSON方式,也可导出csv格式;
导出为CSV格式代码文件如下:

./mongoexport -d test -c t1 -csv -f num -o t1.dat
  • -csv:指明了要导出的是CSV格式
  • -f: 指明需要导出的是哪些例子

数据导入 mongoimport
现将ti删除:

> db.t1.drop()
true> show collections
system.indexes
system.users>

再导入数据,这里导入的是csv数据:

./mongoimport -d test -c t1 --type csv --headerline -file /home/t1.dat
connected to: 127.0.0.1

看看导入的数据是不是一样:

> db.t1.find()
{ "_id" : ObjectId("4f8ac746b2764d3c3e2cafbb"), "num" : 1 }
{ "_id" : ObjectId("4f8ac74cb2764d3c3e2cafbc"), "num" : 2 }
{ "_id" : ObjectId("4f8ac74eb2764d3c3e2cafbd"), "num" : 3 }
{ "_id" : ObjectId("4f8ac751b2764d3c3e2cafbe"), "num" : 4 }
{ "_id" : ObjectId("4f8ac755b2764d3c3e2cafbf"), "num" : 5 }>
  • --type csv 导入的数据格式为CSV,为什么导入CSV格式:CSV对各大主流的数据库支持更良好,而JSON作为轻量级的数据格式,还有些弊端。
  • --file 指明导入的文件路径

数据备份和恢复

使用 数据备份 mongodump
./mongodump -d test -o /home/dump
  • -o:表示输出的备份路径,如果没有使用这个选项的话,MongoDB会自动创建dump文件夹并将备份文件放于其内。
使用数据恢复 mongorestore

mongorestore获取mongodump的输出结果,并将备份的数据插入到运行的MongoDB中。

./mongorestore -d test dump/*
connected to: 127.0.0.1
Thu Apr 19 18:16:12 dump/test/system.users.bson
Thu Apr 19 18:16:12      going into namespace [test.system.users]
2 objects found
Thu Apr 19 18:16:12 dump/test/t1.bson
Thu Apr 19 18:16:12      going into namespace [test.t1]
5 objects found
Thu Apr 19 18:16:12 dump/test/system.indexes.bson
Thu Apr 19 18:16:12      going into namespace [test.system.indexes]
Thu Apr 19 18:16:12 { key: { _id: 1 }, ns: "test.system.users", name: "_id_" }
Thu Apr 19 18:16:13 { key: { _id: 1 }, ns: "test.t1", name: "_id_" }
2 objects found
作者:u011027104 发表于2014-6-10 22:54:43 原文链接
阅读:128 评论:0 查看评论

mysql master/slave 数据库备份

$
0
0

出自:http://blog.csdn.net/mer1234567/article/details/7405775

 

1 复制概述

      Mysql内建的复制功能是构建大型,高性能应用程序的基础。将Mysql的数据分布到多个系统上去,这种分布的机制,是通过将Mysql的某一台主机的数据复制到其它主机(slaves)上,并重新执行一遍来实现的。复制过程中一个服务器充当主服务器,而一个或多个其它服务器充当从服务器。主服务器将更新写入二进制日志文件,并维护文件的一个索引以跟踪日志循环。这些日志可以记录发送到从服务器的更新。当一个从服务器连接主服务器时,它通知主服务器从服务器在日志中读取的最后一次成功更新的位置。从服务器接收从那时起发生的任何更新,然后封锁并等待主服务器通知新的更新。

请注意当你进行复制时,所有对复制中的表的更新必须在主服务器上进行。否则,你必须要小心,以避免用户对主服务器上的表进行的更新与对从服务器上的表所进行的更新之间的冲突。

1.1 mysql支持的复制类型:

  (1):基于语句的复制:  在主服务器上执行的SQL语句,在从服务器上执行同样的语句。MySQL默认采用基于语句的复制,效率比较高。  
            一旦发现没法精确复制时,   会自动选着基于行的复制。    
  (2):基于行的复制:把改变的内容复制过去,而不是把命令在从服务器上执行一遍. 从mysql5.0开始支持
  (3):混合类型的复制: 默认采用基于语句的复制,一旦发现基于语句的无法精确的复制时,就会采用基于行的复制。

 1.2 . 复制解决的问题

         MySQL复制技术有以下一些特点:
         (1)    数据分布 (Data distribution )
         (2)    负载平衡(load balancing)
         (3)    备份(Backups) 
         (4)    高可用性和容错行 High availability and failover 

  1.3 复制如何工作 

        整体上来说,复制有3个步骤:   

       (1)    master将改变记录到二进制日志(binary log)中(这些记录叫做二进制日志事件,binary log events);
       (2)    slave将master的binary log events拷贝到它的中继日志(relay log);
        (3)    slave重做中继日志中的事件,将改变反映它自己的数据。

下图描述了复制的过程:

                                  

          该过程的第一部分就是master记录二进制日志。在每个事务更新数据完成之前,master在二日志记录这些改变。MySQL将事务串行的写入二进制日志,即使事务中的语句都是交叉执行的。在事件写入二进制日志完成后,master通知存储引擎提交事务。
       下一步就是slave将master的binary log拷贝到它自己的中继日志。首先,slave开始一个工作线程——I/O线程。I/O线程在master上打开一个普通的连接,然后开始binlog dump process。Binlog dump process从master的二进制日志中读取事件,如果已经跟上master,它会睡眠并等待master产生新的事件。I/O线程将这些事件写入中继日志。
       SQL slave thread(SQL从线程)处理该过程的最后一步。SQL线程从中继日志读取事件,并重放其中的事件而更新slave的数据,使其与master中的数据一致。只要该线程与I/O线程保持一致,中继日志通常会位于OS的缓存中,所以中继日志的开销很小。
        此外,在master中也有一个工作线程:和其它MySQL的连接一样,slave在master中打开一个连接也会使得master开始一个线程。复制过程有一个很重要的限制——复制在slave上是串行化的,也就是说master上的并行更新操作不能在slave上并行操作。

 2 .复制配置

有两台 MySQL数据库服务器Master和slave,Master为主服务器,slave为从服务器,初始状态时,Master和slave中的数据信息相同,当Master中的数据发生变化时,slave也跟着发生相应的变化,使得master和slave的数据信息同步,达到备份的目的。

要点:
负责在主、从服务器传输各种修改动作的媒介是主服务器的二进制变更日志,这个日志记载着需要传输给从服务器的各种修改动作。因此,主服务器必须激活二进制日志功能。从服务器必须具备足以让它连接主服务器并请求主服务器把二进制变更日志传输给它的权限。
        
环境:
Master和slave的MySQL数据库版本同为5.0.18
操作系统:unbuntu 11.10
IP地址:10.100.0.100

2.1、创建复制帐号

1、在Master的数据库中建立一个备份帐户:每个slave使用标准的MySQL用户名和密码连接master。进行复制操作的用户会授予REPLICATION SLAVE权限。用户名的密码都会存储在文本文件master.info中

命令如下:
mysql > GRANT REPLICATION SLAVE,RELOAD,SUPER ON *.* 
TO backup@’10.100.0.200’ 
IDENTIFIED BY ‘1234’;

建立一个帐户backup,并且只能允许从10.100.0.200这个地址上来登陆,密码是1234。

(如果因为mysql版本新旧密码算法不同,可以设置:set password for 'backup'@'10.100.0.200'=old_password('1234'))

2.2、拷贝数据

(假如是你完全新安装mysql主从服务器,这个一步就不需要。因为新安装的master和slave有相同的数据)

关停Master服务器,将Master中的数据拷贝到B服务器中,使得Master和slave中的数据同步,并且确保在全部设置操作结束前, 禁止在Master和slave服务器中进行写操作,使得两数据库中的数据一定要相同!

2.3、配置master

接下来对master进行配置,包括打开二进制日志,指定唯一的servr ID。例如,在配置文件加入如下值:

server-id=1
log-bin=mysql-bin

server-id:为主服务器A的ID值
log-bin:二进制变更日值

重启master,运行SHOW MASTER STATUS,输出如下:


2.4、配置slave

Slave的配置与master类似,你同样需要重启slave的MySQL。如下:
log_bin           = mysql-bin
server_id         = 2
relay_log         = mysql-relay-bin
log_slave_updates = 1
read_only         = 1
server_id是必须的,而且唯一。slave没有必要开启二进制日志,但是在一些情况下,必须设置,例如,如果slave为其它slave的master,必须设置bin_log。在这里,我们开启了二进制日志,而且显示的命名(默认名称为hostname,但是,如果hostname改变则会出现问题)。
relay_log配置中继日志,log_slave_updates表示slave将复制事件写进自己的二进制日志(后面会看到它的用处)。
有些人开启了slave的二进制日志,却没有设置log_slave_updates,然后查看slave的数据是否改变,这是一种错误的配置。所以,尽量使用read_only,它防止改变数据(除了特殊的线程)。但是,read_only并是很实用,特别是那些需要在slave上创建表的应用。

2.5、启动slave

接下来就是让slave连接master,并开始重做master二进制日志中的事件。你不应该用配置文件进行该操作,而应该使用CHANGE MASTER TO语句,该语句可以完全取代对配置文件的修改,而且它可以为slave指定不同的master,而不需要停止服务器。如下:

mysql> CHANGE MASTER TO MASTER_HOST='server1',

    -> MASTER_USER='repl',

    -> MASTER_PASSWORD='p4ssword',

    -> MASTER_LOG_FILE='mysql-bin.000001',

    -> MASTER_LOG_POS=0;

MASTER_LOG_POS的值为0,因为它是日志的开始位置。

你可以用SHOW SLAVE STATUS语句查看slave的设置是否正确:

mysql> SHOW SLAVE STATUS\G

*************************** 1. row ***************************

             Slave_IO_State:

                Master_Host: server1

                Master_User: repl

                Master_Port: 3306

              Connect_Retry: 60

            Master_Log_File: mysql-bin.000001

        Read_Master_Log_Pos: 4

             Relay_Log_File: mysql-relay-bin.000001

              Relay_Log_Pos: 4

      Relay_Master_Log_File: mysql-bin.000001

           Slave_IO_Running: No

          Slave_SQL_Running: No

                             ...omitted...

      Seconds_Behind_Master: NULL

 

Slave_IO_State, Slave_IO_Running, 和Slave_SQL_Running是No

表明slave还没有开始复制过程。日志的位置为4而不是0,这是因为0只是日志文件的开始位置,并不是日志位置。实际上,MySQL知道的第一个事件的位置是4。

为了开始复制,你可以运行:

mysql> START SLAVE;

运行SHOW SLAVE STATUS查看输出结果:

mysql> SHOW SLAVE STATUS\G

*************************** 1. row ***************************

             Slave_IO_State: Waiting for master to send event

                Master_Host: server1

                Master_User: repl

                Master_Port: 3306

              Connect_Retry: 60

            Master_Log_File: mysql-bin.000001

        Read_Master_Log_Pos: 164

             Relay_Log_File: mysql-relay-bin.000001

              Relay_Log_Pos: 164

      Relay_Master_Log_File: mysql-bin.000001

           Slave_IO_Running: Yes

          Slave_SQL_Running: Yes

                             ...omitted...

      Seconds_Behind_Master: 0

在这里主要是看:
                   Slave_IO_Running=Yes
                   Slave_SQL_Running=Yes

slave的I/O和SQL线程都已经开始运行,而且Seconds_Behind_Master不再是NULL。日志的位置增加了,意味着一些事件被获取并执行了。如果你在master上进行修改,你可以在slave上看到各种日志文件的位置的变化,同样,你也可以看到数据库中数据的变化。

你可查看master和slave上线程的状态。在master上,你可以看到slave的I/O线程创建的连接:

在master上输入show processlist\G;

mysql> show processlist \G

*************************** 1. row ***************************

     Id: 1

   User: root

   Host: localhost:2096

     db: test

Command: Query

   Time: 0

 State: NULL

   Info: show processlist

*************************** 2. row ***************************

     Id: 2

   User: repl

   Host: localhost:2144

     db: NULL

Command: Binlog Dump

   Time: 1838

 State: Has sent all binlog to slave; waiting for binlog to be updated

   Info: NULL

2 rows in set (0.00 sec)

行2为处理slave的I/O线程的连接。

在slave服务器上运行该语句:

 

mysql> show processlist \G

*************************** 1. row ***************************

     Id: 1

   User: system user

   Host:

     db: NULL

Command: Connect

   Time: 2291

 State: Waiting for master to send event

   Info: NULL

*************************** 2. row ***************************

     Id: 2

   User: system user

   Host:

     db: NULL

Command: Connect

   Time: 1852

 State: Has read all relay log; waiting for the slave I/O thread to update it

   Info: NULL

*************************** 3. row ***************************

     Id: 5

   User: root

   Host: localhost:2152

     db: test

Command: Query

   Time: 0

 State: NULL

   Info: show processlist

3 rows in set (0.00 sec)

行1为I/O线程状态,行2为SQL线程状态。

2.5、添加新slave服务器

假如master已经运行很久了,想对新安装的slave进行数据同步,甚至它没有master的数据。
此时,有几种方法可以使slave从另一个服务开始,例如,从master拷贝数据,从另一个slave克隆,从最近的备份开始一个slave。Slave与master同步时,需要三样东西:
(1)master的某个时刻的数据快照;
(2)master当前的日志文件、以及生成快照时的字节偏移。这两个值可以叫做日志文件坐标(log file coordinate),因为它们确定了一个二进制日志的位置,你可以用SHOW MASTER STATUS命令找到日志文件的坐标;
(3)master的二进制日志文件。

可以通过以下几中方法来克隆一个slave:
(1)    冷拷贝(cold copy)
停止master,将master的文件拷贝到slave;然后重启master。缺点很明显。
(2)    热拷贝(warm copy)
如果你仅使用MyISAM表,你可以使用mysqlhotcopy拷贝,即使服务器正在运行。
(3)    使用mysqldump
使用mysqldump来得到一个数据快照可分为以下几步:
<1>锁表:如果你还没有锁表,你应该对表加锁,防止其它连接修改数据库,否则,你得到的数据可以是不一致的。如下:
mysql> FLUSH TABLES WITH READ LOCK;
<2>在另一个连接用mysqldump创建一个你想进行复制的数据库的转储:
shell> mysqldump --all-databases --lock-all-tables >dbdump.db
<3>对表释放锁。
mysql> UNLOCK TABLES;

 

3、深入了解复制

已经讨论了关于复制的一些基本东西,下面深入讨论一下复制。

3.1、基于语句的复制(Statement-Based Replication)

     MySQL 5.0及之前的版本仅支持基于语句的复制(也叫做逻辑复制,logical replication),这在数据库并不常见。master记录下改变数据的查询,然后,slave从中继日志中读取事件,并执行它,这些SQL语句与master执行的语句一样。
这种方式的优点就是实现简单。此外,基于语句的复制的二进制日志可以很好的进行压缩,而且日志的数据量也较小,占用带宽少——例如,一个更新GB的数据的查询仅需要几十个字节的二进制日志。而mysqlbinlog对于基于语句的日志处理十分方便。
 
      但是,基于语句的复制并不是像它看起来那么简单,因为一些查询语句依赖于master的特定条件,例如,master与slave可能有不同的时间。所以,MySQL的二进制日志的格式不仅仅是查询语句,还包括一些元数据信息,例如,当前的时间戳。即使如此,还是有一些语句,比如,CURRENT USER函数,不能正确的进行复制。此外,存储过程和触发器也是一个问题。
     另外一个问题就是基于语句的复制必须是串行化的。这要求大量特殊的代码,配置,例如InnoDB的next-key锁等。并不是所有的存储引擎都支持基于语句的复制。

3.2、基于记录的复制(Row-Based Replication)

      MySQL增加基于记录的复制,在二进制日志中记录下实际数据的改变,这与其它一些DBMS的实现方式类似。这种方式有优点,也有缺点。优点就是可以对任何语句都能正确工作,一些语句的效率更高。主要的缺点就是二进制日志可能会很大,而且不直观,所以,你不能使用mysqlbinlog来查看二进制日志。
对于一些语句,基于记录的复制能够更有效的工作,如:
mysql> INSERT INTO summary_table(col1, col2, sum_col3)
    -> SELECT col1, col2, sum(col3)
    -> FROM enormous_table
    -> GROUP BY col1, col2;
     假设,只有三种唯一的col1和col2的组合,但是,该查询会扫描原表的许多行,却仅返回三条记录。此时,基于记录的复制效率更高。
    另一方面,下面的语句,基于语句的复制更有效:
 mysql> UPDATE enormous_table SET col1 = 0;
此时使用基于记录的复制代价会非常高。由于两种方式不能对所有情况都能很好的处理,所以,MySQL 5.1支持在基于语句的复制和基于记录的复制之前动态交换。你可以通过设置session变量binlog_format来进行控制。

3.3、复制相关的文件

除了二进制日志和中继日志文件外,还有其它一些与复制相关的文件。如下:

(1)mysql-bin.index

服务器一旦开启二进制日志,会产生一个与二日志文件同名,但是以.index结尾的文件。它用于跟踪磁盘上存在哪些二进制日志文件。MySQL用它来定位二进制日志文件。它的内容如下(我的机器上):

 (2)mysql-relay-bin.index

该文件的功能与mysql-bin.index类似,但是它是针对中继日志,而不是二进制日志。内容如下:
.\mysql-02-relay-bin.000017
.\mysql-02-relay-bin.000018

(3)master.info

保存master的相关信息。不要删除它,否则,slave重启后不能连接master。内容如下(我的机器上):

 I/O线程更新master.info文件,内容如下(我的机器上):

 

.\mysql-02-relay-bin.000019

254

mysql-01-bin.000010

286

0

52813

 

 

 (4)relay-log.info 

包含slave中当前二进制日志和中继日志的信息。

 

 

3.4、发送复制事件到其它slave

当设置log_slave_updates时,你可以让slave扮演其它slave的master。此时,slave把SQL线程执行的事件写进行自己的二进制日志(binary log),然后,它的slave可以获取这些事件并执行它。如下:

 

 

3.5、复制过滤(Replication Filters)

复制过滤可以让你只复制服务器中的一部分数据,有两种复制过滤:在master上过滤二进制日志中的事件;在slave上过滤中继日志中的事件。如下:

 

 

4、复制的常用拓扑结构

复制的体系结构有以下一些基本原则:
(1)    每个slave只能有一个master;
(2)    每个slave只能有一个唯一的服务器ID;
(3)    每个master可以有很多slave;
(4)    如果你设置log_slave_updates,slave可以是其它slave的master,从而扩散master的更新。

MySQL不支持多主服务器复制(Multimaster Replication)——即一个slave可以有多个master。但是,通过一些简单的组合,我们却可以建立灵活而强大的复制体系结构。

 

4.1、单一master和多slave

由一个master和一个slave组成复制系统是最简单的情况。Slave之间并不相互通信,只能与master进行通信。如下:

 如果写操作较少,而读操作很时,可以采取这种结构。你可以将读操作分布到其它的slave,从而减小master的压力。但是,当slave增加到一定数量时,slave对master的负载以及网络带宽都会成为一个严重的问题。
这种结构虽然简单,但是,它却非常灵活,足够满足大多数应用需求。一些建议:
(1)    不同的slave扮演不同的作用(例如使用不同的索引,或者不同的存储引擎);
(2)    用一个slave作为备用master,只进行复制;
(3)    用一个远程的slave,用于灾难恢复;

 

4.2、主动模式的Master-Master(Master-Master in Active-Active Mode)

Master-Master复制的两台服务器,既是master,又是另一台服务器的slave。如图:

主动的Master-Master复制有一些特殊的用处。例如,地理上分布的两个部分都需要自己的可写的数据副本。这种结构最大的问题就是更新冲突。假设一个表只有一行(一列)的数据,其值为1,如果两个服务器分别同时执行如下语句:
在第一个服务器上执行:
mysql> UPDATE tbl SET col=col + 1;
在第二个服务器上执行:
mysql> UPDATE tbl SET col=col * 2;
那么结果是多少呢?一台服务器是4,另一个服务器是3,但是,这并不会产生错误。
实际上,MySQL并不支持其它一些DBMS支持的多主服务器复制(Multimaster Replication),这是MySQL的复制功能很大的一个限制(多主服务器的难点在于解决更新冲突),但是,如果你实在有这种需求,你可以采用MySQL Cluster,以及将Cluster和Replication结合起来,可以建立强大的高性能的数据库平台。但是,可以通过其它一些方式来模拟这种多主服务器的复制。

 

4.3、主动-被动模式的Master-Master(Master-Master in Active-Passive Mode)

这是master-master结构变化而来的,它避免了M-M的缺点,实际上,这是一种具有容错和高可用性的系统。它的不同点在于其中一个服务只能进行只读操作。如图:

 4.4、带从服务器的Master-Master结构(Master-Master with Slaves)

这种结构的优点就是提供了冗余。在地理上分布的复制结构,它不存在单一节点故障问题,而且还可以将读密集型的请求放到slave上。



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐




如何摆脱工具类

$
0
0

英文原文: How to get rid of helper and utils classes

无论是进行代码 review 还是紧急编码调整,你总会发现:你又搞出了一个帮助类(helper class)。代码运行一切正常,进度又必须跟上,发布任务一个接一个,因此那个帮助类逐渐变成了一个提供了很多静态(static)方法的“怪兽类”(monster class),在它的 utils 包内不受控制地增长。utils 包长久以来就是一个技术争议的荒蛮之地,面向对象设计理念连半步都不敢踏入。“工具类是功能集中,并且逻辑毫不重复(Do not repeat yourself)” 一些开发人员会这样喊道 ,通常就是他们编写了这些工具类。因为所有都是静态的,所以它很快 - 团队里面的另外一些人这样说,也许就是是添加另外一些静态方法的人。它很容易使用,我们使这些代码很简洁 — 你可以在这个空间内听到这样的言论,但这又是 另外一个对 KISS 的误解了

我们会争论到:通常帮助类和工具类都很简单,特别是当我们不能修改新功能的目标类(例如外部依赖库)或我们不能找到使用的目标(不清晰的领域模型,PoC,需求缺失),或者我们只是不想去找它(懒,这也是帮助类的最主要原因)。但是最大的问题在于这很明显不是面向对象的解决方案,并且随着时间的推移(缺少团队沟通,资源重用,快速修复和一些其他的东西)它会导致一些包含无尽静态方法的容器和令人头疼的维护(你想要做到 DRY,但你却是用 10 个方法来提供几乎相同的功能,尽管不是完全一样;你想要快速,但你现在不能方便地添加一个 cache 机制到那个静态类中或者你遇到了并发的麻烦;你想使事情变得简单,但现在你的 IDE 提供了一长列的各种各样的方法,这并不能简化你的工作)。但不要担心,我们会尝试着去解决它。

让我们来重构帮助类

首先,我们需要定义我们的问题:一个只提供静态方法的无状态类(有 Helper 或 Utils 后缀),它没有明确的职责,在项目中也不会被初始化为对象。

接着,我们需要一个几乎明确的方案来解决问题。这几乎就代表了例外和项目特性:最后的决定当然是根据具体的情况来了,任何被称为通用解决方案的基本上都可以忽略。我们最后需要分析一下给出的类,尝试着:

  • 找到一个确定静态方法从属的目标类
  • 或找到这个类实际提供的目标业务实体,然后把它迁移到相关的组件,重命名并且删除静态方法(替换它们)
  • 或者通过面向对象方式添加一个提供一个或多个行为(之前存在的静态方法)新类。

上面的任何方案都可以提供一个更好的模型。然后我们再依据下面的步骤(假设根据下面的步骤进行项目重构):

  1. 为了使我们的任务简单些,我们删掉项目的帮助类中没用的方法(你的 IDE 将会帮你大忙)。
  2. 接下来我们把 class 定义为 final。你看到项目中有编译错误了吗?如果有,为什么帮助类或工具类需要被继承呢?你也许已经有一个目标:子类。如果子类是另外一个帮助类(真的吗?),把它和父类合并吧。
  3. 如果不存在,我们为该类添加一个私有构造函数。你看到项目中出现了编译错误了吗?那么肯定在哪个地方初始化了这个类,所以这并不是单纯的帮助类或者它没有被正确使用。看一下那些调用方,你会发现一个或一系列方法都可能属于这个目标类(或者实体)。
  4. 让我们通过一定规则类似的签名来分组类方法,将它们拆分到更小的帮助类中(从繁杂到有共性的方法,那个共性也许就是我们需要的目标实体了)。通常到了这一步,我们会从一个大的工具类向更轻量的帮助类过渡(提示:这时候不要害怕创建一个只有一个方法的类),同时我们的范围缩小了(从 ProjectUtilsCarHelperEngineHelperWheelHelper等等)。(好,你的代码难道看起来不是更简洁了吗?)
  5. 如果这些新类只有一个方法,我们需要看一下它的用途。如果我们只有一个调用者,那么恭喜你,那就是我们的目标类了!你可以把方法移到类中,作为 behavior 或私有方法(保持它的 static 标识或者利用内部状态)。这个帮助类就消失了。

  6. 我们目前得到的帮助类(但是它确实可以成为你的起点)确定了这些关联方法的一个通用状态。提示:看一下那些方法中的大部分通用参数(例如,所有方法都接收一个 Car对象),这表明,这些方法可能应该作为方法属于 Car类(或者扩展?封装类?)。否则,这些通用的参数应该是一个可以传给构造函数并且被所有(非静态和其他的)方法使用的类的属性,状态。那个属性应该会使你想起类的前缀,方法的归类可以使你想起一系列行为的类( CarValidatorCarReaderCarConverter等等)。那么这个帮助类又可以去掉了。

  7. 如果这堆方法根据可选的输入和一些相同输入参数来使用不同的参数,那么考虑通过使用建造者模式(Builder pattern)定义可变的接口来转换这个帮助类:从一系列类似 Helper.calculate (x)calculate (x, y)calculate (x, z)calculate (y, z)的静态方法我们可以简单地想到如 newBuilder () .with (x) .with (y) .calculate ()。帮助类会提供 behaviours,减少业务方法列表,并且提供更好的扩展性。调用方可以把它当作内部属性来重用或者在需要的时候再初始化。这个帮助类(我们所知的)又可以去掉了。
  8. 如果帮助类提供的方法确实是供不同的参数使用的(但,在这个时候,都是用于同一对象的),可以考虑使用命令模式(Command pattern):调用方实际上创建必须的命令(处理必须的输入和提供必要的操作),在确定的上下文情况下会有一个调用者进行执行。你也许可以获取到每个静态方法的命令实现,你的代码也从 Helper.calculate (x,y)calculate (z)变成了 invoker.calculate (new Action (x, y))。帮助类再见。

  9. 如果帮助类提供的方法接收相同的参数,但处理不同的逻辑,可以考虑使用策略模式( Strategy pattern):每一个静态方法都可以简单地变成一个策略实现,从而消除原来的帮助类(取而代之的是上下文组件)。

  10. 如果需要处理的多个静态方法涉及到一个类层次或一系列的组件,可以考虑使用访问者模式( Visitor pattern):你可以根据不同的访问方法得到几个访问者实现,这也许可以替换部分或所有之前存在的静态方法。
  11. 如果之前的情况都不符合你的情况,那可以使用三个最重要的指标:你的经验,你的项目能力和直觉。

总结

过程很简单,找到对的实体和合理的目标类或者通过一种采用面向对象设计的标准方法来重构给定的帮助类(但会在代码复杂度上有所增加,值得吗?)。过一下上面提到的场景列表,也许当你尝试理解怎么去实现重构时会有多于一个将会为你提供灵感;特定的限制也许会限制已确定的解决方案;复杂的静态方法和相关的流程也许需要几个重构的步骤,可以一直优化它直到得到可接受的结果。或者你可以选择在某种程度上以代码可读性和 简单性的名义来维持原来的帮助类(希望能满足上面至少 5 个步骤)。帮助类并不都是有害的,但绝大多数情况下你并不需要它们。

参考:  如休整脱离帮助类和工具类参考自我们的 JCG 成员 Antonio Di Matteo 重构的建议

翻译:  ImportNew.com 陈晓舜
译文链接:  http://www.importnew.com/11593.html

本文链接

腾讯移动前端框架 mt 2.0 发布

$
0
0

MT是手机腾讯网前端团队开发维护的一个专注于移动端的js模块管理框架。

Git: http://git.oschina.net/luyongfugx/mt
mt介绍文档: http://mt.tencent.com/mt1index.html

为什么使用MT

  • 无更新不下载

  • 简单友好的模块定义规范

  • 简单易用的打包管理工具

  • 强大的js增量更新代理服务

MT2.0新增特性

  • 本地存储异常回调

  • 统计回调

  • combo支持

  • 新增LCS增量算法

1.  本地存储异常,统计回调

设置回调

通过设施g_config的storeInc对象的statFunc,storeExFunc两个函数,可以设置统计和本地存储异常回调 , statFunc在请求每个js的时候触发,便于统计每个js的请求情况,storeExFunc在写本地存储异常回调, 将脚本内容写入本地存储出现异常的时候调用,用来提供给业务清理本地存储。

storeInc:{  
    //统计回调,统计脚本请求情况,jsUrl是js地址,  
    //mode是请求模式,full:表示全量请求,  
    //inc表示增量请求,local表示从本地存储读取  
    'statFunc':function(jsUrl,mode){  
        console.log('get '+jsUrl+' from '+mode);  
    },  
    //写本地存储异常回调,将脚本内容写入本地存储  
    //出现异常的时候调用,用来提供给业务清理本地存储  
    //,storekey表示写如的key  
    'storeExFunc':function(storeKey){  
        console.log('set store item '+storeKey+' exception');  
    },  
    'store': true,  
    'inc': true,  
    'proxy':true,  
    'debug': false  
},

2.  combo支持

冷combo

冷combo就是在打包混淆的时候把多个不同的模块打包进同一个js,前台下载的时候直接下载这个js 这个MT1.0已经支持,打包配置如下:

{  
    './release/{pv}/base-{fv}.js': {  
           files: ['./js/init.js','./js/util.js']  
    },  
    './release/{pv}/page/p1-{fv}.js': {  
       files: ['./js/page/p1.js']  
    },  
    './release/{pv}/page/p2-{fv}.js': {  
       files: ['./js/page/p2.js']  
    },  
    './release/{pv}/page/p3-{fv}.js': {  
       files: ['./js/page/p3.js']  
    }  
}

可以看到我们的init,util模块被打到base.js里,达到冷combo的目的

热combo,半热combo

半热combo是相对冷combo来说的,除了走打包实现冷combo以外,我们还支持通过前台配置来实现半热combo或热combo

combo:{  
     //是否启用combo  
    cb:true,  
    //哪些模块的js走半热combo一块下载  
   //,这里数组的每个项是要一起下载的模块  
    conf:['init,util','p1,p2,p3']  
  
}

上面的代码,我们设置了combo的cb为true,说明走combo. conf的配置则设置了哪些模块是要走combo一起下载的, 即使打包脚本没有把他们打在一起。 为了看效果,我们先把cb设为false,conf设置为空数组,表示不走combo:

combo:{  
//是否启用combo  
cb:flase,  
//哪些模块的js走半热combo一块下载  
//,这里数组的每个项是要一起下载的模块  
conf:[]  
  
}

我们看下网络请求:



可以看到base.js,p1.js,p2.js,p3.js是分开下载的,说明没有走combo,然后设置了combo的cb为true,说明走combo. 我们看下网络请求:



可以看到base.js,p1.js是分开下载的,而p2.js,p3.js是一起下载的,这是因为mt2.0自己分析了依赖,把某个模块共同依赖一起下载了,这个例子里面p1依赖了p2,p3两个模块 所以p2,p3被一起下载了,这就是热combo!

这时候我们想,我想让p1,p2,p3一次就下载了,怎么弄?很简单,我们只要设置combo.conf为如下

combo:{  
//是否启用combo  
cb:true,  
//哪些模块的js走半热combo一块下载  
//,这里数组的每个项是要一起下载的模块  
conf:['init,util','p1,p2,p3']  
  
}

我们看下网络请求:



ok,p1,p2,p3一次就下载了!!,这就是半热combo,需要配置一下conf.

3.  新增基于lcs算法的增量更新

MT1.0的增量更新是基于chunk算法来实现的,精确度是到块级别的。后来很多朋友给我意见,说其实可以做得更加精确一些,精确到字符级别。 于是我用lcs算法实现了精确到字符级别的设计,最后这个demo也可以看作是整个MT2.0的使用方法

首先到我们的github: https://github.com/mtjs/mt下载代码,然后看mt2.0文件夹下的demo目录,里面有个test.html,可以看到总配置代码

var g_config =  {  
    jsmap:{  
        'init': 'base.js',  
        'util': 'base.js',  
        'p1': 'page/p1.js',  
        'p2': 'page/p2.js',  
        'p3': 'page/p3.js'  
    },  
    storeInc:{  
        //统计回调,统计脚本请求情况,jsUrl是js地址,mode是请求模式,full:表示全量请求,inc表示增量请求,local表示从本地存储读取  
        'statFunc':function(jsUrl,mode){  
            console.log('get '+jsUrl+' from '+mode);  
        },  
        //写本地存储异常回调,将脚本内容写入本地存储出现异常的时候调用,用来提供给业务清理本地存储,storekey表示写如的key  
        'storeExFunc':function(storeKey){  
            console.log('set store item '+storeKey+' exception') ;  
        },  
        'store': true,  
        'inc': true,  
        'proxy':true,  
        'debug': false  
    },  
    //是否走combo,同时支持conf指定哪几个js是合并下载的  
  
    combo:{cb:true,conf:["init,util","p1,p2,p3"]},  
    testEnv: false,  
    staticPath: '/release',  
    serverDomain: 'http://localhost:6600',  
    buildType: 'project',  
    ver: '2014053000002'  
  
};

在2014053000002版本,我们的p2代码如下:

define('p2', [], function () {  
console.log('p2 ok!');  
document.write('p2 ok!<br>');  
});  
  
}

本地打包

我们运行demo目录下的build.sh ,其实是执行命令

node ../js/mtbuild.js test.html build.conf  lcs

第三个参数说明走lcs增量更新算法,你也可以设置成chunk走老算法

启动增量服务

到js目录下执行命令

node storeincServer.js lcs ../demo

第2个参数说明走lcs增量更新算法,你也可以设置成chunk走老算法,第三个参数是根目录,这里设置成../demo

效果演示

打开chrome(必须支持localstorage),输入地址:http://localhost:6600/test.html,可以看到请求的是全量的js



本地存储里的内容是2014053000002版本的:




接着我们修改p2.js代码,加上"lcs"这3个字 :

define('p2', [], function () {  
console.log('p2 ok!');  
document.write('p2 ok lcs!<br>');  
});

然后重新运行命令

node ../js/mtbuild.js test.html build.conf  lcs

这时候生成2014053000003版本代码,打开chrome(必须支持localstorage), 输入地址:http://localhost:6600/test.html,这时候可以看到请求的内容是增量的,并且精确到了字符级别:



我们来看下同样是这个修改,如果我们走chunk算法,会是什么样子。 我们需要重新走一遍上边的流程,但是把build.sh命令的lcs参数改成chunk,启动storeincServer时的lcs也改成chunk, 这里就不罗嗦步骤了,我们直接看看走chunk是的网络请求:



发现相对lcs算法,chunk的精确度是比较差的,所以推荐使用lcs算法

阿里巴巴全资收购UC优视:组建新移动事业群

$
0
0
6月11日上午消息,阿里巴巴集团与UC优视今日联合宣布,UC优视全资融入阿里巴巴集团,并组建阿里UC移动事业群。UC优视董事长兼CEO俞永福将担任UC移动事业群总裁,并进入阿里集团战略决策委员会。

   整合以股票置换为主 估值远超19亿美元

  俞永福在内部员工信中表示,此次整合将创造中国互联网史上最大的并购整合:本次整合将大部分以阿里巴巴集团股票,配合部分现金的方式进行,整个交易对UC的估值远远超过之前“中国互联网最大并购交易”百度对91的19亿美元估值。

据了解,本次整合将主要以阿里巴巴集团股票置换为主,配合部分现金。总金额或将创造中国互联网史上最大的并购整合。有观点认为,UC优视通过此次融合实现了上市。

“如果为了控制力,不上市和晚上市无疑对创业者更有利。但作为团队带头人,我们有巨大的责任和压力帮大家实现更好的个人发展和物质回报。”俞永福表示,上市不是创业的最终目的,而只是为了实现企业发展、公司品牌和团队激励的一个过程。

“阿里巴巴集团在过去五年的合作中,对UC这支创业团队一直非常肯定,本次整合也给出了一个中国互联网历史上最高的价格方案,并通过换股给了UC的同学们一个快速上市、享受价值成长的机会。”

俞永福还指出,整合完成后,仍会继续保持创业初心,在与阿里巴巴集团的各种前瞻性布局和业务充分融合后,能够淋漓尽致地发挥势能。
............

Tags - , ,

IE11中打开网站不兼容的终极解决方案

$
0
0

在Win8.1的IE11环境里面,不少网站即使通过兼容视图也无法正常显示,为了应对网站不兼容的情况,我们给大家提供过很多方法,比如 在F12开发人员工具修改仿真模式,或者 将IE的字符串修改低版本IE号,现在终于有了终极的解决方案了。我们只需先安装好Win8.1 2014 Update补丁,然后,就可以开启IE11的企业模式来正常显示那些网站了。不知道如何安装的,自己百度一下即可,非常简单!

首先,我们按“Win+Q”组合键打开搜索窗口,输入“gpedit.msc”命令打开组策略编辑器,依次定位到“计算机配置→管理模板→Windows组件→Internet Explorer”,在右侧选择“允许用户从‘工具’菜单启用和使用企业模式”(如图1)选项;双击打开该选项,设置为“启用”(如图2);重启系统后,IE11的企业模式就可用了。

单击“启用和使用企业模式”选项

图1

将企业模式设置为“启用”

图2

现在,你再在IE11浏览器中打开以前无法正常显示的网站时,只需单击“工具→企业模式”命令即可以IE8兼容模式访问了(如图3)。另一种启用企业模式的方法是:按F12打开开发工具,切换到“仿真”,更改“浏览器配置文件”为“企业”(如图4)。

在IE11中打开企业模式

图3

默认则以IE8IE8兼容模式访问网站

图4

This article addresses: http://www.iefans.net/ie11-wangzhan-bujianrong-zhongji-fangan/

Here is no comments yet by the time your rss reader get this, Do you want to be the first commentor? Hurry up

如何评价 UC 并入阿里巴巴?

$
0
0

UC并入阿里,是一个让人思绪很多的事情。除了已有的从资本角度、公司角度的考虑,我想的更多的是关于产品。

1、国际化

第一想到的是国际化问题。我对UC的感受一直分两个方面,一是适合屌丝,二是国外效果好。听做国外市场的朋友讲,UC在国外市场,特别是印度、东南亚市场的效果,近乎达到了QQ在国内的情形(脑补份额80%以上),考虑到东南亚、印度暂未形成微信这种超级APP,UC浏览器作为常用APP,价值巨大。

2、产品整合

产品整合是指UC和阿里旗下现有的产品的整合,个人主想象的是支付宝和淘宝,和天猫无关(天猫气质与UC不符)。类似微信客户端结合微信支付,来硬推微信支付。手机支付宝虽然装机量巨大,但是打开率较低,用户只有在需要付费时才打开。而UC则相反,打开率很高。试想用户在UC的首页、搜索推荐页、内级推荐页、404等页面布满商品流量的中心化和去中心化的入口,打开即可快速拉起支付宝app来支付,和淘宝快速拉起支付包app来支付,分别满足闲逛时看到商品的支付,和专门找商品的支付,这两种电商场景。

如果这块选品恰当,估计效果应当不差。这点估计大佬们早就烂熟于心,也已经开始各种对老板们的心态挖掘的类似狗仔队的文章,如阿里并UC:四个男人间的故事终局

3、产品感觉

阿里不是互联网公司,我一直这么认为。除了支付宝在抄微信外,阿里其他产品,基本产品设计和运营在决策中的权重,设计远远让于运营。阿里不是不知道这点,但是内心基因永远是商品更重要。对电商来讲,确认是这样。但是对于一些新兴的或阿里不熟悉的领域,如O2O、游戏、内容分发,阿里基因不管用。

而UC相反,UC相对少运营,单纯靠产品功能吸引用户口碑和用户传播,早期UC省流量的形象在用户心中深扎,并不是靠的宣传,而是靠的实际细节功能。UC的基因是用精准的产品细节和体验,和关键点,来打动用户,让UC来做相对新的移动互联网,比阿里自己继续来用做生意的思路来做产品,我觉得要好得多。

如何系统地学习数据挖掘?

$
0
0
数据挖掘:What?Why?How?
这个问题思考了很久,作为过来人谈一谈,建议先看下以前的一些回答。

磨刀不误砍柴工。在学习数据挖掘之前应该明白几点:
  • 数据挖掘目前在中国的尚未流行开,犹如屠龙之技。
  • 数据初期的准备通常占整个数据挖掘项目工作量的70%左右。
  • 数据挖掘本身融合了 统计学、数据库和机器学习等学科,并不是新的技术。
  • 数据挖掘技术更适合业务人员学习(相比技术人员学习业务来的更高效)
  • 数据挖掘适用于传统的BI(报表、OLAP等)无法支持的领域。
  • 数据挖掘项目通常需要重复一些毫无技术含量的工作。

如果你阅读了以上内容觉得可以接受,那么继续往下看。

学习一门技术要和行业靠拢,没有行业背景的技术如空中楼阁。技术尤其是计算机领域的技术发展是宽泛且快速更替的(十年前做网页设计都能成立公司),一般人没有这个精力和时间全方位的掌握所有技术细节。但是技术在结合行业之后就能够独当一面了,一方面有利于抓住用户痛点和刚性需求,另一方面能够累计行业经验,使用互联网思维跨界让你更容易取得成功。不要在学习技术时想要面面俱到,这样会失去你的核心竞争力。

一、目前国内的数据挖掘人员工作领域大致可分为三类。
  • 1)数据分析师:在拥有行业数据的电商、金融、电信、咨询等行业里做业务咨询,商务智能,出分析报告。
  • 2)数据挖掘工程师:在多媒体、电商、搜索、社交等大数据相关行业里做机器学习算法实现和分析。
  • 3)科学研究方向:在高校、科研单位、企业研究院等高大上科研机构研究新算法效率改进及未来应用。

二、说说各工作领域需要掌握的技能。
(1).数据分析师
  • 需要有深厚的数理统计基础,但是对程序开发能力不做要求。
  • 需要熟练使用主流的数据挖掘(或统计分析)工具如 Business Analytics and Business Intelligence Software (SAS)、 SPSS 、EXCEL等。
  • 需要对与所在行业有关的一切核心数据有深入的理解,以及一定的数据敏感性培养。
  • 经典图书推荐:《概率论与数理统计》、《统计学》推荐David Freedman版、《业务建模与数据挖掘》、《数据挖掘导论》、《SAS编程与数据挖掘商业案例》、《Clementine数据挖掘方法及应用 》、《Excel 2007 VBA参考大全》、《IBM SPSS Statistics 19 Statistical Procedures Companion》等。
(2).数据挖掘工程师
  • 需要理解主流机器学习算法的原理和应用。
  • 需要熟悉至少一门编程语言如(Python、C、C++、Java、Delphi等)。
  • 需要理解数据库原理,能够熟练操作至少一种数据库(Mysql、SQL、DB2、Oracle等),能够明白MapReduce的原理操作以及熟练使用Hadoop系列工具更好。
  • 经典图书推荐:《数据挖掘概念与技术》、《机器学习实战》、《人工智能及其应用》、《数据库系统概论》、《算法导论》、《Web数据挖掘》、《 Python标准库》、《thinking in Java》、《Thinking in C++》、《数据结构》等。
(3).科学研究方向

三、以下是通信行业数据挖掘工程师的工作感受。

真正从数据挖掘项目实践的角度讲,沟通能力对挖掘的兴趣爱好是最重要的,有了爱好才可以愿意钻研,有了不错的沟通能力,才可以正确理解业务问题,才能正确把业务问题转化成挖掘问题,才可以在相关不同专业人才之间清楚表达你的意图和想法,取得他们的理解和支持。所以我认为沟通能力和兴趣爱好是个人的数据挖掘的核心竞争力,是很难学到的;而其他的相关专业知识谁都可以学,算不上个人发展的核心竞争力。

说到这里可能很多数据仓库专家、程序员、统计师等等都要扔砖头了,对不起,我没有别的意思,你们的专业对于数据挖掘都很重要,大家本来就是一个整体的,但是作为单独一个个体的人来说,精力有限,时间有限,不可能这些领域都能掌握,在这种情况下,选择最重要的核心,我想应该是数据挖掘技能和相关业务能力吧(从另外的一个极端的例子,我们可以看, 比如一个迷你型的挖掘项目,一个懂得市场营销和数据挖掘技能的人应该可以胜任。这其中他虽然不懂数据仓库,但是简单的Excel就足以胜任高打6万个样本的数据处理;他虽然不懂专业的展示展现技能,但是只要他自己看的懂就行了,这就无需什么展示展现;前面说过,统计技能是应该掌握的,这对一个人的迷你项目很重要;他虽然不懂编程,但是专业挖掘工具和挖掘技能足够让他操练的;这样在迷你项目中,一个懂得挖掘技能和市场营销业务能力的人就可以圆满完成了,甚至在一个数据源中根据业务需求可以无穷无尽的挖掘不同的项目思路,试问就是这个迷你项目,单纯的一个数据仓库专家、单纯的一个程序员、单纯的一个展示展现技师、甚至单纯的一个挖掘技术专家,都是无法胜任的)。这从另一个方面也说明了为什么沟通能力的重要,这些个完全不同的专业领域,想要有效有机地整合在一起进行数据挖掘项目实践,你说没有好的沟通能力行吗?

数据挖掘能力只能在项目实践的熔炉中提升、升华,所以跟着项目学挖掘是最有效的捷径。国外学习挖掘的人都是一开始跟着老板做项目,刚开始不懂不要紧,越不懂越知道应该学什么,才能学得越快越有效果。我不知道国内的数据挖掘学生是怎样学的,但是从网上的一些论坛看,很多都是纸上谈兵,这样很浪费时间,很没有效率。

另外现在国内关于数据挖掘的概念都很混乱,很多BI只是局限在报表的展示和简单的统计分析,却也号称是数据挖掘;另一方面,国内真正规模化实施数据挖掘的行业是屈指可数(银行、保险公司、移动通讯),其他行业的应用就只能算是小规模的,比如很多大学都有些相关的挖掘课题、挖掘项目,但都比较分散,而且都是处于摸索阶段,但是我相信数据挖掘在中国一定是好的前景,因为这是历史发展的必然。

讲到移动方面的实践案例,如果你是来自移动的话,你一定知道国内有家叫华院分析的公司(申明,我跟这家公司没有任何关系,我只是站在数据挖掘者的角度分析过中国大多数的号称数据挖掘服务公司,觉得华院还不错,比很多徒有虚名的大公司来得更实际),他们的业务现在已经覆盖了绝大多数中国省级移动公司的分析挖掘项目,你上网搜索一下应该可以找到一些详细的资料吧。我对华院分析印象最深的一点就是2002年这个公司白手起家,自己不懂不要紧,一边自学一边开始拓展客户,到现在在中国的移动通讯市场全面开花,的确佩服佩服呀。他们最开始都是用EXCEL处理数据,用肉眼比较选择比较不同的模型,你可以想象这其中的艰难吧。

至于移动通讯的具体的数据挖掘的应用,那太多了,比如不同话费套餐的制订、客户流失模型、不同服务交叉销售模型、不同客户对优惠的弹性分析、客户群体细分模型、不同客户生命周期模型、渠道选择模型、恶意欺诈预警模型,太多了,记住,从客户的需求出发,从实践中的问题出发,移动中可以发现太多的挖掘项目。最后告诉你一个秘密,当你数据挖掘能力提升到一定程度时,你会发现无论什么行业,其实数据挖掘的应用有大部分是重合的相似的,这样你会觉得更轻松。

四、成为一名数据科学家需要掌握的技能图。(原文: Data Science: How do I become a data scientist?




人一能之,己十之;人十能之,己千之。果能此道矣,虽愚,必明;虽柔,必强。
与君共勉。

以上,祝各位挖掘到自己的快乐和金矿:)

— 完 —
本文作者: Han Hsiao

【知乎日报】 你都看到这啦,快来点我嘛 Σ(▼□▼メ)

此问题还有 4 个回答,查看全部。
延伸阅读:
数据挖掘的系统教程是怎样的,包含哪些教材?
在数据分析、挖掘方面,有哪些好书值得推荐?

你可能不知道 智能手机还有这10个神奇功能

$
0
0

手机只能用来打电话和发短信的时代已经一去不复返了,如今我们早就习惯了用智能手机拍照、拍视频、收发邮件、查看网页以及运行各种各样的应用,而且各大厂商正在不断为智能手机添加更丰富的功能,比如指纹识别和心率监测。但是,你知道智能手机可以诊断汽车故障、扫描护照信息甚至自制显微镜吗?很多人或许从未想到,智能手机也能实现以下这10个比较“奇葩”的功能:

1. 红外线探测

我们用肉眼看不到红外线,但是智能手机的摄像头能探测到它——拿起电视、空调等家用电器的红外遥控器试试看:打开手机的相机应用,然后把遥控器的红外发射管对准摄像头,当你按键时你就会在取景器中看到它发出白色或紫色的光。你可以用这一招来检查遥控器的电池还有没有电。

105287973

2. 通过NFC读取护照信息

很多国家现在发放的护照都内置了存储持有者照片、指纹扫描图等信息的RFID(射频识别)芯片,而带有NFC(近场通信)功能的手机可以借助专门的应用扫取这些信息。当然,不是所有护照都支持这项功能。

105287977

3. 用蓝牙耳机当遥控快门

蓝牙手机可以充当智能手机的遥控拍照快门,但是并非所有蓝牙耳机都能这样做,而且你得自己摸索用哪个键和哪种按键组合方式(例如按音量增大键两次、按通话键三次,等等)。

105287994

4. 进行比特币挖矿

智能手机也能对比特币和其他加密货币进行挖矿。当然,这样做不能让你一夜暴富——即便用高端智能手机挖矿,可能每天也赚不到几分钱,而且还会大大增加手机的负荷甚至导致严重发热,最后往往得不偿失。但是,知道智能手机可以挖矿总归是件挺酷的事情。

105288012

5. 帮助科研人员攻克癌症等顽疾

在人类与癌症和其他顽疾进行的斗争中,智能手机也能出一份力——例如三星推出的免费应用“Power Sleep”能让手机在夜间充电时贡献运算力量,从而帮助进行抗癌研究的科研人员分析庞大的蛋白质分子数据。此外,HTC的“Power to Give”应用也能以类似的方式让智能手机为多种医学、环境和科学研究项目出力。

105288014

6. 加一滴水即可自制显微镜

在摄像头上滴一滴水,就能把智能手机变成简易显微镜,这滴水能作为“附加镜头”让摄像头进行超微距对焦。你的手越稳,拍出来的照片就越清晰,而图示照片是LG G2手机采用手动对焦并开启闪光灯拍摄的。当然,你往摄像头上滴水的时候一定要非常小心,如果手机进水可就得不偿失了。

105288017

7. 充当OBD-II,对汽车进行诊断

“OBD-II”是第二代车载诊断系统的英文缩写,它被用来监测车辆状况以及诊断可能出现的故障。借助转接器和专门的应用,智能手机也能作为OBD-II实时汇报汽车数据。

105288019

8. 连接U盘或鼠标

安卓已经有了USB即插即用功能,我们可以让大多数常见的USB设备连接至比较新的安卓智能手机和平板电脑,比如用U盘传输文件或是用USB鼠标导航用户界面。虽然一些新推出的U盘同时具备微型和全尺寸USB接口,但是大多数时候你恐怕得借助USB连接线。

105288020

9. 用摄像头测量距离

智能手机测距应用在精确度方面当然无法媲美专业仪器,但在仅需估测一下大致距离时也够用了。它们采用三角学原理计算用户与某一可见物体之间的大致距离,而用户需要做的事情是输入自己握持智能手机的位置高度并将十字准星瞄准物体底部。

105288022

10. 测量海拔高度和气压

智能手机可以通过GPS提供比较可靠的海拔高度数据,而一些比较新的智能手机还能利用内置的气压计监测气压变化和辅助GPS定位。

105288027

你可能不知道 智能手机还有这10个神奇功能,首发于 极客范 - GeekFan.net


四个领域内人工智能的崛起

$
0
0

Illustration: Getty

前几天,有消息称人工智能软件Eugene Goostman 通过了图灵测试,有评委真把它当成了一个13岁的小孩。虽然有人质疑测试的合理性,但这毕竟提醒我们计算机在这数十年里已经有了长足的进步。计算机以它们自己的方式做着一些智能的事,以下4个领域就是计算机正在崛起的地方。

信息检索

计算机可算是最好的图书管理员,每次你用谷歌搜索时,它都会检索约500亿网页。谷歌搜索十分强大,很多人都不会点击第二页的内容。

它的未来会怎么样?理解人类语言可能是最困难的事之一,数十年来,计算机都无法弄清人类语言文字的涵义。它们也无法明白为什么同一个词在不同的语境下会有完全不同的意义。斯坦福大学的生物医药信息研究员Russ Altman一直试图解决这一问题。自2000年起,他和同事就在教机器如何从医学研究报道中抽取有用信息。他们开发的 程序可以理解一些从句,也能根据上下文了解单词的含义,还知道一些同义词和反义词。

机器人

目前机器人已经受控制的条件下进行一些自动化操作,比如汽车制造。不过让它们像人类一样做出复杂的行为仍旧十分困难。尽管如此,一些前沿机器人的表现还是令人惊叹,它们可以解放人类劳动力,从事一些更具创造性的工作。亚马逊的机器人大军就能林立的货架中取出物品交给人类。

研究人员正在训练机器人读取人类行为的信息,从而能在更复杂的项目上与人类合作。人类和机器可以各发挥所长,人类更灵巧,而机器人的动作更精确。卡内基梅隆大学的专家David Bourne制作了一款机器人手臂,可以帮助汽车焊接。在测试中,机器人会告诉人类将各部件放在哪里,然后时行精确的焊接,对更复杂的任务,它会交给人类伙伴。

机器学习

机器学习是人工智能的一个分支,用试错的方法解决复杂问题,如通过数百万次的迭代来帮助银行评估信用风险。

目前机器学习服务只能由一些科技巨头通过云服务提供,不过未来智能手机也能成为一个端口。美国高通公司的研究员Tony Lewis表示,他们正在研究的项目可以通过强化学习教会机器人做一些事情。到时候,你不需要自己设置铃声或提醒之类的东西,只需要向手机做出积极或消极的反馈,它就会了解你的生活习惯。

更好的大脑

在识别语音、运动和图像上,机器人还有一大段路要走,Siri总会犯错,谷歌甚至需要1.6万个处理器才能训练计算机识别出 视频中的猫(准确率还算理想)。这是因为语音和形象不能还原到二进制的数字。

不过新的处理器可以模拟人类神经网的活动方式,以并行的方式处理信息流,它们被称为神经形态计算(neuromorphic computing)。最终的目标是设计出只需要现代计算机一部分计算能力的设备,就可以读取复杂的信息。这意味着下一代Siri和小冰可以实现真正的调情了。

via wired

相关

机器人会抢走我们的工作吗?

文章内容来自网络投稿,雷锋网登载此文为出于传递更多信息目的,作者观点不代表雷锋网
责任编辑: 张 驰

您可能也喜欢:

【硬了】人工智能

Skymind:让人工智能触手可得

TED设奖奖励第一个能自主演讲的人工智能

备受科技巨头青睐的人工智能创业公司

人工智能要革谁的命?
无觅

(转)使用ZooKeeper实现的两个实例

$
0
0

        我们来看看,利用ZK实现分布式锁和实现实时更新server列表的功能的例子,转自:

                     http://coolxing.iteye.com/blog/1871630

                     http://coolxing.iteye.com/blog/1871520

**************************************以下为转载********************************

分布式锁:

场景描述

     在分布式应用, 往往存在多个进程提供同一服务. 这些进程有可能在相同的机器上, 也有可能分布在不同的机器上. 如果这些进程共享了一些资源, 可能就需要分布式锁来锁定对这些资源的访问.
本文将介绍如何利用zookeeper实现分布式锁.

思路

    进程需要访问共享数据时, 就在"/locks"节点下创建一个sequence类型的子节点, 称为thisPath. 当thisPath在所有子节点中最小时, 说明该进程获得了锁. 进程获得锁之后, 就可以访问共享资源了. 访问完成后, 需要将thisPath删除. 锁由新的最小的子节点获得.
有了清晰的思路之后, 还需要补充一些细节. 进程如何知道thisPath是所有子节点中最小的呢? 可以在创建的时候, 通过getChildren方法获取子节点列表, 然后在列表中找到排名比thisPath前1位的节点, 称为waitPath, 然后在waitPath上注册监听, 当waitPath被删除后, 进程获得通知, 此时说明该进程获得了锁.

实现

以一个DistributedClient对象模拟一个进程的形式, 演示zookeeper分布式锁的实现.

 
  1. public class DistributedClient {  
  2.     // 超时时间  
  3.     private static final int SESSION_TIMEOUT = 5000;  
  4.     // zookeeper server列表  
  5.     private String hosts = "localhost:4180,localhost:4181,localhost:4182";  
  6.     private String groupNode = "locks";  
  7.     private String subNode = "sub";  
  8.   
  9.     private ZooKeeper zk;  
  10.     // 当前client创建的子节点  
  11.     private String thisPath;  
  12.     // 当前client等待的子节点  
  13.     private String waitPath;  
  14.   
  15.     private CountDownLatch latch = new CountDownLatch(1);  
  16.   
  17.     /** 
  18.      * 连接zookeeper 
  19.      */  
  20.     public void connectZookeeper() throws Exception {  
  21.         zk = new ZooKeeper(hosts, SESSION_TIMEOUT, new Watcher() {  
  22.             public void process(WatchedEvent event) {  
  23.                 try {  
  24.                     // 连接建立时, 打开latch, 唤醒wait在该latch上的线程  
  25.                     if (event.getState() == KeeperState.SyncConnected) {  
  26.                         latch.countDown();  
  27.                     }  
  28.   
  29.                     // 发生了waitPath的删除事件  
  30.                     if (event.getType() == EventType.NodeDeleted && event.getPath().equals(waitPath)) {  
  31.                         doSomething();  
  32.                     }  
  33.                 } catch (Exception e) {  
  34.                     e.printStackTrace();  
  35.                 }  
  36.             }  
  37.         });  
  38.   
  39.         // 等待连接建立  
  40.         latch.await();  
  41.   
  42.         // 创建子节点  
  43.         thisPath = zk.create("/" + groupNode + "/" + subNode, null, Ids.OPEN_ACL_UNSAFE,  
  44.                 CreateMode.EPHEMERAL_SEQUENTIAL);  
  45.   
  46.         // wait一小会, 让结果更清晰一些  
  47.         Thread.sleep(10);  
  48.   
  49.         // 注意, 没有必要监听"/locks"的子节点的变化情况  
  50.         List<String> childrenNodes = zk.getChildren("/" + groupNode, false);  
  51.   
  52.         // 列表中只有一个子节点, 那肯定就是thisPath, 说明client获得锁  
  53.         if (childrenNodes.size() == 1) {  
  54.             doSomething();  
  55.         } else {  
  56.             String thisNode = thisPath.substring(("/" + groupNode + "/").length());  
  57.             // 排序  
  58.             Collections.sort(childrenNodes);  
  59.             int index = childrenNodes.indexOf(thisNode);  
  60.             if (index == -1) {  
  61.                 // never happened  
  62.             } else if (index == 0) {  
  63.                 // inddx == 0, 说明thisNode在列表中最小, 当前client获得锁  
  64.                 doSomething();  
  65.             } else {  
  66.                 // 获得排名比thisPath前1位的节点  
  67.                 this.waitPath = "/" + groupNode + "/" + childrenNodes.get(index - 1);  
  68.                 // 在waitPath上注册监听器, 当waitPath被删除时, zookeeper会回调监听器的process方法  
  69.                 zk.getData(waitPath, true, new Stat());  
  70.             }  
  71.         }  
  72.     }  
  73.   
  74.     private void doSomething() throws Exception {  
  75.         try {  
  76.             System.out.println("gain lock: " + thisPath);  
  77.             Thread.sleep(2000);  
  78.             // do something  
  79.         } finally {  
  80.             System.out.println("finished: " + thisPath);  
  81.             // 将thisPath删除, 监听thisPath的client将获得通知  
  82.             // 相当于释放锁  
  83.             zk.delete(this.thisPath, -1);  
  84.         }  
  85.     }  
  86.   
  87.     public static void main(String[] args) throws Exception {  
  88.         for (int i = 0; i < 10; i++) {  
  89.             new Thread() {  
  90.                 public void run() {  
  91.                     try {  
  92.                         DistributedClient dl = new DistributedClient();  
  93.                         dl.connectZookeeper();  
  94.                     } catch (Exception e) {  
  95.                         e.printStackTrace();  
  96.                     }  
  97.                 }  
  98.             }.start();  
  99.         }  
  100.   
  101.         Thread.sleep(Long.MAX_VALUE);  
  102.     }  
  103. }   

思考

       思维缜密的朋友可能会想到, 上述的方案并不安全. 假设某个client在获得锁之前挂掉了, 由于client创建的节点是ephemeral类型的, 因此这个节点也会被删除, 从而导致排在这个client之后的client提前获得了锁. 此时会存在多个client同时访问共享资源.

对上面的解释:

    现在有subs5 sub6  subs7  subs8几个子节点,当前subs5正获得锁,如果subs6对应的client6挂掉,则subs6被删除--出发了client7那边的监听,导致client7也拿到了锁,导致5和7的客户端同时得到锁。
   如何解决这个问题呢? 可以在接到waitPath的删除通知的时候, 进行一次确认, 确认当前的thisPath是否真的是列表中最小的节点.

 
  1. // 发生了waitPath的删除事件  
  2. if (event.getType() == EventType.NodeDeleted && event.getPath().equals(waitPath)) {  
  3.     // 确认thisPath是否真的是列表中的最小节点  
  4.     List<String> childrenNodes = zk.getChildren("/" + groupNode, false);  
  5.     String thisNode = thisPath.substring(("/" + groupNode + "/").length());  
  6.     // 排序  
  7.     Collections.sort(childrenNodes);  
  8.     int index = childrenNodes.indexOf(thisNode);  
  9.     if (index == 0) {  
  10.         // 确实是最小节点  
  11.         doSomething();  
  12.     } else {  
  13.         // 说明waitPath是由于出现异常而挂掉的  
  14.         // 更新waitPath  
  15.         waitPath = "/" + groupNode + "/" + childrenNodes.get(index - 1);  
  16.         // 重新注册监听, 并判断此时waitPath是否已删除  
  17.         if (zk.exists(waitPath, true) == null) {  
  18.             doSomething();  
  19.         }  
  20.     }  
  21. }  

    另外, 由于thisPath和waitPath这2个成员变量会在多个线程中访问, 最好将他们声明为volatile, 以防止出现线程可见性问题.

另一种思路

   下面介绍一种更简单, 但是不怎么推荐的解决方案.
     每个client在getChildren的时候, 注册监听子节点的变化. 当子节点的变化通知到来时, 再一次通过getChildren获取子节点列表, 判断thisPath是否是列表中的最小节点, 如果是, 则执行资源访问逻辑.

 
  1. public class DistributedClient2 {  
  2.     // 超时时间  
  3.     private static final int SESSION_TIMEOUT = 5000;  
  4.     // zookeeper server列表  
  5.     private String hosts = "localhost:4180,localhost:4181,localhost:4182";  
  6.     private String groupNode = "locks";  
  7.     private String subNode = "sub";  
  8.   
  9.     private ZooKeeper zk;  
  10.     // 当前client创建的子节点  
  11.     private volatile String thisPath;  
  12.   
  13.     private CountDownLatch latch = new CountDownLatch(1);  
  14.   
  15.     /** 
  16.      * 连接zookeeper 
  17.      */  
  18.     public void connectZookeeper() throws Exception {  
  19.         zk = new ZooKeeper(hosts, SESSION_TIMEOUT, new Watcher() {  
  20.             public void process(WatchedEvent event) {  
  21.                 try {  
  22.                     // 连接建立时, 打开latch, 唤醒wait在该latch上的线程  
  23.                     if (event.getState() == KeeperState.SyncConnected) {  
  24.                         latch.countDown();  
  25.                     }  
  26.   
  27.                     // 子节点发生变化  
  28.                     if (event.getType() == EventType.NodeChildrenChanged && event.getPath().equals("/" + groupNode)) {  
  29.                         // thisPath是否是列表中的最小节点  
  30.                         List<String> childrenNodes = zk.getChildren("/" + groupNode, true);  
  31.                         String thisNode = thisPath.substring(("/" + groupNode + "/").length());  
  32.                         // 排序  
  33.                         Collections.sort(childrenNodes);  
  34.                         if (childrenNodes.indexOf(thisNode) == 0) {  
  35.                             doSomething();  
  36.                         }  
  37.                     }  
  38.                 } catch (Exception e) {  
  39.                     e.printStackTrace();  
  40.                 }  
  41.             }  
  42.         });  
  43.   
  44.         // 等待连接建立  
  45.         latch.await();  
  46.   
  47.         // 创建子节点  
  48.         thisPath = zk.create("/" + groupNode + "/" + subNode, null, Ids.OPEN_ACL_UNSAFE,  
  49.                 CreateMode.EPHEMERAL_SEQUENTIAL);  
  50.   
  51.         // wait一小会, 让结果更清晰一些  
  52.         Thread.sleep(10);  
  53.   
  54.         // 监听子节点的变化  
  55.         List<String> childrenNodes = zk.getChildren("/" + groupNode, true);  
  56.   
  57.         // 列表中只有一个子节点, 那肯定就是thisPath, 说明client获得锁  
  58.         if (childrenNodes.size() == 1) {  
  59.             doSomething();  
  60.         }  
  61.     }  
  62.   
  63.     /** 
  64.      * 共享资源的访问逻辑写在这个方法中 
  65.      */  
  66.     private void doSomething() throws Exception {  
  67.         try {  
  68.             System.out.println("gain lock: " + thisPath);  
  69.             Thread.sleep(2000);  
  70.             // do something  
  71.         } finally {  
  72.             System.out.println("finished: " + thisPath);  
  73.             // 将thisPath删除, 监听thisPath的client将获得通知  
  74.             // 相当于释放锁  
  75.             zk.delete(this.thisPath, -1);  
  76.         }  
  77.     }  
  78.   
  79.     public static void main(String[] args) throws Exception {  
  80.         for (int i = 0; i < 10; i++) {  
  81.             new Thread() {  
  82.                 public void run() {  
  83.                     try {  
  84.                         DistributedClient2 dl = new DistributedClient2();  
  85.                         dl.connectZookeeper();  
  86.                     } catch (Exception e) {  
  87.                         e.printStackTrace();  
  88.                     }  
  89.                 }  
  90.             }.start();  
  91.         }  
  92.   
  93.         Thread.sleep(Long.MAX_VALUE);  
  94.     }  
  95. }  

      为什么不推荐这个方案呢? 是因为每次子节点的增加和删除都要广播给所有client, client数量不多时还看不出问题. 如果存在很多client, 那么就可能导致广播风暴--过多的广播通知阻塞了网络. 使用第一个方案, 会使得通知的数量大大下降. 当然第一个方案更复杂一些, 复杂的方案同时也意味着更容易引进bug.

 

***************************************************************************************************

 

实时更新server列表:

    通过之前的3篇博文, 讲述了ZooKeeper的基础知识点. 可以看出, ZooKeeper提供的核心功能是非常简单, 且易于学习的. 可能会给人留下ZooKeeper并不强大的印象, 事实并非如此, 基于ZooKeeper的核心功能, 我们可以扩展出很多非常有意思的应用. 接下来的几篇博文, 将陆续介绍ZooKeeper的典型应用场景.

场景描述

    在分布式应用中, 我们经常同时启动多个server, 调用方(client)选择其中之一发起请求.
    分布式应用必须考虑高可用性和可扩展性: server的应用进程可能会崩溃, 或者server本身也可能会宕机. 当server不够时, 也有可能增加server的数量. 总而言之, server列表并非一成不变, 而是一直处于动态的增减中.
    那么client如何才能实时的更新server列表呢? 解决的方案很多, 本文将讲述利用ZooKeeper的解决方案.

思路

    启动server时, 在zookeeper的某个znode(假设为/sgroup)下创建一个子节点. 所创建的子节点的类型应该为ephemeral, 这样一来, 如果server进程崩溃, 或者server宕机, 与zookeeper连接的session就结束了, 那么其所创建的子节点会被zookeeper自动删除. 当崩溃的server恢复后, 或者新增server时, 同样需要在/sgroup节点下创建新的子节点.
    对于client, 只需注册/sgroup子节点的监听, 当/sgroup下的子节点增加或减少时, zookeeper会通知client, 此时client更新server列表.

实现AppServer

    AppServer的逻辑非常简单, 只须在启动时, 在zookeeper的"/sgroup"节点下新增一个子节点即可.

 
  1. public class AppServer {  
  2.     private String groupNode = "sgroup";  
  3.     private String subNode = "sub";  
  4.   
  5.     /** 
  6.      * 连接zookeeper 
  7.      * @param address server的地址 
  8.      */  
  9.     public void connectZookeeper(String address) throws Exception {  
  10.         ZooKeeper zk = new ZooKeeper("localhost:4180,localhost:4181,localhost:4182", 5000, new Watcher() {  
  11.             public void process(WatchedEvent event) {  
  12.                 // 不做处理  
  13.             }  
  14.         });  
  15.         // 在"/sgroup"下创建子节点  
  16.         // 子节点的类型设置为EPHEMERAL_SEQUENTIAL, 表明这是一个临时节点, 且在子节点的名称后面加上一串数字后缀  
  17.         // 将server的地址数据关联到新创建的子节点上  
  18.         String createdPath = zk.create("/" + groupNode + "/" + subNode, address.getBytes("utf-8"),   
  19.             Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);  
  20.         System.out.println("create: " + createdPath);  
  21.     }  
  22.       
  23.     /** 
  24.      * server的工作逻辑写在这个方法中 
  25.      * 此处不做任何处理, 只让server sleep 
  26.      */  
  27.     public void handle() throws InterruptedException {  
  28.         Thread.sleep(Long.MAX_VALUE);  
  29.     }  
  30.       
  31.     public static void main(String[] args) throws Exception {  
  32.         // 在参数中指定server的地址  
  33.         if (args.length == 0) {  
  34.             System.err.println("The first argument must be server address");  
  35.             System.exit(1);  
  36.         }  
  37.           
  38.         AppServer as = new AppServer();  
  39.         as.connectZookeeper(args[0]);  
  40.           
  41.         as.handle();  
  42.     }  
  43. }  

将其打成appserver.jar后待用, 生成jar时别忘了指定入口函数. 具体的教程请自行搜索.

 

实现AppClient

    AppClient的逻辑比AppServer稍微复杂一些, 需要监听"/sgroup"下子节点的变化事件, 当事件发生时, 需要更新server列表.
    注册监听"/sgroup"下子节点的变化事件, 可在getChildren方法中完成. 当zookeeper回调监听器的process方法时, 判断该事件是否是"/sgroup"下子节点的变化事件, 如果是, 则调用更新逻辑, 并再次注册该事件的监听.

 
  1. public class AppClient {  
  2.     private String groupNode = "sgroup";  
  3.     private ZooKeeper zk;  
  4.     private Stat stat = new Stat();  
  5.     private volatile List<String> serverList;  
  6.   
  7.     /** 
  8.      * 连接zookeeper 
  9.      */  
  10.     public void connectZookeeper() throws Exception {  
  11.         zk = new ZooKeeper("localhost:4180,localhost:4181,localhost:4182", 5000, new Watcher() {  
  12.             public void process(WatchedEvent event) {  
  13.                 // 如果发生了"/sgroup"节点下的子节点变化事件, 更新server列表, 并重新注册监听  
  14.                 if (event.getType() == EventType.NodeChildrenChanged   
  15.                     && ("/" + groupNode).equals(event.getPath())) {  
  16.                     try {  
  17.                         updateServerList();  
  18.                     } catch (Exception e) {  
  19.                         e.printStackTrace();  
  20.                     }  
  21.                 }  
  22.             }  
  23.         });  
  24.   
  25.         updateServerList();  
  26.     }  
  27.   
  28.     /** 
  29.      * 更新server列表 
  30.      */  
  31.     private void updateServerList() throws Exception {  
  32.         List<String> newServerList = new ArrayList<String>();  
  33.   
  34.         // 获取并监听groupNode的子节点变化  
  35.         // watch参数为true, 表示监听子节点变化事件.   
  36.         // 每次都需要重新注册监听, 因为一次注册, 只能监听一次事件, 如果还想继续保持监听, 必须重新注册  
  37.         List<String> subList = zk.getChildren("/" + groupNode, true);  
  38.         for (String subNode : subList) {  
  39.             // 获取每个子节点下关联的server地址  
  40.             byte[] data = zk.getData("/" + groupNode + "/" + subNode, false, stat);  
  41.             newServerList.add(new String(data, "utf-8"));  
  42.         }  
  43.   
  44.         // 替换server列表  
  45.         serverList = newServerList;  
  46.   
  47.         System.out.println("server list updated: " + serverList);  
  48.     }  
  49.   
  50.     /** 
  51.      * client的工作逻辑写在这个方法中 
  52.      * 此处不做任何处理, 只让client sleep 
  53.      */  
  54.     public void handle() throws InterruptedException {  
  55.         Thread.sleep(Long.MAX_VALUE);  
  56.     }  
  57.   
  58.     public static void main(String[] args) throws Exception {  
  59.         AppClient ac = new AppClient();  
  60.         ac.connectZookeeper();  
  61.   
  62.         ac.handle();  
  63.     }  
  64. }  

将其打包成appclient.jar后待用, 别忘了指定入口函数.

 

运行

    在运行jar包之前, 需要确认zookeeper中是否已经存在"/sgroup"节点了, 没有不存在, 则创建该节点. 如果存在, 最好先将其删除, 然后再重新创建. ZooKeeper的相关命令可参考我的另一篇博文.
运行appclient.jar:  java -jar appclient.jar 开启多个命令行窗口, 每个窗口运行appserver.jar进程: java -jar appserver.jar server0000. "server0000"表示server的地址, 别忘了给每个server设定一个不同的地址. 观察appclient的输出.
依次结束appserver的进程, 观察appclient的输出.
appclient的输出类似于:

 
  1. server list updated: []  
  2. server list updated: [server0000]  
  3. server list updated: [server0000, server0001]  
  4. server list updated: [server0000, server0001, server0002]  
  5. server list updated: [server0000, server0001, server0002, server0003]  
  6. server list updated: [server0000, server0001, server0002]  
  7. server list updated: [server0000, server0001]  
  8. server list updated: [server0000]  
  9. server list updated: []  


已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



智能电表可能曝光你在家的活动

$
0
0
智能电表可能太智能了,它的数据能揭示你在家中的活动。上个月,世界最大广告代理商 WPP的一个部门宣布与英国软件公司Onzo合作,研究方法收集智能电表数据。Onzo CEO Joel Hagan说,智能电表数据具有“打开家门”的潜力。但打开用户的前门只是一个开始。智能电表数不仅仅能揭示你经常使用哪些电器,甚至可能会曝光你喜欢观看哪些电视节目。德国应用科技大学的研究人员测量了电视屏幕上展示特定节目的耗电量,发现每个节目都有一个独一无二的电功率签名,他们可以将节目的签名与智能电表的电量数据匹配起来,从而暴露某个家庭正在观看什么节目。






关于推荐个人观点

$
0
0


回想起来,我也做推荐了3年多了,最近公司做了调整招聘了很多算法工程师,以为需要多么高大上的算法才能搭建起来的,从实践中走

过来,我只想说【不是这样的】

第一次接触推荐系统是在四年前入职的时候,那时候,机器学习和大数据都是没有的概念,什么大数据处理开源软件根本不存在,我们

用多台计算机web程序记录用户行为,用.net的wcf框架实现了和现在mapreduce一样的功能,分析了用户的日志,一台分发任务,其余计

算计算完回传到分发任务的这台计算机,这台计算机合并各台回传数据批量入库,到现在程序还在使用中。而现在就是每天晚上数据部

会同步到他们的数据仓库中。也许在现在很多人眼里看来很可笑吧!

当然推荐的数据量也咩有想想的那么多用mysql和mongodb完全支持,当然不是说没有必要搭建hadoop。

推荐不是仅仅靠算法,还要结合实际的场景,不同的产品进行推荐,来调整算法。要有各种各样的过滤引擎支持对数据的过滤处理。

推荐算法还要分品类进行调整,不是一个算法适用于所有品类,图书和3C完全不同的概念。

推荐是在实践当中不断积累和完善的。

我也看了那些认为算法很牛逼人物们的博客文章,比如用文本写了几行测试数据自认为会了ItemCF的算法,可是你有没有考虑过,如果

商品过亿,评论过亿,订单过亿的时候你的这个例子怎么搬到线上去运行呢?难道你要一下子塞到机器内存,我想机器会疯掉的吧!

当然理论大家还是要学的,呵呵!



写以上应为我看了一篇文章,一遍一遍的读我读了好几遍,转载给大家:

http://www.aszxqw.com/work/2014/06/01/tuijian-xitong-de-nadianshi.html



回想起来,我也算是国内接触推荐系统较早的人之一了,最近和人聊天,觉得不少人对推荐系统有所误解,以为需要多么高大上的算法

才能搭建起来的,我只想说我经常说的那句话【不是这样的】,所以有了这篇文章。

第一次接触【推荐系统】是在两年前在某高校的互联网信息处理实验室的时候,那时候,【机器学习】和【大数据】都是新概念,但是

差不多半年后,【大数据】的概念就开始风靡全球了,到现在已经被爆炒得面目全非。

那年还因此买了一本项亮的书《推荐系统实践》,那本书和现在的很多热门书籍一样,都是跟着概念热起来的。 虽然有一些作者自己的

实战经验在里面,但是总体上来说并没有太多值得重复翻开的地方。

几乎所有宣扬【推荐系统】的人,都要拿【啤酒和尿布】,【亚马逊推荐占营收20%】之类的经典例子来说力证推荐系统的牛逼之处。到

处宣扬【推荐系统】插上【机器学习】等算法的翅膀,就能让电子商务变得精准无比,能智能的猜出用户想买的东西。

殊不知,其实这两个例子和所谓的【算法】其实关系不大。

1. 啤酒和尿布

首先是【啤酒和尿布】,超市的人员发现买啤酒的男人容易顺手买尿布。这其实是一种数据分析,是根据数据统计加上人工分析得出,

是一种以经验来改善销售的行为。和【机器学习】【数据挖掘】等算法的关系不大。 刚接触【推荐系统】的时候,【协同过滤算法】大

热, 我也曾经迷恋得研究过该算法,以为发现了什么宝贝一样。但是实际上,在工程中【协同过滤】出来的效果往往惨不忍睹,所谓的

【算法工程师】每天能做的就是在那调整【协同过滤】算法的相关参数,然后看看第二天的点击率有没有上升。然后调整到最后你会发

现,牛逼哄哄的【协同过滤】其实还不如简简单单的【看了又看】效果来的好,虽然协同过滤算法本质上也是一种【看了又看】的思想

。但是所谓的【算法工程师】不会因此停下他们探索的脚步,他们会继续去寻找更高大上的算法来实验,才能显得他们有在为自己的工

资付出每天的辛勤劳动。

2. 亚马逊的推荐系统

亚马逊的推荐系统占了营收比,我记得是20%,不知道现在上升了还是下降了。这个说辞会让很多人误以为只要你搞好了推荐系统,你的

营收就能上升20%以上一样。其实不然,对于亚马逊来说,为什么推荐能起到这么高的销量,一个很重要的原因在于,【亚马逊的首页点

击率高的部分位置划分给了推荐系统的】,从广告学上讲,广告位置的好坏极大的决定了广告的销量。这个很容易理解

当然不可否定的是亚马逊的推荐系统应该是很牛逼的,但是这并不说明他们采用的【推荐算法】非常牛逼。推荐系统我认为其实和搜索

系统并无太大差异,我一直认为推荐系统其实只是一个个性化的搜索引擎。之前在【秘密】上很火的有个爆料是:“360搜索的Rank刚开

始就是用【机器学习】的算法去做,屎一样的效果,是我把百度的基于规则的算法偷过去之后才变好的。” ,这个爆料出来不少人讽刺

【基于规则】,觉得这是在黑百度的算法。 其实不是这样的,记得当时阿里搜索挖了一个谷歌搜索的员工,该人在阿里分享的时候就说

过:【谷歌的搜索效果比别人好的原因就是规则库牛逼,关于算法使用的都是成熟的人尽皆知的算法,并没什么新奇酷的算法】。 可能

也是这个原因,谷歌研究院的科学家几乎全是【工程师背景】出身的。还记得上次【CCF推荐系统前言讲座】,刚开始叫了几个学院派的

讲师在那大讲特讲各种酷炫掉渣天的算法,然后淘宝打大数据负责人车品觉 上台之后直接来了句【我们实验出各种算法效果不太好,还

不如最基本的 关联规则 效果来的好】直接把前面的学院派专家们打脸打得都肿了。
我心目中的推荐系统

不管是电商,或者是新闻,都有【个性化推荐】和【热门推荐】的取舍。一个商品热门或者点击量高是有其原因的。所以将热门的东西

推荐给用户是非常合情合理的,因为既然热门,也侧面说明了很大概率上该用户也会喜欢该商品。而【个性化推荐】本质上是为了解决

【长尾】问题,把那些不热门的东西,但是很可能符合某特定用户品味的商品【挖掘】出来,推荐给特定的用户群。

首先,在推荐中,醒目的推荐位应该是【热门推荐】或者【人工推荐】,【人工推荐】是指比如在体育新闻中,巴萨夺冠之类的大新闻

是直接让编辑来【人工推荐】即可,就是此新闻一出,马上登上头条,而不是在那磨磨唧唧的计算特征值,计算是相似度,计算是否符

合用户兴趣。 对于推荐中的【冷启动】,最理想的推荐就是【相关推荐】。说到这里,整个推荐系统的 80% 已经搭建完毕,【热门推

荐+人工推荐+相关推荐】,这三者都是【个性化】都没什么关系,也算法关系也不大,但是这三者效果的好坏就决定了整个系统推荐效

果好坏的 80% 。好多人连最基本的这三者都没有做好,就开始想一步登天,很可惜,这样的捷径是不存在的。 接下来是 20% 的【个性

化】的做法,如上所说,个性化是为了解决【长尾】问题,正是因为长尾占商品的 20% ,所以在此我任务【个性化】其实也只有 20%

。要解决个性化,首先就是要对用户分析,最成熟的办法就是对用户打标签(是否让你想起来社交网络为什么经常让你选用合适的标签

描述自己,没错,就是为了分析你)。

其实,给用户打标签,逼格更高的说法叫【用户特征提取】或者【用户行为分析】。说到这两个词,那些所谓的【算法工程师】可能就

会开始扯什么高大上的算法,机器学习,自然语言处理,数据挖掘等各种算法。其实在我看来,算法很大情况根本派不上用场,我认为

这方面的关键在于【数据统计 + 人工分析】。将用户的浏览记录等记录下来,统计他最常点击的东西,最常去的频道,然后给他打上这

些频道或者商品的标签。或者收集更详细的信息,比如年龄,打上【青少年,男人,女人,老人】等标签,根据这些标签进行推荐。比

如当推荐护肤的商品时,就可以偏向于女人,推荐运动产品时,就可以偏向于男人和青少年,推荐保健品时,就可以偏向于老年人。所

以,光看年龄这个标签的维度,就可以做很多文章。所以标签库的设计和积累,是非常广泛和重要的,而这方面需要大量依赖于【人工

分析】,而不是看论文调算法能做到的。 就好比现在的中文分词,拼到最后大家都在比词库的积累,谁的词库好,谁的效果就好,【搜

狗】的【拼音输入法】效果好也是因为词库比别人好。

最后就是根据标签的定向推荐,这个推荐概率是有【权重设置】在里面,就比如刚才对年龄这个维度的权重,是需要给予对应的权重值

,如何给定呢?其实就是【拍脑袋】,当然,如果有某些公司已经得出经验值了直接可以拿来用就会更好。但是在拍完脑袋之后需要做

的就是观察点击率变化,查Bad Case,然后再对权重进行调整,也就是根据评测和反馈来调整,没有【评测和反馈】,整个系统等于是

一个黑盒,谈何优化?在我看来,【推荐系统】本质上首先是一个系统,需要不断的对各种效果进行【评测】,查各种【Bad Case】,

而这些都不是看论文可以学到的东西。
总结

    实力派的【算法工程师】往往都是ABC[always be coding],这样的算法工程师才能根据实际问题建立模型或者建立规则库,是真正

能解决问题的人。往往是一些有研究背景,经验丰富的研究员,更加重视工程,因为工程架构上一些恰当合理的设计,效果往往就能远

远高过于模型算法优化。
    学院派的【算法工程师】往往是为了算法而算法,而不是为了解决推荐系统的问题去找最适合算法。这也是为什么大公司经常招了

一些博士毕业的算法工程师后,不是研究算法而是让他们整天在那看数据报表?【因为发现算法没啥好研究,而且他们的工程能力又太

蹩脚,只能让他们在那看看报表找找规律了。】
    【几乎所有所谓的智能推荐算法都是花拳绣腿】
    当一个做推荐系统的部门开始重视【数据清理,数据标柱,效果评测,数据统计,数据分析】这些所谓的脏活累活,这样的推荐系

统才会有救。




已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



MariaDB Galera Cluster 10.0.11 发布

$
0
0

MariaDB Galera Cluster 是一个用于同步 MariaDB数据库的多 master 集群的工具。在数据方面完全兼容 MariaDB 和 MySQL。

MariaDB Galera Cluster 10.0.11 发布,这是一个 Beta 版本,相关链接:

- Release Notes:
   https://mariadb.com/kb/en/mariadb-galera-cluster-10011-release-notes

 - Changelog:
   https://mariadb.com/kb/en/mariadb-galera-cluster-10011-changelog

 - Downloads: https://downloads.mariadb.org/mariadb-galera/10.0.11

 About MariaDB Galera Cluster:
  - https://mariadb.com/kb/en/what-is-mariadb-galera-cluster/

 APT and YUM Repository Configuration Generator:
  - https://downloads.mariadb.org/mariadb/repositories/

Viewing all 15843 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>