2015年5月31日星期日

Kafka实战-简单示例 - 哥不是小萝莉

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
Kafka实战-简单示例 - 哥不是小萝莉  阅读原文»

1.概述

  上一篇博客《Kafka实战-Kafka Cluster》中,为大家介绍了Kafka集群的安装部署,以及对Kafka集群Producer/Consumer、HA等做了相关测试,今天我们来开发一个Kafka示例,练习如何在Kafka中进行编程,下面是今天的分享的目录结构:

  • 开发环境
  • ConfigureAPI
  • Consumer
  • Producer
  • 截图预览

  下面开始今天的内容分享。

2.开发环境

  在开发Kafka相关应用之前,我们得将Kafka得开发环境搭建完成,这里我所使用得开发环境如下所示:

基础软件工具名称
IDEJBoss Studio 8
JDK1.7

  关于基础软件的下载及相关配置,大家可参考我写的《高可用Hadoop平台-启航》一文的相关赘述,这里就不多做介绍了。在安装好相关基础软件后,我们开始项目工程的创建,这里我们所使用的工程结构是Maven,关于Maven环境的相关配置信息,可参考我在《Hadoop2源码分析-准备篇》一文对Maven环境配置的赘述。

  在准备完成相关基础软件以及Maven环境后,我们大家创建的工程,在pom.xml文件中,添加Kafka的依赖包,添加代码如下所示:

<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka_2.11</artifactId>
<version>0.8.2.1</version>
</dependency>

  下面开始编写今天的代码示例。

3.ConfigureAPI

  首先是一个配置结构类文件,配置Kafka的相关参数,代码如下所示:

package cn.hadoop.hdfs.conf;

/**
* @Date Apr 28, 2015
*
* @Author dengjie
*
* @Note Set param path
*/
public class ConfigureAPI {

public interface KafkaProperties {
public final static String ZK = "10.211.55.15:2181,10.211.55.17:2181,10.211.55.18:2181";
public final static String GROUP_ID = "test_group1";
public final static String TOPIC = "test2";
public final static String BROKER_LIST = "10.211.55.15:9092,10.211.55.17:9092,10.211.55.18:9092";
public final static int BUFFER_SIZE = 64 * 1024;
public final static int TIMEOUT = 20000;
public final static int INTERVAL = 10000;
}

}

4.Consumer

  然后是一个消费程序,用于消费Kafka的消息,代码如下所示:

  • JConsumer

package cn.hadoop.hdfs.kafka;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import cn.hadoop.hdfs.conf.ConfigureAPI.KafkaProperties;
import kafka.consumer.Consumer;
import kafka.consumer.ConsumerConfig;
import kafka.consumer.ConsumerIterator;
import kafka.consumer.KafkaStream;
import kafka.javaapi.consumer.ConsumerConnector;

/**
* @Date May 22, 2015
*
* @Author dengjie
*
* @Note Kafka Consumer
*/
public class JConsumer extends Thread {

private ConsumerConnector consumer;
private String topic;
private final int SLEEP = 1000 * 3;

public JConsumer(String topic) {
consumer
= Consumer.createJavaConsumerConnector(this.consumerConfig());
this.topic = topic;
}

private ConsumerConfig consumerConfig() {
Properties props
= new Properties();
props.put(
"zookeeper.connect", KafkaProperties.ZK);
props.put(
"group.id", KafkaProperties.GROUP_ID);
props.put(
"zookeeper.session.timeout.ms", "40000");
props.put(
"zookeeper.sync.time.ms", "200");
props.put(
"auto.commit.interval.ms", "1000");
return new ConsumerConfig(props);
}

@Override
public void run() {
Map
<String, Integer> topicCountMap = new HashMap<String, Integer>();
topicCountMap.put(topic,
new Integer(1));
Map
<String, List<KafkaStream<byte[], byte[]>>> consumerMap = consumer.createMessageStreams(topicCountMap);
KafkaStream
<byte[], byte[]> stream = consumerMap.get(topic).get(0);
ConsumerIterator
<byte[], byte[]> it = stream.iterator();
while (it.hasNext()) {
S
用c#开发微信 (9) 微渠道 - 推广渠道管理系统 4 部署测试 (最终效果图) - 疯吻IT  阅读原文»

我们可以使用微信的"生成带参数二维码接口"和 "用户管理接口",来实现生成能标识不同推广渠道的二维码,记录分配给不同推广渠道二维码被扫描的信息。这样就可以统计和分析不同推广渠道的推广效果。

本文是微渠道的第四篇,主要介绍如下内容:

1. 部署

2. 测试

下面是详细的实现方法:

一、部署

1. Entity Framework 错误

如果出现下面的错误:

The EntityContainer name must be unique. An EntityContainer with the name 'xxxx' is already existed

这时只用把web.config打开, 修改res://* 为res://yourproject 即可,比如:

image

2. 部署地址一定要跟微信里设置的URL要一致

image

二、测试

1. 添加渠道类型:

点击渠道类型列表里的添加按钮添加渠道:

image

保存后,添加的渠道类型出现在渠道类型列表里:

image

点击 操作下面的 编辑 和 删除 分别可以修改和删除渠道类型

2. 添加渠道:

点击渠道列表里的添加按钮添加渠道:

image

保存后,添加的渠道出现在渠道列表里:

image

点击 操作下面的 编辑 和 删除 分别可以修改和删除渠道

3. 下载二维码:

点击渠道列表里的"下载二维码"将会下载二维码,并在单独一个页面显示一个二维码,扫描一下,这里分二种情况,一种是没关注的,先关注再保存扫描记录;另一种是关注了,直接扫描保存扫描记录。

image

4. 查看扫描记录:

点击渠道列表里的"查看扫描记录",会打开所有当前渠道的扫描记录:

image

5. 最后我们可以查看所有微信用户:

image

这个页面第一次打开时,会启动全局唯一的同步微信用户的线程,每60秒会同步一次微信的个人用户信息。

在一个微信公众号刚开始推广的时候,很难知道哪个推广渠道效果最好;通过这个微渠道系统,可以对推广渠道的数据进行统计、分析,总结,不断完善推广策略,最终达到预定的市场推广目标。

用c#开发微信 系列汇总


本文链接:用c#开发微信 (9) 微渠道 - 推广渠道管理系统 4 部署测试 (最终效果图),转载请注明。

阅读更多内容

2015年5月29日星期五

android 布局 使用 viewPager 时,如何解决 和 子页面 长按滑动 冲突问题 - 指尖下的幽灵

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
android 布局 使用 viewPager 时,如何解决 和 子页面 长按滑动 冲突问题 - 指尖下的幽灵  阅读原文»

使用 viewPager 时,如何解决 和 子页面 长按滑动 冲突问题。

我的问题原型:

这个问题,我相信遇到的人会比较少,我是在 一个 viewPager 中,其中 一个 fragment 中实现了长按滑动图片的功能,而发现它们两者的

onTouchEvent事件冲突。

尝试过的解决方法:

1-----

遇到这问题,首先是百度,百度到的方法有,自定义 viewPager,在里面重写 onTouchEvent 和 onInterceptTouchEvent,具体代码是下面,这种方法,我尝试

后发现,只能在第一次加载 viewPager的 页面达到 阻断的效果,我这里详细说下,在MainActivity 页面里面,我们初始化了 viewPager,然后我们要在 第二个页面的

fragment 中实现阻断,这时候,你可能会尝试 在 fragment 中new 一个 MainActivity 的对象,然后想方设法 获取它 里面的 viewPager,或者是 引入与 MainActivity

绑定好了的 xml文件,再 在 fragment 中 findViewById() 来获取次 viewPager。 然后使用 自定义 viewPager 里面的 函数。

很不幸,我上述谈到的方法,我都试过了, all failed。

1 package com.LGH.weixin;
2
3 /**
4 * Created by Administrator on 2015/5/30.
5 */
6 import android.content.Context;
7 import android.support.v4.view.ViewPager;
8 import android.util.AttributeSet;
9 import android.util.Log;
10 import android.view.MotionEvent;
11
12
13 public class myViewPager extends ViewPager {
14
15 private boolean enabled = true; // 默认是 可以侧滑的
16
17
18 public myViewPager(Context context, AttributeSet attrs) {
19 super(context, attrs);
20 }
21
22 public void setStopViewPagerSlip(boolean enabled){
23 this.enabled = enabled;
24 Log.i("--------------------","////"+this.enabled);
25 }
26 //触摸没有反应就可以了
27 @Override
28 public boolean onTouchEvent(MotionEvent event) {
29 if (this.enabled) {
30 return super.onTouchEvent(event);
31 }
32 return false;
33 }
34
35
36 @Override
37 public boolean onInterceptTouchEvent(MotionEvent event) {
38 if (this.enabled) {
39 return super.onInterceptTouchEvent(event);
40 }
41 return false;
42 }
43 }

2-----

第二种方法是我最后真正解决了的。刚开始的时候,使用有误,导致失败。

方法: view.requestDisallowInterceptTouchEvent(true); //传入参数是 true 即可

我第一次使用它失败的原因是:

在 我的 fragment中,由于 viewPager 它本是就是一个 view,所以 我使用 该方法的时候,就直接

viewPager .requestDisallowInterceptTouchEvent(true); 结果是失败的。 在子 view 中正确使用方法是 下面 ↓

解决方法:

view.requestDisallowInterceptTouchEvent(true);中使用的 view 要求是你当前 fragment 引入的xml 返回的 view,而且 改为:

view.getParent().requestDisallowInterceptTouchEvent(true);

此时方能真正解决! 下面 引入些必要的 代码。

1 View main = inflater.inflate(R.layout.apart_center,container,false);
1 main.getParent().requestDisallowInterceptTouchEvent(true);


本文链接:android 布局 使用 viewPager 时,如何解决 和 子页面 长按滑动 冲突问题,转载请注明。

如何修改文件中间的几个字节 - 薰衣草的旋律  阅读原文»

工作中碰到一个问题,如何只修改文件中间的几个字节,而其他的内容不变。这个问题看似简单,但是很多人估计都不知道怎么做。我开始seek到文件的特定的位置,然后写文件,但是使用的文件打开模式不对,文件不是被清空,就是被截断,达不到效果。

fopen的打开模式

在C语言中文件打开方式有这么几种:

  • r 以只读方式打开文件,只能读不能写,往文件中写是没有任何效果的
  • r+ 可以读,也可以写,文件打开的时候,指向文件开头,可以通过seek改变读写位置
  • w 这种方式打开的文件句柄,只能写,如果文件存在则将长度清零,否则新建文件,这种句柄通过seek之后,seek位置之前的文件数据全部变成0x00
  • w+ 同w选项,只不过多了一个可读功能
  • a 这种方式打开的文件,可以写,但是位置在文件末尾,即使往回seek也没有用,数据还是从文件末尾开始附加
  • a+ 同a选项,多了可读的功能

另外还有2个选项,可以与上面的6个选项复合使用,一个是t表示以文本的方式打开文件(默认是t),一个是b表示以二进制的方式打开文件,t和b是互斥的不能同时使用。当与b组合时,有这么几种方式:wb、ab、rb、wb+、ab+、rb+,而a,w,r这几个选项是不能组合使用的,其中a,w都表示写文件,只不过一个在文件尾,一个在文件开始处,r表示读文件。我试过将a,w,r几个两两组合使用,发现下面的现象:

  • wr 与w效果一样
  • rw与r效果一样
  • aw与a效果一样
  • wa 与w效果一样
  • ar与a效果一样
  • ra与r效果一样

可以看出来当a,w,r在一起组合使用的时候,其后面的选项实际上好像是被忽略了

问题的解决方法:rb+打开文件

所以解决文章开头提出来的问题,应该使用 rb+ 的方式打开文件,这种方式打开的文件,可读,可写,打开之后写指针在文件开始处,可以任意seek,而seek之后写的内容会覆盖被写的内容,其他没有写到的内容不会有改变。

测试程序

//程序测试结果在ubuntu linux下运行获得
#include <stdio.h>
#include <string.h>
int main()
{
//文件原始数据
//00 01 02 03 04 05 06 07 08 09

//下面每一个fopen前面注释中的数据是以该方式打开文件,写文件之后文件的内容

//00 00 00 00 CC DD
//FILE * file = fopen("./test.data","wb+");

//00 00 00 00 CC DD
//FILE * file = fopen("./test.data","wb");

//00 01 02 03 CC DD 06 07 08 09
FILE * file = fopen("./test.data","rb+"); //这种是正确的做法

//00 01 02 03 04 05 06 07 08 09
//FILE * file = fopen("./test.data","rb");

//00 01 02 03 04 05 06 07 08 09 CC DD
//FILE * file = fopen("./test.data","ab");

//00 01 02 03 04 05 06 07 08 09 CC DD
//FILE * file = fopen("./test.data","ab+");

//00 00 00 00 CC DD
//FILE * file = fopen("./test.data","wr");

//00 01 02 03 04 05 06 07 08 09
//FILE * file = fopen("./test.data","rw");

//00 01 02 03 04 05 06 07 08 09 CC DD
//FILE * file = fopen("./test.data","aw");

//00 00 00 00 CC DD
//FILE * file = fopen("./test.data","wa");

//00 01 02 03 04 05 06 07 08 09 CC DD
//FILE * file = fopen("./test.data","ar");

//00 01 02 03 04 05 06 07 08 09
//FILE * file = fopen("./test.data","ra");
if(file!=NULL)
{
char buffer[]={0xCC,0xDD};
fseek(file,4,SEEK_SET);
fwrite(buffer,1,sizeof(buffer),file);
fclose(file);
}
return 0;
}


本文链接:如何修改文件中间的几个字节,转载请注明。

阅读更多内容

2015年5月27日星期三

svn利用钩子脚本功能实现代码同步到web目录

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
svn利用钩子脚本功能实现代码同步到web目录  阅读原文»

svn利用钩子脚本功能实现代码同步到web目录

一、hook简单介绍

为了方便管理员控制提交的过程 ,Subversion 提供了 hook机制。当特定的 事件发生时,相应的 hook会被调用, hook其实就相当于特定事件的处理函数。每个hook 会得到与它所处理的事件相关的参数,根据 hook的返回值, Subversion会决定是否继续当前的提交过程

要实际安装一个可用的钩子,你需要在 repos/hooks目录下安装一些与钩子同名(如 start-commit或者post-commit)的可执行程序或脚本。

二、本地机器SVN自动更新

1. export方式(备份)

在使用svn客户端时,有可能需要对某一个版本进行本地备份,比如制作成压缩包进行发布,这时候需要从svn文件夹中提取出内容,去除.svn等隐藏的svn配置文件。最笨的方法拷贝一份出来,然后显示隐藏文件,把所有 .svn文件夹都删掉。在svn菜单中,可以找到export命令,这个命令可以将当前svn目录中的内容干净地导出到指定的目录

例如你版本库的svn访问地址是http://10.30.11.12:8080/svn/project1,你想把这个版本库下的/trunk/web文件夹发布到tomcat上,发布到tomcat的文件夹地址是d:/tomcat/opt/web,svn的管理员用户名是abc,密码是12345,那么这个钩子程序应该就是:
svn export http://10.30.11.12:8080/svn/project1/trunk/web d:/tomcat/opt/web --force --username abc --password 12345 --no-auth-cache

注:
--force 是说强制覆盖d:/tomcat/opt/web这个文件夹,避免这个文件夹不为空时报错
--username abc --password 12345 是自动将用户名和密码作为参数传送进去
--no-auth-cache 是说不缓存用户名和密码,这是出于安全考虑

2.update方式

修改hooks/post-commit

export LANG=en_US.UTF-8
SVN=/usr/bin/svn

STATIC_DIR=/web/root/wwwdeng #注意权限问题$SVN update $STATIC_DIR --username deng --password 123456 --no-auth-cache

#必须加上--no-auth-cache不然会报错!!

默认使用的shell类型是sh,最好改成bash,sh是bash的子集,centos中sh其实就是软链接到bash

wKiom1VjzKaCE3pRAAFTxyIwIrs242.jpg

3.update和export比较

update会生成一个隐藏.svn文件夹,这个文件夹是我们不需要的,当然了,如果整个发布的内容很多的话,建议还是用update,而不用export,因为update只更新有变化的部分,而export将重新导出所有内容,网络消耗比update大。

三、svn实现远程机器自动更新

首先实现A机器通过ssh无密码登陆B机器, 修改A机器的post-commit文件

/usr/bin/ssh -l root 192.168.127.183 "/bin/bash /home/www/svnup.sh"

然后在B机器的/home/www/目录创建svnup.sh可执行文件

vim/home/www/svnup.sh

/usr/bin/svn update /web/root/code

版本库有提交请求的时候自动会执行post-commit脚本,post-commit脚本通过ssh让远程机器执行shell脚本自动更新svn。

附注:

@echo off并不是DOS程序中的,
而是DOS批处理中的。
当年的DOS,所有操作都用键盘命令来完成,
当你每次都要输入相同的命令时,
可以把这么多命令存为一个批处理,
从此以后,只要运行这个批处理,
就相当于打了几行、几十行命令。

DOS在运行批处理时,
会依次执行批处理中的每条命令,
并且会在显示器上显示,
如果你不想让它们显示,
可以加一个"echo off"

当然,"echo off"也是命令,
它本身也会显示,
如果连这条也不显示,
就在前面加个"@"。

说了这么多,
我觉得非常详细了,
可能你还是不懂。
没有经过DOS时代的人,
想法跟我们是有区别的。

本文出自 "一无所有-天行者" 博客,请务必保留此出处http://tianxingzhe.blog.51cto.com/3390077/1655385

每日博报 精彩不止一点

迟来的观后感――伪存储专家谈IOPS  阅读原文»


微信号VMCloud

篇前语:

看到封面,相信参加过在北京举行的年亚太区域MVP Open Day的朋友一定不陌生,当时这篇名字为"Hyper-V的数学作业"的课程震撼了在场的每个人的心,包括笔者跟当时跟我一起前往的领导也深深被贾浩老师这篇既有实例又有数据的公开课所启发并在之后的项目中一直收益。当时听完贾老师的课之后,我甚至直接联系到贾老师本人跟他探讨IOPS之余,还要了课件继续做研究(由于保密协议要求,该课件不方便公开,抱歉抱歉,不过本篇解读将会"隐晦"地分享该课件的精华之处,虽远不及贾老师现场讲解的万分之一,但权当抛砖引玉),以下是当年跟贾老师的邮件:

笔者一直忙于应付考试、项目等事没时间整理总结这篇微文,众所周知,目前的虚拟化实际上已经发展到几乎人人皆知的地步,在做虚拟化的过程中,可能很多人或多或少会遇到虚拟机卡、应用莫名访问慢(除开应用本身问题)、数据库死锁多(除开架构优化问题)等情况,而且很多情况下CPU、内存、网络都非常好,甚至占用都不到10%,这到底是为什么?

(免责声明:以下内容由StatLee扮演的StatLee编写,与StatLee本人无关!)

正文部分:

首先,请问下存储相关的参数是什么?在12年前,很多非IT人士可能会回答容量、品牌,IT人士可能会回答容量、转速、读取、写入速度。Ok,容量、转速无可厚非,读取、写入速度这个怎么来衡量呢?很多人可能会回答:"可以看拷贝、复制文件的速度嘛,每秒多少兆多少兆嘛。"没问题,您这样回答OK的,那么我怎么凭借每秒速率来设计我的的底层架构?怎么考虑并发?是平均吗?

通过每秒速率然后平均分摊来设计架构,事实上就算是这样简单的算法都很少人这样做,这样做到底可不可以?据我目前了解,大部分设计者都是基于存储容量考虑,以下我列举一个在VMCloud群里曾经有人问过的问题,姑且称呼他为小明吧(小明躺枪):

小明:"求助各位大神,我有10300G的盘可不可以放60台虚拟机T T"

大蛇:"小伙子,没问题的,每个系统盘40G来算,你3T够的!:)"

小明:"好的,谢谢大神!:D"

第一反应我看到这样的问题,我很汗颜,第二反应,看到这样的回答,我更汗颜,当然回答者说的实际上也没有错,确实,40G60台,差不多也是要2400G(约合2.4T)。

但是!这样的答案真的对吗?这位小伙子以后真的在10300G盘上跑满40台虚拟机会不会有问题呢?

回答这个问题之前,我先来回答前面所提的按照速率平均分摊设计架构究竟可不可以。可以!人家只计算容量设计都没问题,您连速率都考虑进去了肯定比只考虑容量来得慎重啊!更准确的回答,其实您可以选择比速率更加专业的方式,就是今天所要谈的――IOPS

IOPS由于最近几年存储的瓶颈越来越突出,越来越多的ITPro都明白这玩意儿的重要性,那么到底IOPS是什么鬼?如何决定存储的性能?

先上Wiki百科对IOPS的解释(传送门:http://en.wikipedia.org/wiki/IOPS):

简而言之,IOPS是指存储每秒可接受多少次主机发出的访问,主机的一次IO需要多次访问存储才可以完成的一个"指标"。以下是IOPS的计算公式:

看起来蛮复杂的,我要怎么去计算呢?实际上很多时候我们都不需要用到这个公式(如果您真的想纠结下的话,也可以试试,我尝试过,误差不会很大),接下来,咱们来聊聊实战。

实战:

IOPS的加入,仅仅是为您的规划有一个更加精细,但是再精细的估算,也是估算,再上估算之后的存储环境也会受其他的性能参数(诸如网络、内存、处理器等限制),由于本篇只讨论存储,故不考虑其他性能条件(即默认都是满足要求的),所以请不要纠结于精不精准。废话不多说,那么先上一组数据(相信大家都比较熟悉了):

  • 常见SAS盘可提供的单盘IOPS(可能有不同版本有多多少少的误差,无所谓了)

  • 常见系统的IOPS需求(可以看到最高的要求是50左右,我们按照内存比来计算,8G内存大概需要100+IOPS):

  • 常见Raid级别的IOPS比例与计算方式(可能就比较少人考虑了,并不是叠加计算),我们此篇为能够简单暴力的表达IOPS的规划,暂时不考虑应用的读写比例,就以物理的IOPS读写比例来进行计算:

  • 再来个比较夸张的IOPS例子做对比(当然SharePointExchange诸如此类都是吃IO大户,这里暂且以SQL为吃IO大户吧):

Ok,现在我们可以来回答小明的问题了,到底10300G的盘,能不能撑下60台虚拟机?鉴于小明提的问题实际上也不是特别明确,基于谨慎的原则,我们来设计两个场景:

  1. 101WRPM SAS 300G,无Raid60个虚拟机均为常规系统,且内存、CPU均为4G2 Cores

  2. 101WRPM SAS 300GRaid 1060个虚拟机80%为常规系统,内存为8G2 Cores阅读更多内容

2015年5月25日星期一

为DELL 2900添加全局热备磁盘

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
为DELL 2900添加全局热备磁盘  阅读原文»

我们在规划服务器本地存储的时候,一般是为服务器配置RAID,并在机房放置一块同样容量、大小的硬盘做为备用。并且定期巡检机房,一旦看到磁盘报警(红灯或黄灯),应该用备用硬盘替换故障磁盘,此时RAID卡会检测到硬盘替换,并在新替换的磁盘上重建数据。这种方式是目前大多数单位使用的方法,但是,服务器一般都能正常使用三、五年不出问题,开始的时候,可能还会定期检查服务器,之后可能管理员就很少去机房检查,即使去机房检查也很少一一查看服务器的硬盘指示灯。在配置RAID5时,如果阵列中只有一块硬盘出现故障,系统会正常工作,如果有多块硬盘出现故障,则系统将不能正常工作。如果长时间不检查,等发现系统出现问题时再去检查,一般都是出现不止一块磁盘出现故障,此时修复系统就比较麻烦。今天我就碰到一例,一台有6块300GB硬盘、配置了RAID5的服务器,有两个硬盘出现故障(一块呈琥珀色闪烁,表示驱动器出现故障;另一块呈绿色/琥珀色闪烁,驱动器预报故障)的问题。

1 替换有故障磁盘

一台工作多年的DELL 2900服务器,近期有一块磁盘(位置为3)出现故障(呈琥珀色闪烁,离线),而另一块磁盘(位置为0)亦开始呈绿色/琥珀色闪烁,该提示是驱动器预报故障。该服务器共有6块3.5寸、15K、300GB硬盘,配置RAID5,这6块磁盘依次插在0~5的位置。如图1-1所示。

图1-1 服务器正面图

此时服务器已经不能进入系统(提示找不到系统盘)。我到机房之后,看到服务器硬盘档板都是灰尘(如图1-2所示),先关闭服务器电源,将每个硬盘拔下,先清理灰尘,注意不要一下把所有硬盘拔下来,而是一个一个清理灰尘,避免插错位置。

图1-2 硬盘档板灰尘

等清理完灰尘之后,重新打开服务器的电源,按Ctrl+R键进入RAID配置配置,在"Physical Disk Management"(物理磁盘管理)视图中,可以看到03盘位的磁盘已经标记为"Failed",如图1-3所示。

图1-3 磁盘03已经失败

因为机房有一块备用硬盘,换上备用硬盘之后,开始重建,如图1-4所示。

图1-4 磁盘3 Rebuild

返回到"VD Mgmt"界面,在"Physical Disks(物理磁盘组)"可以看到重建进度,如图1-5所示。

图1-5 重建进度

对于300GB的磁盘,在没有进入操作系统界面、在RAID卡配置界面中,大约需要70分钟的时间就可以完成重建。如图1-6所示,重建完成。

图1-6 重建完成

在重建完成后,需要进行数据的一致性校验。在"Virtual Disks(虚拟磁盘)"中,选择每一个逻辑磁盘,按F2键,选择"Consistency Check(一致性检查,以便验证使用 RAID 级别 1、5、6、10、50 和 60 的虚拟磁盘中的冗余数据)",如图1-7所示,检查数据是否完好、正确。

图1-7 一致性检验

一致性检查速度较快,如图1-8所示,这是检验进度。应该几分钟完成。注意,不要误选中"Initialization(初始化)",完全初始化将对所有已经存在的数据造成永久性破坏。

图1-8 校验进度

应该对每一个逻辑磁盘进行校验。检验完成后,退出RAID卡配置界面,此时系统会得以恢复。

对于00位置的磁盘、间隔大约120秒闪烁一次黄灯的硬盘,为了防患于未然,也应该替换,但当前机房只有一个硬盘,需要购买新的硬盘替换。

2 添加全局备用磁盘

当前情况是,该单位有两台DELL 2900服务器,每台服务器都是6块硬盘做RAID5,在机房准备了一块备用磁盘,发现那台服务器磁盘出现问题就人工替换。由于服务器已经使用多年,管理人员怕硬盘再次出现问题,毕竟不可能每天都来机房检查。此时就引来一个问题,有没有办法,不是人工替换硬盘,而是由服务器自动替换损坏硬盘呢?这可以通过在服务器中添加全局热备用磁盘来解决。

全局热备用磁盘,是在磁盘子系统中配置一块或多块额外的磁盘,额外的磁盘平常不用,处于备用状态,一旦系统中出现有故障的磁盘,系统可以用备用的磁盘自动重建磁盘控制器上任何发生故障的驱动器。奇偶/镜像数据用于将有故障磁盘中丢失的数据写入到热备用磁盘中,从而将处于临界状态的时间降为最低。

RAID-0没有必要采用热备用驱动器,因为它不提供任何镜像数据或奇偶校验信息,当然也不能实现磁盘重建。

如果要为所有服务器都配置全局备用磁盘,需要为每台服务器再次配置一块相同容量、性能的磁盘。

等过了几天,磁盘到位之后,我们先在有故障硬盘的服务器的空闲盘位上(磁盘位置07)插上新的硬盘,进入系统将这块新添加的硬盘配置为全局热备磁盘,然后拔下00位置的故障磁盘,查看全局热备是否启用。主要步骤如下。

(1)进入RAID卡配置界面,在物理磁盘管理界面,可以看到07位置已经添加了一个同样大小、接口的磁盘,状态为Ready(就绪),而其他正在使用的磁盘状态为online,如图1-9所示。

图1-9 查看磁盘

(2)选中新添加的磁盘,按F2,在弹出的快捷菜单中选择"Make Global HS(成为全局热备用)",如图1-10所示。

图1-10 标准全局热备

(3)在弹出的对话框中选择"YES",如图1-11所示。

图1-11 确认

(4)设置为全局热备磁盘状态为"Hotspare",如图1-12所示。

图1-12 设置为全局热备

(5)返回到"VD Mgmt"管理界面,可以看到07硬盘为全局热备,信息为"Global,Affinity",如图1-13所示。此时工作磁盘为00、01、02、03、04、05。

图1-13 查看配置

此时如果要退出RAID配置界面,系统会正常使用。

(6)拔下位置0的故障磁盘,此时原来在"Hot spares"磁盘07会替换0位置的磁盘,开始重建,如图1-14所示。此时数据磁盘为01、02、03、04、05、07。

图1-14 全局热备磁盘代替故障磁盘

(7)在00位置插上新买的磁盘,这个磁盘状态为Ready,如图1-15所示。

图1-15 新添加的00位置磁盘状态

(8)之后将这个磁盘再次标记为全局热备,如图1-16所示。

图1-16 标准新添加磁盘为全局热备

(9)之后这块新添加的00位置磁盘变为全局热备,而原来07位置状态为Rebuild,代替原来的00位置的磁盘,如图1-17所示。

<div使用Jenkins发布腾讯云项目  阅读原文»

使用Jenkins发布腾讯云项目

最近研究使用jenkins来发布项目,使用publish-over-ssh插件,把打包好的zip或者war包上传到远程服务器上,并执行一些命令,本来也没什么问题,但是公司主要业务在腾讯云上,但是腾讯云的服务器并没有外网地址,SSH连接到服务器只能通过腾讯云HTTP代理服务器,并且需要token+服务器的密码,才能连接到服务器。

问题来了 publish-over-ssh插件 并没有设置访问时ssh时通过HTTP代理服务器,如何解决才好?

到jenkins服务器上该插件的lib目录下看看该插件的构成,该插件依赖于jsch-0.1.45.jar这个jar包,刚好对jsch比较熟悉,于是找到publish-over-ssh的源码下载下来,找到ssh连接的代码,加上http代理的代码,加的代码如下:

src\main\java\jenkins\plugins\publish_over_ssh\BapSshHostConfiguration.java

  public BapSshClient createClient(final BPBuildInfo buildInfo, final boolean connectSftp) {          final JSch ssh = createJSch();          final Session session = createSession(buildInfo, ssh);          final BapSshClient bapClient = new BapSshClient(buildInfo, session, isEffectiveDisableExec());          try {              final BapSshKeyInfo keyInfo = getEffectiveKeyInfo(buildInfo);              final Properties sessionProperties = getSessionProperties();              Properties properties = new Properties();              // 得到jar包所在的路径              String jarPath = BapSshHostConfiguration.class.getProtectionDomain().getCodeSource().getLocation().getPath();              String sep = File.separator;              int lastIndex = jarPath.lastIndexOf(File.separator);              // 读取配置文件              FileInputStream fileInputStream = new FileInputStream(jarPath.substring(0,lastIndex)+ sep +"configure.properties");              properties.load(fileInputStream);              String enableHttpProxy = properties.getProperty("enable_http_proxy");              String proxyServer = properties.getProperty("http_proxy_server");              String proxyPort = properties.getProperty("http_proxy_port");              if (keyInfo.useKey()) {                  setKey(buildInfo, ssh, keyInfo);                  sessionProperties.put(CONFIG_KEY_PREFERRED_AUTHENTICATIONS, "publickey");              } else {                  session.setPassword(Util.fixNull(keyInfo.getPassphrase()));                  sessionProperties.put(CONFIG_KEY_PREFERRED_AUTHENTICATIONS, "keyboard-interactive,password");              }              session.setConfig(sessionProperties);              if ("1".equals(enableHttpProxy)){                  session.setProxy(new ProxyHTTP(proxyServer,Integer.parseInt(proxyPort)));              }              connect(buildInfo, session);              if (connectSftp) setupSftp(buildInfo, bapClient);              return bapClient;          } catch (IOException ioe) {              bapClient.disconnectQuietly();              throw new BapPublisherException(Messages.exception_failedToCreateClient(ioe.getLocalizedMessage()), ioe);          } catch (RuntimeException re) {              bapClient.disconnectQuietly();              throw re;          }      }  

这个方法其中以下是添加的

  Properties properties = new Properties();  // 得到jar包所在的路径  String jarPath = BapSshHostConfiguration.class.getProtectionDomain().getCodeSource().getLocation().getPath();  String sep = File.separator;  int lastIndex = jarPath.lastIndexOf(File.separator);  // 读取配置文件  FileInputStream fileInputStream = new FileInputStream(jarPath.substring(0,lastIndex)+ sep +"configure.properties");  properties.load(fileInputStream);  String enableHttpProxy = properties.getProperty("enable_http_proxy");  String proxyServer = properties.getProperty("http_proxy_server");  String proxyPort = properties.getProperty("http_proxy_port");  if ("1".equals(enableHttpProxy)){          session.setProxy(new ProxyHTTP(proxyServer,Integer.parseInt(proxyPort)));  }  

通过maven重新打包成publish-over-0.18.jar,然后重命名为classes.jar,到插件的lib备份原有的classes.jar之后删除,上传新生成的classes.jar到lib目录,下载该文件

classes.jar

然后新建configure.properties文件,里面写上配置,如下:

  #### Enable HTTP Proxy 0:disable 1:enable####  enable_http_proxy=1  http_proxy_server=cvm-proxy.opencloud.qq.com  http_proxy_port=80  

classes.jar和configure.properties上传之后,位于如下位置,注意自己的jenkins安装位置

270895242.png

然后重启一下jenkins服务器,在添加主机的IP时候,就填上腾讯云服务器的内网地址和端口,用户名是你的appid,密码是服务器的密码,只不过等发布的时候可以临时把token关闭一下,这样就行了。

只不过这里还有点小问题,这里要是jenkins服务器不只给腾讯云服务器发布项目呢,连接其他的服务器时,不需要通过HTTP代理,这时候 看配置文件里面的

  enable_http_proxy=1  

这一项如果是1,就启用http代理,0 就禁用http代理,所以在使用在把部署文件传到服务器之前把该值修改一下(通过shell命令),就OK了。

至此就大功告成。

本文出自 "雷纳科斯的博客" 博客,请务必保留此出处http://linux5588.blog.51cto.com/65280/1654767

分享至 一键收藏,随时查看,分享好友!
每日博报 精彩不止一点

阅读更多内容

(十二) 一起学 Unix 环境高级编程 (APUE) 之 进程间通信(IPC) - yuhuashi

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
(十二) 一起学 Unix 环境高级编程 (APUE) 之 进程间通信(IPC) - yuhuashi  阅读原文»

.

.

.

.

.

目录

(一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO

(二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO

(三) 一起学 Unix 环境高级编程 (APUE) 之 文件和目录

(四) 一起学 Unix 环境高级编程 (APUE) 之 系统数据文件和信息

(五) 一起学 Unix 环境高级编程 (APUE) 之 进程环境

(六) 一起学 Unix 环境高级编程 (APUE) 之 进程控制

(七) 一起学 Unix 环境高级编程 (APUE) 之 进程关系 和 守护进程

(八) 一起学 Unix 环境高级编程 (APUE) 之 信号

(九) 一起学 Unix 环境高级编程 (APUE) 之 线程

(十) 一起学 Unix 环境高级编程 (APUE) 之 线程控制

(十一) 一起学 Unix 环境高级编程 (APUE) 之 高级 IO

(十二) 一起学 Unix 环境高级编程 (APUE) 之 进程间通信(IPC)

在第一篇博文中我们介绍过,进程间通信(IPC) 分为 PIPE(管道)、Socket(套接字) 和 XSI(System V)。XSI 又分为 msg(消息队列)、sem(信号量数组) 和 shm(共享内存)。

这些手段都是用于进程间通讯的,只有进程间通讯才需要借助第三方机制,线程之间的通讯是不需要借助第三方机制的,因为线程之间的地址空间是共享的。

管道分为命名管道(FIFO)和匿名管道(PIPE),无论是哪种管道,都是由内核帮你创建和维护的。

管道的特点:

1.管道是半双工的,即同一时间数据只能从一端流向另一端。试想,如果一个管道从两边同时输入和输出数据,那么管道里的数据就乱了。

2.管道的两端一端作为读端,一端作为写端。

3.管道具有自适应的特点,默认会适应速度比较慢的一方,管道被写满或读空时速度快的一方会自动阻塞。

pipe(2) 函数

1 pipe - create pipe
2
3 #include <unistd.h>
4
5 int pipe(int pipefd[2]);

pipe(2) 用于创建管道,pipefd 是一个数组,表示管道的两端文件描述符,pipefd[0] 端作为读端,pipefd[1] 端作为写端

pipe(2) 产生的是匿名管道,在磁盘的任何位置上找不到这个管道文件,而且匿名管道只能用于具有亲缘关系的进程之间通信

一般情况有亲缘关系的进程之间使用管道进行通信时,会把自己不用的一端文件描述符关闭。

下面是创建匿名管道在父子进程之间传送了一个字符串“Hello”的小栗子。

1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4
5 #include <sys/types.h>
6 #include <sys/wait.h>
7
8 #define BUFSIZE 1024
9
10 int main()
11 {
12 int pd[2];
13 char buf;
14 pid_t pid;
15 int len;
16
17 // 创建匿名管道
18 if(pipe(pd) < 0)
19 {
20 perror("pipe()");
21 exit(1);
22 }
23
24 // 创建子进程
25 pid = fork();
26 if(pid < 0)
27 {
28 perror("fork()");
29 exit(1);
30 }
31 if(pid == 0) { // 子进程 读取管道数据
32 // 关闭写端
33 close(pd[1]);
34 // 从管道中读取数据,如果子进程比父进程先被调度会阻塞等待数据写入
35 len = read(pd[0],buf,BUFSIZE);
36 puts(buf);
37 /* 管道是 fork(2) 之前创建的,
38 * 父子进程里都有一份,
39 * 所以退出之前要确保管道两端都关闭
40 */
41 close(pd[0]);
42 exit(0);
43 } else { // 父进程 向管道写入数据
44 close(pd[0]);
45 write(pd[1],"Hello!",6);
46 close(pd[1]);
47 wait(NULL);
48 exit(0);
49 }
50 }

在上面的栗子中,父进程创建了一个匿名管道,在 pd[2] 数组中凑齐了读写双方,子进程同样继承了具有读写双方的数组 pd[2]。

父进程先关闭管道的读端然后向管道中写入数据,然后将用完的写端也关闭,等待子进程消亡并为其收?div style="border-bottom:1px solid #aaa;margin-bottom:25px">xUtils框架的使用详解 - 杰瑞教育  阅读原文»

一、xUtils简介

  xUtils 最初源于Afinal框架,进行了大量重构,使得xUtils支持大文件上传,更全面的http请求协议支持(10种谓词),拥有更加灵活的ORM,更多的事件注解支持且不受混淆影响...

  xUtils最低兼容android 2.2 (api level 8)。当前xUtils主要有四大模块:

  DbUtils模块

android中的orm框架,一行代码就可以进行增删改查;

支持事务,默认关闭;

可通过注解自定义表名,列名,外键,唯一性约束,NOT NULL约束,CHECK约束等(需要混淆的时候请注解表名和列名);

支持绑定外键,保存实体时外键关联实体自动保存或更新;

  ViewUtils模块

android中的ioc框架,完全注解方式就可以进行UI,资源和事件绑定;

新的事件绑定方式,使用混淆工具混淆后仍可正常工作;

  HttpUtils模块

支持同步,异步方式的请求;

支持大文件上传,上传大文件不会oom;

支持GET,POST,PUT,MOVE,COPY,DELETE,HEAD,OPTIONS,TRACE,CONNECT请求;

  BitmapUtils模块

加载bitmap的时候无需考虑bitmap加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象;

支持加载网络图片和本地图片;

内存管理使用lru算法,更好的管理bitmap内存;

二、DbUtils使用方法
DbUtils db = DbUtils.create(this);
User user
= new User(); //这里需要注意的是User对象必须有id属性,或者有通过@ID注解的属性
user.setEmail("jerehedu@qq.com");
user.setName(
"jerehedu");
db.save(user);
// 使用saveBindingId保存实体时会为实体的id赋值

...
// 查找
Parent entity = db.findById(Parent.class, parent.getId());
List
<Parent> list = db.findAll(Parent.class);//通过类型查找

Parent Parent
= db.findFirst(Selector.from(Parent.class).where("name","=","test"));

// IS NULL
Parent Parent = db.findFirst(Selector.from(Parent.class).where("name","=", null));
// IS NOT NULL
Parent Parent = db.findFirst(Selector.from(Parent.class).where("name","!=", null));

// WHERE id<54 AND (age>20 OR age<30) ORDER BY id LIMIT pageSize OFFSET pageOffset
List<Parent> list = db.findAll(Selector.from(Parent.class)
.where(
"id" ,"<", 54)
.and(WhereBuilder.b(
"age", ">", 20).or("age", " < ", 30))
.orderBy(
"id")
.limit(pageSize)
.offset(pageSize
* pageIndex));

// op为"in"时,最后一个参数必须是数组或Iterable的实现类(例如List等)
Parent test = db.findFirst(Selector.from(Parent.class).where("id", "in", new int[]{1, 2, 3}));
// op为"between"时,最后一个参数必须是数组或Iterable的实现类(例如List等)
Parent test = db.findFirst(Selector.from(Parent.class).where("id", "between", new String[]{"1", "5"}));

DbModel dbModel
= db.findDbModelAll(Selector.from(Parent.class).select("name"));//select("name")只取出name列
List<DbModel> dbModels = db.findDbModelAll(Selector.from(Parent.class).groupBy("name").select("name", "count(name)"));
...

List
<DbModel> dbModels = db.findDbModelAll(sql); // 自定义sql查询
db.execNonQuery(sql) // 执行自定义sql
三、HttpUtils使用方法
HttpUtils http = new HttpUtils();
http.send(HttpRequest.HttpMethod.GET,
"http://www.jerehedu.com",
new RequestCallBack<String>(){
@Override
public void onLoading(long total, long current, boolean isUploading) {
testTextView.setText(current
+ "/" + total);
}

@Override
public void onSuccess(ResponseInfo<String> responseInfo) {
textView.setText(responseInfo.result);
}

@Override
public void onStart() {
}

@Override
public void