Solo  当前访客:4 登录 注册

喧哗博客-http://blog.xuahua.com

繁华过后的沉寂--技术经验分享
浏览次数: 94,390    文章总数: 91    评论总数: 3
存档:
2016 年 08 月 (13)

分布式框架安装与布署-dubbo 有更新!

 前言

在电子商务行业发展到今天,各种应用支持高并发的开源框架进行无数的实践以及验证。其中首推淘宝的dubbo,虽说这套系统淘宝不再跟进升级,但是其他从dubbo衍生出来的分支,dubbox等很多继续在使用中。。

像京东,当当网都是在使用的dubbo框架。

好了,话入正题

 ;)淘宝dubbo,只支持spring2.x ,下载地址 https://github.com/alibaba/dubbo

:)当当网的分支dubbox 已经可以支持spring3.x 下载地址 https://github.com/dangdangdotcom/dubbox

 

root> git clone https://github.com/dangdangdotcom/dubbox dubbo

root> cd dubbo

root> mvn clean install -Dmaven.test.skip=true 

在这里不跳过测试,会出现 N多问题,曾经在此花了N多时间来解决或看源码,最后放弃。。先直接跑起来才是王道。所以加上 -Dmaven.test.skip=true

生成的 com.allibaba.dubbo.jar 在 dubbo/target/目录下。

为了后续应用的使用,把此jar包上传至maven 私有库nexus中。

上传私有库

 

至此,dubbox 编译完成。

二,布署 zookeeper注册中心  原址:http://blog.csdn.net/huwei2003/article/details/49101269

官网文档地址大全:

OverView(概述)
http://zookeeper.apache.org/doc/r3.4.6/zookeeperOver.html

Getting Started(开始入门)
http://zookeeper.apache.org/doc/r3.4.6/zookeeperStarted.html

Tutorial(教程)
http://zookeeper.apache.org/doc/r3.4.6/zookeeperTutorial.html

Java Example(Java示例)
http://zookeeper.apache.org/doc/r3.4.6/javaExample.html

Programmer's Guide(开发人员指南)
http://zookeeper.apache.org/doc/r3.4.6/zookeeperProgrammers.html

Recipes and Solutions(技巧及解决方案)
http://zookeeper.apache.org/doc/r3.4.6/recipes.html

3.4.6 API online(在线API速查)

http://zookeeper.apache.org/doc/r3.4.6/api/index.html

另外推荐园友sunddenly的zookeeper系列
http://www.cnblogs.com/sunddenly/category/620563.html

 

文在一台机器上模拟3个 zk server的集群安装

1.1 下载解压

解压到3个目录(模拟3台zk server):

  /home/hadoop/zookeeper-1
  /home/hadoop/zookeeper-2
  /home/hadoop/zookeeper-3
1.2 创建每个目录下conf/zoo.cfg配置文件

/home/hadoop/zookeeper-1/conf/zoo.cfg 内容如下:

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/hadoop/tmp/zk1/data
dataLogDir=/home/hadoop/tmp/zk1/log
clientPort=2181
server.1=localhost:2287:3387
server.2=localhost:2288:3388
server.3=localhost:2289:3389

/home/hadoop/zookeeper-2/conf/zoo.cfg 内容如下:

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/hadoop/tmp/zk2/data
dataLogDir=/home/hadoop/tmp/zk2/log
clientPort=2182
server.1=localhost:2287:3387
server.2=localhost:2288:3388
server.3=localhost:2289:3389

/home/hadoop/zookeeper-3/conf/zoo.cfg 内容如下:

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/hadoop/tmp/zk3/data
dataLogDir=/home/hadoop/tmp/zk3/log
clientPort=2183
server.1=localhost:2287:3387
server.2=localhost:2288:3388
server.3=localhost:2289:3389

注:因为是在一台机器上模拟集群,所以端口不能重复,这里用2181~2183,2287~2289,以及3387~3389相互错开。另外每个zk的instance,都需要设置独立的数据存储目录、日志存储目录,所以dataDir、dataLogDir这二个节点对应的目录,需要手动先创建好。

另外还有一个灰常关键的设置,在每个zk server配置文件的dataDir所对应的目录下,必须创建一个名为myid的文件,其中的内容必须与zoo.cfg中server.x 中的x相同,即:

/home/hadoop/tmp/zk1/data/myid 中的内容为1,对应server.1中的1
/home/hadoop/tmp/zk2/data/myid 中的内容为2,对应server.2中的2
/home/hadoop/tmp/zk3/data/myid 中的内容为3,对应server.3中的3

生产环境中,分布式集群部署的步骤与上面基本相同,只不过因为各zk server分布在不同的机器,上述配置文件中的localhost换成各服务器的真实Ip即可。分布在不同的机器后,不存在端口冲突问题,可以让每个服务器的zk均采用相同的端口,这样管理起来比较方便。

1.3 启动验证

/home/hadoop/zookeeper-1/bin/zkServer.sh start

/home/hadoop/zookeeper-2/bin/zkServer.sh start

/home/hadoop/zookeeper-3/bin/zkServer.sh start
启用成功后,输入 jps 看下进程

20351 ZooKeeperMain
20791 QuorumPeerMain
20822 QuorumPeerMain
20865 QuorumPeerMain

应该至少能看到以上几个进程。

可以启动客户端测试下:

bin/zkCli.sh -server localhost:2181
(注:如果是远程连接,把localhost换成指定的IP即可)

成功后,应该会进到提示符下,类似下面这样:

[zk: localhost:2181(CONNECTED) 0]

 

二,布署dubbo-admin-2.8.4.war包,

进入dubbo目录

root> cd dubbo-admin

root> mvn clean package -Dmaven.test.skip=true

打包以后,复制 dubbo-admin.2.8.4.war包复制到 tomcat webapps/root中。

注意:

如果启动提示找不到 /META-INF/spring/dubbo-admin.xml

可以在 源码文件中找到或者修改 /WEB-INF/webx.xml 

<!-- 应用资源 -->
<beans:import resource="common/dubbo-admin.xml" />
<!-- <beans:import resource="classpath:/META-INF/spring/dubbo-admin.xml" /> -->

我把dubbo-admin.xml 复制到了 /WEB-INF/common/目录下。

同时修改tomcat中server.xml中 port=8090

访问 http://localhost:8090/dubbo-admin.2.8.4/ 根据个人情况,我是直接使用源码编译至 root目录下,所以访问路径有些变化,http://localhost:8090/

如下图dubbo后台

 

 

 

 

三,监控dubbo-monitor布署

下载

root> git clone https://github.com/handuyishe/dubbo-monitor dubbo-monitor

root> cd dubbo-monitor

root>mvn clean package -Dmaven.test.skip=true

进入 target 目录找到 dubbo-monitor.2.8.4.war 

布署到tomcat webapps/root/目录中。。我是解压后再扔进去,没有dubbo-monitor.2.8.4 这层目录,所以访问直接使用http://localhost:8091/即可;

修改service.xml 。因为已经存在一个host,需要同时复制一个host,同时修改port=8091

重启tomcat。

访问http://localhost:8091/

结果如下 dubbo-monitory

 

 

如何解决热点数据更新问题

原创地址: http://blog.itpub.net/22664653/viewspace-1269948/

一 背景
     某个业务线 商品开放开用户申请免费试用,当某个商品特别吸引人时,比如iPhone6 。肯定有一大波人为了少卖一个肾 疯狂去抢申请资格。有甚者利用机器人申请注册,于是简单的申请操作变成了秒杀行为. 大量请求同时更新数据库中的同一个商品的申请次数,update 操作给表加上行锁,导致后面的请求全部排队等待前面一个update完成,释放行锁后才能处理下一个请求。大量后来请求等待,占用了数据库的连接。一旦数据库连接数被占满,就会导致后来的全部请求因拿不到连接而超时,业务请求出现无法及时处理的情况,数据库系统的RT会异常飙高,业务层由于等待出现超时,app 层的连接耗尽,一系列的雪崩效应!

二 解决方案
     从上面的背景分析,解决热点数据并发更新需要注意核心问题: 减少直接对db层数据热点的并发更新,本文从业务和数据库的设计层面来规划.同时也希望大家提更好的解决思路。
1 前端层面
   前端是整个流量的入口, 正常业务访问时系统表现平稳,但是当有人恶意请求时,需要加上流控措施,比如常见的
   a 需要用户回答问题,填写验证码,移动图像等等,防止或者减少有机器人来恶意请求。
   b 页面上采用防止机器人的判断 两秒以内的成功请求一律拒绝。
   c 通过设置nginx ,对同一个ip源的请求次数做限制,防止机器人来申请。
  优点 有效减少或者防止有人利用机器人恶意请求
  缺点 存在一定的误杀率,错杀了正常的请求。

2 应用层
    应用程序接收前端前端请求,进行一系列的数据库操作,在我们规避了恶意请求之后如果还是有大量的数据库写访问请求,我们需要
    a 对业务做降级
限制接口的调用次数,降低对数据库的请求压力。
选择不更新请求次数,弱化该商品申请次数的展现。类似于阅读次数,申请次数 ,与金额,库存无关的功能点。

    b 通过异步更新来避免直接写数据库 。
      应用使用分布式缓存(比如tair)来存储某项商品的申请次数或者某人的申请次数,以商品id/user_id 或者将where 条件作为key,申请试用人数为value/符合某项具体条件的 count结果为value, 有用户申请成功则更新申请试用人数。不需要查询和实时写数据库,每隔一定时间/次数将结果写入数据库。
      优点:该方法完全依赖于缓存,读写速度快,不需要实时更新数据库,减轻数据库并发写的压力;
      缺点:缓存不是100%稳定,很容易丢,即使采用持久化的缓存,在高并发下有时也可能会出现异常,穿透缓存到db ,导致前端业务展现问题。
    
3 数据库层
    a 将热点数据拆分,分在不同的库不同的表中,分散热点数据,减轻数据库并发更新热点带来的RT升高和应用连接等待时能保证业务能够正常访问其他商品表,损失局部可用性。
    优点:实时读写数据库,前端展示数据的准确性。
    缺点:业务逻辑稍显复杂。
  b 限流补丁
     针对某些特定的sql语句 从MySQL 层面加以限制,当系统thread_running达到一定值或者某个sql执行时间超过一定阈值则拒绝该sql的执行。(阿里内部已经实现限流版本)
   c 使用MySQL的 thread pool 功能。在并发较大时,one to one的模式会引起Innodb的mutex锁争用。当前解决方法是通过innodb_thread_concurrency参数,但是该参数自身也存在锁争用,同样影响了MySQL的性能。
优点:thread pool主要从四个方面考虑:减少SQL并发,使得有足够的资源:使用线程组,独立管理:使用优先级队列,限制并发执行的事务:避免死锁。
缺点:在测试过程中发现,会有大量的连接等待kernel mutex锁,但是持续的压力会导致MySQL的thread running飙高,最终导致MySQL不可用。
三 小结
     在电商类业务中数据库的热点/单点更新 一直是DBA和业务方比较关心的问题,它最直观的影响用户体验,比如商品的超卖,系统的可用性。需要不断的细化解决思路和具体实现比如 热点商品的属性是否实时更新 ,库存数量需要实时展示,访问次数,请求次数可以异步延迟展示。本文只是简单阐述了 对热点更新的解决思路,还有不完善的地方,欢迎给位提供更好的建议。
 

liunx下FTP快速搭建 有更新!

1,查看系统是否已经安装

rpm -qa |grep vsftpd

vsftpd服务器快速搭建

2,安装

yum install vsftpd -y

vsftpd快速搭建

3,重启 service vsftpd start|restart|stop

 

4,建立ftp账号密码

建用户:在root用户下:
useradd -d /home/ftp   ftpuser //增加用户ftpuser,并制定ftpuser用户的主目录为/home/ftp
passwd ftpuser                        //为ftpuser设置密码
 

5, 修改配置文件

root>vim /etc/vsftpd/vsftpd.conf

anonymous_enable=NO ##禁用匿名账号

local_enable=YES

write_enable=YES

 最后在该文件的最后面添加如下行:
userlist_enable=YES
userlist_deny=NO
userlist_file=/etc/vsftpd/user_list

chroot_list_enable=YES //限制访问自身目录
 
chroot_list_file=/etc/vsftpd/chroot_list #指定账号密码文件


最后保存/etc/vsftpd/vsftpd.conf文件。

6,写入账号访问路径限制

root>vim /etc/vsftpd/chroot_list

ftpuser /home/ftp

 

保存退出。

root>service vsftpd restart

httpclient4.x 模拟post请求

     /**
	 * @param url
	 * @param data
	 * @param encode
	 *            指定头编码
	 * @return
	 */
	public static String postRequest(String url, Map<String, String> data,
			String encode) {
		if(StringUtils.isBlank(encode)){
			encode = "utf8";
		}
		StringBuilder sb = new StringBuilder();
		CloseableHttpClient httpclient = HttpClientBuilder.create().build();
		HttpPost httppost = new HttpPost(url);
		postRequestconfig(httppost);
        try{
        	if (data != null) {
        		List<NameValuePair> dataary = new ArrayList<NameValuePair>();
				for (String mapKey : data.keySet()) {
					// 填入各个表单域的值
					String vString = data.get(mapKey) == null ? "" : data.get(
							mapKey).toString();
					NameValuePair data1 = new BasicNameValuePair(mapKey, vString);
					dataary.add(data1);
				}
				// 将表单的值放入postMethod中
				 httppost.setEntity(new UrlEncodedFormEntity(dataary,encode));
			}
	        CloseableHttpResponse response = httpclient.execute(httppost);
	        int statusOk = response.getStatusLine().getStatusCode();
	        if(logger.isInfoEnabled()){
	        	logger.info(url+"result-statusCode=>>"+statusOk);
	        }
	        if(statusOk == HttpStatus.SC_OK){
	        	HttpEntity entity = response.getEntity();
	        	BufferedInputStream instream = new BufferedInputStream(entity.getContent()); 
		        byte[] chars = new byte[2048];
		        int len=0;
		        while((len=instream.read(chars))!=-1){
		        	sb.append(new String(chars,0,len,encode));
		        }
		        instream.close();
		        response.close();
	        }else{
	        	logger.error(url+"result->网络异常.."+statusOk);
	        }
	        if(logger.isInfoEnabled()){
	        	logger.info(url+"result->"+sb.toString());
	        }
        }catch(Exception e){
        	e.printStackTrace();
        }finally{
        	httppost.releaseConnection();
        	try {
				httpclient.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
        }
        return sb.toString();
	}

httpclient4.x 模拟get请求

private static void postRequestconfig(HttpPost httppost){
		 //配置请求的超时设置
		RequestConfig requestConfig = RequestConfig.custom()
				.setConnectionRequestTimeout(Timeout)
				.setConnectTimeout(Timeout)  
				.setSocketTimeout(Timeout).build();
        httppost.setConfig(requestConfig);
	}
public static String getRequest(String url) { StringBuilder sb = new StringBuilder(); CloseableHttpClient httpclient = HttpClientBuilder.create().build(); HttpGet httpget = new HttpGet(url); getRequestconfig(httpget); try{ CloseableHttpResponse response = httpclient.execute(httpget); int statusOk = response.getStatusLine().getStatusCode(); if(logger.isInfoEnabled()){ logger.info(url+"result-statusCode=>>"+statusOk); } if(statusOk == HttpStatus.SC_OK){ HttpEntity entity = response.getEntity(); BufferedInputStream instream = new BufferedInputStream(entity.getContent()); byte[] chars = new byte[2048]; int len=0; while((len=instream.read(chars))!=-1){ sb.append(new String(chars,0,len)); } }else{ logger.error(url+"result->网络异常.."+statusOk); } if(logger.isInfoEnabled()){ logger.info(url+"result->"+sb.toString()); } }catch(Exception e){ e.printStackTrace(); }finally { httpget.releaseConnection(); try { httpclient.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return sb.toString(); }

Got an error reading communication packets 有更新!

 

具体表现

2016-08-11T17:34:01.264286Z 36668 [Note] Aborted connection 36668 to db: 'game' user: 'game28' host: 'localhost' (Got an error reading communication packets)
2016-08-11T17:34:01.264335Z 36672 [Note] Aborted connection 36672 to db: 'game' user: 'game28' host: 'localhost' (Got an error reading communication packets)
2016-08-11T17:34:01.264337Z 36671 [Note] Aborted connection 36671 to db: 'game' user: 'game28' host: 'localhost' (Got an error reading communication packets)
2016-08-11T17:35:01.424325Z 36678 [Note] Aborted connection 36678 to db: 'xx' user: 'xx' host: 'localhost' (Got an error reading communication packets)
2016-08-11T17:35:01.424335Z 36679 [Note] Aborted connection 36679 to db: 'xx' user: 'xx' host: 'localhost' (Got an error reading communication packets)
2016-08-11T17:35:01.424372Z 36685 [Note] Aborted connection 36685 to db: 'x' user: 'xx' host: 'localhost' (Got an error reading communication packets)
2016-08-11T17:35:01.424343Z 36680 [Note] Aborted connection 36680 to db: 'xx' user: 'xx' host: 'localhost' (Got an error reading communication packets 

解决方法

在my.cnf 文件中,增加 max_allowed_packet =256M

 原因 

http://dev.mysql.com/doc/refman/5.7/en/communication-errors.html

The max_allowed_packet variable value is too small or queries require more memory than you have allocated for mysqld

翻译出来就是,服务器端设定max_allowed_packet的值太小或者查询要求的缓冲内存区比mysqld设定的要大。

 

 

 

nginx+tomcat负载均衡配置

1,前提nginx安装完成;如果不知道,可以请见http://blog.xuahua.com/articles/2016/08/24/1472024453381.html

示例Nginx安装目录为 /usr/local/nginx

2,jdk,tomcat安装完成。

下面要讲的是配置nginx 与tomcat的负载配置;本次示例使用的域名为 blog.xuahua.com

nginx的配置

/usr/local/nginx/conf/nginx.conf

user          root;
worker_processes  10;

#error_log  /var/log/nginx/error.log;
#error_log  /var/log/nginx/error.log  notice;
#error_log  /var/log/nginx/error.log  info;
error_log /data/logs/nginx/error.log error;

pid        /var/run/nginx.pid;


events {
    use epoll;
    worker_connections  65535;
}


http {
    include      mime.types;
    default_type  application/octet-stream;
        server_names_hash_bucket_size 128;
        #client_header_buffer_size 32k;
        #large_client_header_buffers 4 32k;
        #client_max_body_size 64m;
        #client_body_buffer_size 256k;
        sendfile on;
        tcp_nopush     on;
        keepalive_timeout 60;
        tcp_nodelay on;
        client_header_timeout   3m;
        client_body_timeout     3m;
        send_timeout    3m;

#FastCGI相关参数是为了改善网站的性能:减少资源占用,提高访问速度。下面参数看字面意思都能理解。
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 128k;
#
##gzip模块设置
gzip on; #开启gzip压缩输出
gzip_min_length 1k; #最小压缩文件大小
gzip_buffers 4 16k; #压缩缓冲区
gzip_http_version 1.0; #压缩版本(默认1.1,前端如果是squid2.5请使用1.0)
gzip_comp_level 2; #压缩等级
gzip_types text/plain application/x-javascript text/css application/xml;
##压缩类型,默认就已经包含text/html,所以下面就不用再写了,写上去也不会有问题,但是会有一个warn。
gzip_vary on;
##limit_zone crawler $binary_remote_addr 10m; #开启限制IP连接数的时候需要使用
##跨域访问
# add_header Access-Control-Allow-Origin *;
# add_header Access-Control-Allow-Headers X-Requested-With;
# add_header Access-Control-Allow-Methods GET,POST,OPTIONS;

             proxy_redirect off ;
             proxy_set_header Host $host;
             proxy_set_header X-Real-IP $remote_addr;
             proxy_set_header REMOTE-HOST $remote_addr;
             proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
             client_max_body_size 50m;
             client_body_buffer_size 256k;
             proxy_connect_timeout 30;
             proxy_send_timeout 30;
             proxy_read_timeout 60;
             proxy_buffer_size 256k;
             proxy_buffers 4 256k;
             proxy_busy_buffers_size 256k;
             proxy_temp_file_write_size 256k;
 proxy_next_upstream error timeout invalid_header http_500 http_503 http_404;
             proxy_max_temp_file_size 128m;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

   # access_log  /var/log/nginx/access.log  main;

    access_log  /data/logs/nginx/access.log  main;

 upstream blog.xuahua.com{
        server 10.116.21.192:9090;
        server 10.116.21.192:9090;
}

 

重点 upstream的server配置

server 10.116.21.192:9090 指向 tomcat的9090端口

server 10.116.21.193:9090 指向内网193 tomcat的9090端口。

 

而且针对server 的配置还有更多的参数,可根据实际情况增加。

 

nginx的https配置可见  http://blog.xuahua.com/articles/2016/03/01/1456812606792.html

liunx下的Nginx安装

1,nginx 下载
 
wget  http://nginx.org/download/nginx-1.9.9.tar.gz
先 安装pcre,libevent, OpenSSL
>yum install pcre*
>yum install libevent*
>yum install openssl*
 
解压nginx,进入目录。
>./configure   --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module   --with-pcre=pcre源目录
pcre 指向源文件目录,而不是编译后的目录

                        # --with-http_stub_status_module:这个模块用于获取nginx自上次启动以来的工作状态,非核心模块

                       # --with-http_ssl_module     :HTTPS 使用

                       # 上文中的--with-cc-opt='-O2' --with-cpu-opt=opteron 这是编译器优化,目前最常用的是-02 而不是3.后面对应CPU的型号,可参照:http://wiki.gentoo.tw/index.php/HOWTO_CFLAG

 

> make && make install

pcre-7.8-7.el6.x86_64
pcre-devel-7.8-7.el6.x86_64
pcre-static-7.8-7.el6.x86_64

代理配置

  proxy_redirect off ;
             proxy_set_header Host $host;
             proxy_set_header X-Real-IP $remote_addr;
             proxy_set_header REMOTE-HOST $remote_addr;
             proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
             client_max_body_size 50m;
             client_body_buffer_size 256k;
             proxy_connect_timeout 30;
             proxy_send_timeout 30;
             proxy_read_timeout 60;
             proxy_buffer_size 256k;
             proxy_buffers 4 256k;
             proxy_busy_buffers_size 256k;
             proxy_temp_file_write_size 256k;
             proxy_next_upstream error timeout invalid_header http_500 http_503 http_404;
             proxy_max_temp_file_size 128m;

 

        2.1 pcre 编译安装  安装pcre 让nginx支持rewrite 方便以后所需

 

        wget ftp://ftp.csx.cam.ac.uk//pub/software/programming/pcre/pcre-8.37.tar.gz
        tar zxvf pcre-8.37.tar.gz
        cd pcre-8.37/
       ./configure --prefix=/usr/local/pcre
编译完后可以执行make check进行测试(这一步非必须)
        make
  1. Skipping pcregrep UTF-8 tests: no UTF-8 support in PCRE library  
  2. Testing pcregrep newline settings  
  3. PASS: RunGrepTest  
  4. ==================  
  5. All 5 tests passed  
  6. ==================  
  7. make[2]: Leaving directory `/usr/local/pcre-8.32'  
  8. make[1]: Leaving directory `/usr/local/pcre
    加上对utf-8的支持可以在./configuration时加上参数: ./configure --enable-utf8  
make install
 
nginx -t -c /usr/local/nginx/conf/nginx.conf
    2.2 libevent 编译安装

        # wget http://www.monkey.org/~provos/libevent-2.0.12-stable.tar.gz
        # tar zxf libevent-2.0.12-stable.tar.gz 
        # cd libevent-2.0.12-stable
        #./configure  --prefix=/usr/local/lib
        # make && make install
     

githup-使用手记

经常使用SVN,身边也经常听人说githup如何高大上,今天有时间上来也折腾一下。。

1,首先注册 https://github.com

2,创建 repository 这个好像免费只能是public的。。不管他,先创建一个 xuahuaBlog

3,配置member ,这里好像需要邮箱认证通过才可以。我使用的是 service@xuahua.com

4,在客户端 liunx 上面默认安装了git..如果没有安装的请先安装。

root> mkdir xuahua //新建一个本地目录,准备当做本地仓库

root> git clone https://github.com/xuahuaBlog/home.git  //检出githup上面的仓库

root> git checkout https://github.com/xuahuaBlog/home.git home //切换仓库

root>git  config --global user.name xxx //githup账号

root>git config --global user.email xxx@xxx.com //邮箱账号

root >  git remote set-url origin https://xxx@github.com/xuahuaBlog/project.git

root>git push //默认是 origion/master

password> //会弹出来提示你输入密码

输入密码,提交,即可在githup上面看到本地仓库新增加的文件了。。

整个流程比较简单,但是已经通过了。

hh

hibnerate-createSQLQuery返回自定义对象 有更新!

SQLQuery query = createSQLQuery(sql, values).addEntity(XXX.class);
query.list();

或者

SQLQuery query = createSQLQuery(sql, values);
		
		List<Map<String,Object>> list = query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).setFirstResult(startIndex).setMaxResults(pageSize).list();
		List rlist =  new ArrayList();
		if(list!=null && !list.isEmpty()){
			for(Map<String,Object> m : list){
				try {
					Object obj = MapBeanUtils.toObject(clazz, m);
					rlist.add(obj);
				} catch (InstantiationException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}

nginx-最容易忽略的错误

场景:

当我访问子域名a.xxx 时,url 会自动跳转其他的子域名如admin.xxx ..

排查:

1,我怀疑工程代码里面做了跳转,检查所有代码发现并无此问题。(排除)

2,工程没有,那就是Nginx转发的问题。于是检查配置,

发现在nginx.conf 文件中,引入子域名的配置时,指定 include vhosts/sites_*.conf; 

但是在vhosts目录,访问的子域名 a.xxx 配置文件 为 sites_a.xx 

并不是指定的sites_*.conf 格式,导致Nginx并未生效此子域名配置。

才会导致访问子域名 a.xxx时,会跳转到一个其他的子域名。

原因:

nginx 引入子域名并未导入,只是在nginx.conf 中配置了upstream 才会导致可以访问,但是跳转又不正常。

 

以此为记!

java并发编程之栅栏(CyclicBarrier)与闭锁(Latch) 有更新!

如果想实现所有的线程一起等待某个事件的发生,当某个事件发生时,所有线程一起开始往下执行的话,有什么好的办法吗?

方法1,栅栏CyclicBarrier

方法2 ,闭锁 Latch


栅栏与闭锁(Latch)的差异在于:


    闭锁   Latch 


一种同步方法,可以延迟线程的进度直到线程到达某个终点状态。通俗的讲就是,一个闭锁相当于一扇大门,在大门打开之前所有线程都被阻断,一旦大门打开所有线程都将通过,

但是一旦大门打开,所有线程都通过了,那么这个闭锁的状态就失效了,门的状态也就不能变了,只能是打开状态。

也就是说闭锁的状态是一次性的,它确保在闭锁打开之前所有特定的活动都需要在闭锁打开之后才能完成。


   应用场景:


  • 确保某个计算在其需要的所有资源都被初始化之后才继续执行。二元闭锁(包括两个状态)可以用来表示“资源R已经被初始化”,而所有需要R的操作都必须先在这个闭锁上等待。
  • 确保某个服务在其依赖的所有其他服务都已经启动之后才启动。
  • 等待直到某个操作的所有参与者都就绪在继续执行。(例如:多人游戏中需要所有玩家准备才能开始)


            CountDownLatch是JDK 5+里面闭锁的一个实现,允许一个或者多个线程等待某个事件的发生。CountDownLatch有一个正数计数器,countDown方法对计数器做减操作,await方法等待计数器达到0。

         所有await的线程都会阻塞直到计数器为0或者等待线程中断或者超时。


         代码例子: 

                   

    栅栏  CyclicBarrier


 栅栏类似于闭锁,它能阻塞一组线程直到某个事件发生。栅栏与闭锁的关键区别在于,所有的线程必须同时到达栅栏位置,才能继续执行。闭锁用于等待事件,而栅栏用于等待其他线程。


     场景:

 应用一些协议,比如几个家庭成员决定在某个地方集合,所有人在6:00在某地集合,到了以后要等待其他人,之后才能讨论去哪里吃饭。

 并行迭代,将一个问题分成很多子问题,当一系列的子问题都解决之后(所有子问题线程都已经await()),此时将栅栏打开,所有子问题线程被释放,而栅栏位置可以留着下次使用。



  例子:两个分别关于CountDownlatch和CyclicBarrier的例子

1、CountDownLatch


    有三个工人在为老板干活,这个老板有一个习惯,就是当三个工人把一天的活都干完了的时候,他就来检查所有工人所干的活。记住这个条件:三个工人先全部干完活,老板才检查。所以在这里用Java代码设计两个类,Worker代表工人,Boss代表老板,具体的代码实现如下:


    工人:


              

package LatchAndCyclicBarrier;

import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class Work implements Runnable{


        private CountDownLatch downLatch;
        private String name;

        public Work(CountDownLatch downLatch, String name){
            this.downLatch = downLatch;
            this.name = name;
        }

        public void run() {
            this.doWork();
            try{
                TimeUnit.SECONDS.sleep(new Random().nextInt(10));
            }catch(InterruptedException ie){
            }
            System.out.println(this.name + "活干完了!");
            this.downLatch.countDown();

        }

        private void doWork(){
            System.out.println(this.name + "正在干活!");
        }

    }


老板:

 

package LatchAndCyclicBarrier;

import java.util.concurrent.CountDownLatch;

public class Boss implements Runnable{

        private CountDownLatch downLatch;

        public Boss(CountDownLatch downLatch){
            this.downLatch = downLatch;
        }

        public void run() {
            System.out.println("老板正在等所有的工人干完活......");
            try {
                this.downLatch.await();
            } catch (InterruptedException e) {
            }
            System.out.println("工人活都干完了,老板开始检查了!");
        }

    }

测试代码: 




package LatchAndCyclicBarrier;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestLatch {

    public static void main(String[] args) {
            ExecutorService executor = Executors.newCachedThreadPool();

            CountDownLatch latch = new CountDownLatch(3);

            Work w1 = new Work(latch,"张三");
            Work w2 = new Work(latch,"李四");
            Work w3 = new Work(latch,"王二");

            Boss boss = new Boss(latch);

            executor.execute(w3);
            executor.execute(w2);
            executor.execute(w1);
            executor.execute(boss);

            executor.shutdown();
        }

    }
执行结果:
李四正在干活!
老板正在等所有的工人干完活......
王二正在干活!
张三正在干活!
李四活干完了!
王二活干完了!
张三活干完了!
工人活都干完了,老板开始检查了!

2、CyclicBarrier


接着上面的例子,还是这三个工人,不过这一次,这三个工人自由了,老板不用检查他们任务了,他们三个合作建桥,有三个桩,每人打一个,同时打完之后才能一起搭桥(搭桥需要三人一起合作)。也就是说三个人都打完桩之后才能继续工作。

   








package LatchAndCyclicBarrier;

import java.util.concurrent.CyclicBarrier;

public class CycWork implements Runnable {


        private CyclicBarrier cyclicBarrier ;
        private String name ;

        public CycWork(CyclicBarrier cyclicBarrier,String name)
       {
               this .name =name;
               this .cyclicBarrier =cyclicBarrier;
       }

        @Override
        public void run() {
               // TODO Auto-generated method stub

              System. out .println(name +"正在打桩,毕竟不轻松。。。。。" );

               try {
                     Thread. sleep(5000);
                     System. out .println(name +"不容易,终于把桩打完了。。。。" );
                      cyclicBarrier .await();

              } catch (Exception e) {
                      // TODO: handle exception
                     e.printStackTrace();
              }

              System. out .println(name +":其他逗b把桩都打完了,又得忙活了。。。" );


       }

}
测试程序:
 
package LatchAndCyclicBarrier;

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CycTest {

        public static void main(String[] args)
       {
              ExecutorService executorpool=Executors. newFixedThreadPool(3);
              CyclicBarrier cyclicBarrier= new CyclicBarrier(3);

              CycWork work1= new CycWork(cyclicBarrier, "张三" );
              CycWork work2= new CycWork(cyclicBarrier, "李四" );
              CycWork work3= new CycWork(cyclicBarrier, "王五" );

              executorpool.execute(work1);
              executorpool.execute(work2);
              executorpool.execute(work3);

              executorpool.shutdown();

       }

}
运行结果:
 
李四正在打桩,毕竟不轻松。。。。。
张三正在打桩,毕竟不轻松。。。。。
王五正在打桩,毕竟不轻松。。。。。
李四不容易,终于把桩打完了。。。。
张三不容易,终于把桩打完了。。。。
王五不容易,终于把桩打完了。。。。
王五:其他逗b把桩都打完了,又得忙活了。。。
李四:其他逗b把桩都打完了,又得忙活了。。。
张三:其他逗b把桩都打完了,又得忙活了。。。 
 

CountDownlatch和CyclicBarrierde 源码部分

1、CountDownLatch中的两个关键方法

 public void countDown() {    //对计数器减一 表示有一个事件已经发生了
        sync.releaseShared(1); 
    }
public void await() throws InterruptedException { //等到计数器为0
        sync.acquireSharedInterruptibly(1);
    }
await方法调用了AbstractQueuedSynchronizer中的acquireSharedInterruptibly
 
public final void acquireSharedInterruptibly (int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }
public final boolean releaseShared (int arg) {
        if (tryReleaseShared(arg)) {   
            doReleaseShared();
            return true ;
        }
        return false ;
    }
protected boolean tryReleaseShared (int arg) {
        throw new UnsupportedOperationException();
    }
2、CyclicBarrier中的await()方法
 
public int await() throws InterruptedException, BrokenBarrierException {
        try {
            return dowait(false, 0L);
        } catch (TimeoutException toe) {
            throw new Error(toe); // cannot happen;
        }
    }
 private int dowait(boolean timed, long nanos)
        throws InterruptedException, BrokenBarrierException,
               TimeoutException {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            final Generation g = generation;

            if (g.broken)
                throw new BrokenBarrierException();

            if (Thread.interrupted()) {
                breakBarrier();
                throw new InterruptedException();
            }

           int index = --count;
           if (index == 0) {  // tripped
               boolean ranAction = false;
               try {
                   final Runnable command = barrierCommand;
                   if (command != null)
                       command.run();
                   ranAction = true;
                   nextGeneration();
                   return 0;
               } finally {
                   if (!ranAction)
                       breakBarrier();
               }
           }

            // loop until tripped, broken, interrupted, or timed out
            for (;;) {
                try {
                    if (!timed)
                        trip.await();
                    else if (nanos > 0L)
                        nanos = trip.awaitNanos(nanos);
                } catch (InterruptedException ie) {
                    if (g == generation && ! g.broken) {
                        breakBarrier();
                        throw ie;
                    } else {
                        // We‘re about to finish waiting even if we had not
                        // been interrupted, so this interrupt is deemed to
                        // "belong" to subsequent execution.
                        Thread.currentThread().interrupt();
                    }
                }

                if (g.broken)
                    throw new BrokenBarrierException();

                if (g != generation)
                    return index;

                if (timed && nanos <= 0L) {
                    breakBarrier();
                    throw new TimeoutException();
                }
            }
        } finally {
            lock.unlock();
        }
    }
上面dowait方法中有一个index,index=--count而count的值在源码中来自

count = parties;
提到 parties就不得不看看构造函数了 

public CyclicBarrier(int parties) {
        this(parties, null);
    }
如上例子,我们构造了CyclicBarrier(3)那么此时的 count值为3,接着dowait源码,当index==0时,后面执行的

final Runnable command = barrierCommand;
其实是可以设置的,这个Runnable可以传进来,当我们希望所有线程都达到某一时刻之后,用什么线程执行接下来的工作,
当没有传Runnable进来时,就继续执行(唤醒其他线程),否则就runnable.run()(唤醒其他线程之前执行) 
原文:http://blog.csdn.net/yujin753/article/details/46125283


java进阶之一生成二维码

生成二维码图片,指定内容,生成图片提供下载。


/**
	 * 生成二维码并返回图片路径
	 * @param domain
	 * @param SERVER_PATH
	 * @param filepath
	 * @param content
	 * @param imgPath
	 * @param filename
	 * @param needCompress
	 * @return
	 * @throws Exception
	 * 
	 * String path_ = QRCodeUtil.buildcodeurl(Constants.getConfigkey("upload.image.base64.domain"),
					Constants.getConfigkey("common.file.path"),"/qrcode/user/",
					Constants.getConfigkey("h5.cus.url")+"/reg?cid="+o.getId()
					, null,o.getId()+".jpg");
	 */
	public static String buildcodeurl(String domain,String SERVER_PATH,String filepath,String content, String imgPath,String filename) throws Exception{
		String path = SERVER_PATH+filepath;
		QRCodeUtil.encode(content, imgPath, path,filename, true);
		String path_ = domain+filepath+filename;
		return path_;
		
	}

/**
	 * 生成二维码(内嵌LOGO)
	 * 
	 * @param content
	 *            内容
	 * @param imgPath
	 *            LOGO地址
	 * @param destPath
	 *            存放目录
	 * @param needCompress
	 *            是否压缩LOGO
	 * @throws Exception
	 */
	public static void encode(String content, String imgPath, String destPath,String filename,
			boolean needCompress) throws Exception {
		BufferedImage image = QRCodeUtil.createImage(content, imgPath,
				needCompress);
		mkdirs(destPath);
		String file = filename;
		File f = new File(destPath+"/"+file);
		if(!f.getParentFile().exists()){
			f.getParentFile().mkdirs();
		}
		ImageIO.write(image, FORMAT_NAME,f);
	}

整个源文件下载  http://file.xuahua.com/blog/2016/0806/QRCodeUtil.java


公告

喧哗博客--繁华过后的沉寂--技术经验分享^-^
Copyright (c) 2009-2019, b3log.org & hacpai.com