test21

jboss集群session复制原理:

jboss session复制是jboss session同步的一种实现。原理是在各Jboss节点间建立横向联系,每个节点都将本节点的session变化同步到其他所有节点上。

jboss的session复制与HTTP集群是相互配合、相互独立的两个系统。session复制是节点间的横向联系,HTTP集群是负载均衡器与节点的纵向联系。

   10.0.2.203 – 安装JDK 1.6,JBoss 7,JBoss节点名称为jboss1

   10.0.2.202 – 安装JDK 1.6,JBoss 7,JBoss节点名称为jboss2


   不过在编译nginx的时候给nginx打上nginx_upstream_check_module补丁,在网上下载这个模块,解压和nginx放于/usr/local/src/目录下,进入这个目录下的nginx解压后的目录,编辑 auto/cc/gcc文件,(关闭debug)

# debug
#CFLAGS="$CFLAGS -g"  注释掉这行,去掉 debug 模式编译,编译以后程序只有几百k
再编辑 src/core/nginx.h文件,
改成这样:#define NGINX_VER          "nginx"  修改此行,去掉后面的“NGINX_VERSION”,为了安全,这样编译后外界无法获取程序的版本号

最后打补丁:

patch -p1 <  /usr/local/src/nginx_upstream_check_module-master/check_1.2.6+.patch,

然后 ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --add-module=/usr/local/src/nginx_upstream_check_module-master --add-module=/usr/local/src/nginx-sticky-module-1.0/

#使用nginx_upstream_check_module 模块对后端server进行检测

再make  && make install

以下实验注意iptables 和 selinux 的影响。

安装jdk和jboss 此处就不多说了,jboss不需要修改

 /usr/local/jboss-4.2.2.GA/server/all/deploy/jboss-web.deployer 目录下的

 server.xml文件的 <Connector port="8080" address="${jboss.bind.address}"默认地址

a:下面是nginx的配置:

user  nginx nginx;

worker_processes  2;

events {

       use epoll;

   worker_connections  1024;

}

http {

       upstream jboss {

       sticky;        #添加此项实现session的sticky,即一个客户端的访问会被nginx转发到同一台jboss实例进行处理

       server 10.0.2.203:8080 weight=1 max_fails=3 fail_timeout=60s;

       server 10.0.2.202:8080 weight=1 max_fails=3 fail_timeout=60s;

       check interval=3000 rise=2 fall=5 timeout=1000;

       }

   #interval检测间隔时间,单位为毫秒。

   #rsie请求2次正常的话,标记此realserver的状态为up。

   #fall表示请求5次都失败的情况下,标记此realserver的状态为down。

   #timeout为超时时间,单位为毫秒。

   include       mime.types;

   default_type  application/octet-stream;



location /status {

       stub_status on;

       access_log off;

       }


 location ~ \.jsp$ {

       #  root html;

         index  index.jsp;

         proxy_pass http://jboss;

       }

b:jboss的配置同 上篇的 “使用apache的mod_jk实现jboss负载均衡

   参考此篇http://smartest.blog.51cto.com/3585938/1340219

c:启动10.0.2.203和10.0.2.202主机的jboss实例,然后启动10.0.2.90的nginx server

客户端 浏览器访问 10.0.2.90/status

165414783.jpg

如果使用nginx_upstream_check_module 模块,则需要修改nginx配置文件

location /status {

       #stub_status on;      #关闭nginx自身的status状态统计

       check_status;

       access_log off;

       }

然后浏览器访问 10.0.2.90/status

175459528.jpg

可以看到默认使用tcp进行check,可以修改成http,

check interval=3000 rise=2 fall=5 timeout=1000 type=http;


jboss 的配置参考 上篇“使用apache的mod_jk实现jboss负载均衡

http://smartest.blog.51cto.com/blog/3585938/1340219


客户端访问 后端jboss 10.0.2.90/index.jsp

165645494.jpg

165924575.jpg

nginx默认采用简单的轮询调度算法将请求转发到后端的jboss实例。

这个类似于apache的mod_proxy模式,每次都将当前所有的session复制到要访问的jboss实例(没有sticky的情况),jboss默认采用UDP方式,这对于带宽有影响。

注意:当session复制时,只能10.0.2.202(jboss2)到10.0.2.203,不能10.0.2.203到10.0.2.202,待后续解决。

问题:

取消nginx的sticky配置,每一次请求都会复制session,当一台jboss实例停掉后,不影响session,当这台jboss实例恢复后,恢复的jboss提示“ERROR [JBossCacheManager] Cannot add session with id=wxYgIkmw3KnEBn4xjSD1cA**.jboss1 because it is invalid”,原正常jboss提示“Possible concurrency problem: Replicated version id 1 matches in-memory version for session wxYgIkmw3KnEBn4xjSD1cA**”。(在用mod_jk时也用这个问题)

<think>我们面对的问题:如何对包含数字的字符串进行自然排序,使得像"test2-01"排在"test11-12"之前(即按数字大小排序,而不是按字典序排序,因为字典序中'2'>'1',所以"test11"会排在"test2"前面)。自然排序(NaturalSort)是指人类通常对字符串排序的方式,即考虑字符串中的数字部分为数值大小,而非逐个字符比较。根据引用[1]中的提示,我们可以通过将字符串中的数字部分转换为数值类型来进行比较。具体来说,我们可以将字符串拆分成非数字和数字部分,然后对数字部分进行数值比较。在Java中,我们可以使用自定义Comparator来实现。例如,我们可以将每个字符串拆分成一系列的令牌(token),这些令牌交替地由非数字字符和数字字符组成。然后,我们逐个比较这些令牌:-如果两个令牌都是数字,则将它们转换为整数(或长整数等)进行比较。-如果一个是数字一个不是,那么我们可以将非数字令牌视为较小(或根据需求调整)。-如果两个都是非数字,则按字符串字典序比较。但是,注意我们的字符串格式是"test11-12",其中包含多个数字部分。我们需要对整个字符串进行拆分。我们可以使用正则表达式来拆分字符串,将字符串拆分为数字和非数字的序列。例如,使用正则表达式`(?<=\D)(?=\d)|(?<=\d)(?=\D)`可以匹配数字和非数字之间的边界。然而,在Java中,我们可以使用`Comparator.comparing`方法,并提供一个键提取器(keyextractor)来将每个字符串转换为一个可比较的键。我们可以使用一个自定义的函数来生成一个比较键,该键是一个由令牌组成的列表,每个令牌可以是字符串或数字。另一种方法是使用现成的自然排序工具类。例如,ApacheCommonsIO中的`FilenameUtils`类提供了自然排序的比较器,但如果我们不想引入外部库,可以自己实现。下面是一个自定义比较器的示例实现:```javaimportjava.util.Comparator;importjava.util.regex.Matcher;importjava.util.regex.Pattern;publicclassNaturalOrderComparatorimplementsComparator<String>{privatestaticfinalPatternNUMBER_PATTERN=Pattern.compile("\\d+");@Overridepublicintcompare(Strings1,Strings2){//使用正则表达式匹配数字部分Matcherm1=NUMBER_PATTERN.matcher(s1);Matcherm2=NUMBER_PATTERN.matcher(s2);intindex1=0;intindex2=0;while(true){//检查是否已经处理完两个字符串if(index1>=s1.length()&&index2>=s2.length()){return0;}elseif(index1>=s1.length()){return-1;}elseif(index2>=s2.length()){return1;}//查找下一个数字部分booleanfoundDigit1=m1.find(index1);booleanfoundDigit2=m2.find(index2);//比较当前非数字部分(从当前索引到数字开始的位置)if(foundDigit1&&foundDigit2){//比较非数字部分StringnonDigit1=s1.substring(index1,m1.start());StringnonDigit2=s2.substring(index2,m2.start());intnonDigitCompare=nonDigit1.compareTo(nonDigit2);if(nonDigitCompare!=0){returnnonDigitCompare;}//比较数字部分intnum1=Integer.parseInt(m1.group());intnum2=Integer.parseInt(m2.group());intnumCompare=Integer.compare(num1,num2);if(numCompare!=0){returnnumCompare;}//更新索引index1=m1.end();index2=m2.end();}elseif(!foundDigit1&&!foundDigit2){//都没有数字了,直接比较剩余部分returns1.substring(index1).compareTo(s2.substring(index2));}else{//一个有数字,一个没有,那么没有数字的字符串较小(或者我们可以将非数字部分与数字部分比较?但通常数字部分会被视为大于非数字?)//实际上,根据自然排序,通常数字部分在非数字部分之后,但这里我们简化:如果还有数字,那么数字部分大于非数字?但这样可能不对。//更合理的做法:将剩余部分按字符比较。//因此,我们直接比较剩余字符串。returns1.substring(index1).compareTo(s2.substring(index2));}}}}```但是,上述实现可能较复杂,且没有考虑数字前导零的情况(如"01"和"1")。在自然排序中,前导零通常不影响数值大小,但上述代码会解析为整数,因此"01"和"1"会被视为相同(都解析为1)。但如果我们希望保留前导零的字符串比较(比如在版本号中,有时前导零有意义),则不能这样处理。不过,根据问题中的例子,我们的字符串是"test2-01"和"test11-12",其中数字部分有前导零,但我们希望按数值排序,所以可以忽略前导零。然而,问题中的字符串格式是固定的吗?如果固定,我们也可以尝试按特定格式解析。但为了通用性,我们使用上述自然排序方法。另外,在Java8中,我们可以使用更简洁的方式来实现,例如使用`Comparator.comparing`和正则表达式拆分,然后对每个部分进行比较。下面是一个更简洁的实现(但可能效率稍低):```javapublicstaticComparator<String>naturalOrder(){return(s1,s2)->{//使用正则表达式将字符串拆分为数字和非数字的令牌String[]tokens1=s1.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");String[]tokens2=s2.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");intlen=Math.min(tokens1.length,tokens2.length);for(inti=0;i<len;i++){Stringtoken1=tokens1[i];Stringtoken2=tokens2[i];//如果两个令牌都是数字,则按数值比较if(token1.matches("\\d+")&&token2.matches("\\d+")){intnum1=Integer.parseInt(token1);intnum2=Integer.parseInt(token2);intcmp=Integer.compare(num1,num2);if(cmp!=0)returncmp;}else{//否则按字符串比较intcmp=token1.compareTo(token2);if(cmp!=0)returncmp;}}//如果共同部分都相同,则按长度returntokens1.length-tokens2.length;};}```注意:上述实现可能不够健壮,因为当拆分后的令牌数量不同时,我们只比较了共同长度的部分,然后按令牌数量排序。但自然排序要求:如果共同部分相同,则更长的字符串(剩余令牌)应该继续比较。不过,上面的实现将剩余部分视为整体(按令牌数量,而不是继续拆分比较)。所以我们需要改进:在共同部分比较后,如果有一个字符串还有令牌,那么我们应该继续比较,而不是直接返回令牌数量的差。改进版本:```javapublicstaticComparator<String>naturalOrder(){return(s1,s2)->{String[]tokens1=s1.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");String[]tokens2=s2.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");intlen=Math.min(tokens1.length,tokens2.length);for(inti=0;i<len;i++){Stringtoken1=tokens1[i];Stringtoken2=tokens2[i];if(token1.matches("\\d+")&&token2.matches("\\d+")){intnum1=Integer.parseInt(token1);intnum2=Integer.parseInt(token2);intcmp=Integer.compare(num1,num2);if(cmp!=0)returncmp;}else{intcmp=token1.compareTo(token2);if(cmp!=0)returncmp;}}//如果共同部分相同,则比较令牌数量(即长度)实际上不对,应该继续比较剩余令牌?//但实际上,由于拆分后令牌数量不同,我们无法直接比较剩余令牌(因为剩余令牌可能包含数字和非数字),所以应该继续拆分比较吗?//但我们已经将整个字符串拆分了,所以我们可以直接比较令牌数量:如果共同部分相同,那么令牌多的字符串应该更大吗?不一定,因为可能后面还有非数字部分。//所以,我们应该将剩余令牌按顺序继续比较?但是上面的循环已经比较了所有共同索引的令牌,剩下的令牌我们无法再拆分(因为已经拆分了),所以我们可以将剩余令牌连接起来作为一个字符串比较?//但这样又回到了字典序比较,可能不符合自然排序。//因此,我们改为:如果共同部分相同,则比较令牌数量,但这样不对。例如:"a1"和"a1b":拆分后tokens1=["a","1"],tokens2=["a","1","b"],共同部分相同,然后我们比较令牌数量,认为"a1"小于"a1b"(因为2<3),这是合理的吗?在自然排序中,较长的字符串应该更大,因为它是前者的扩展。//但是,如果剩余令牌是数字呢?例如:"a1"和"a01":实际上不会出现这种情况,因为"a01"会被拆分成["a","01"],而"a1"是["a","1"],在比较时,第一个令牌相同,第二个令牌都是数字,所以比较1和1(相等),然后令牌数量相同,则相等。但"a01"和"a1"在数值上相等,但字符串不同,所以应该相等吗?自然排序中,数值相等则认为相等。//因此,我们直接比较令牌数量:如果共同部分都相等,那么令牌数量多的字符串更大。这符合自然排序吗?考虑"a1"和"a1a":拆分后,共同部分(前两个令牌)相同,然后"a1a"多了一个令牌"a",所以"a1a"大于"a1",这符合字典序。//所以,我们返回令牌数量的比较。returntokens1.length-tokens2.length;};}```但是,这个实现在某些情况下可能不正确。例如:"1a"和"1":拆分后,tokens1=["1","a"],tokens2=["1"],共同部分第一个令牌相同,然后tokens1长度2>1,所以"1a">"1",但自然排序中,通常"1a"应该大于"1"吗?是的,因为"1"后面没有内容,而"1a"还有内容。所以,上述实现基本满足要求。然而,我们还可以使用现有的库,比如ApacheCommonsIO中的`NaturalOrderComparator`,或者Google的`Ordering.natural()`(Guava库)。如果允许使用第三方库,推荐使用。在Java中,如果我们使用StreamAPI,可以这样使用:```javaList<String>list=...;//包含"test11-12","test2-01","test3-32"list.sort(naturalOrder());```注意:上述自然排序比较器没有处理前导零(例如"01"和"1"会被视为相等,因为它们都解析为1)。但问题中的字符串有前导零(如"-01"),我们希望按数值排序,所以这样是可以的。现在,针对问题中的例子:原始列表:["test11-12","test2-01","test3-32"]字典序排序:test11-12,test2-01,test3-32->因为'test1'比'test2'小(因为字符'1'<'2'),所以test11-12会排在最前面,但我们希望test2-01在test11-12前面。使用自然排序后:"test2-01"->拆分成:["test","2","-","01"]->数字部分:2和01(解析为1)?注意:这里拆分后,第二个令牌是"2",第四个令牌是"01",但在比较时,我们按顺序比较令牌。"test11-12"->拆分成:["test","11","-","12"]比较过程:第一个令牌:都是"test"->相等第二个令牌:一个是"2"(数字),一个是"11"(数字)->比较2和11,2<11,所以"test2-01"<"test11-12"所以排序后:["test2-01","test3-32","test11-12"]->注意"test3-32"在自然排序中,第二个令牌是3,介于2和11之间,所以排序正确。但是,注意"test2-01"的第四个令牌是"01",而"test11-12"的第四个令牌是"12",但我们在比较第二个令牌时已经得出了结果,所以不会比较到第四个令牌。因此,我们实现了自然排序。另外,引用[1]中提到的方法:`Comparator.comparing(s->Integer.valueOf(s.getNum()))`,这是针对特定字段的(例如有一个对象的getNum方法返回字符串)。但我们的字符串是整体,所以需要整体比较,不能只提取一个字段。综上所述,我们可以使用自定义的自然排序比较器。在代码中,我们也可以使用现有的实现,例如Java中没有内置的自然排序比较器,但我们可以使用`String.CASE_INSENSITIVE_ORDER`之类的,但自然排序需要自定义。另外,在问题中,字符串格式是“名称+数字+横杠+数字”,我们也可以考虑按特定格式解析。例如,如果格式固定,我们可以用正则表达式提取前面的名称和两个数字,然后按第一个数字排序,再按第二个数字排序。但这样不够通用。因此,我们推荐自然排序算法。总结:使用自定义的Comparator,将字符串拆分成数字和非数字令牌,然后交替比较。注意:上述实现没有考虑负数(字符串中的负号)和浮点数,但问题中的例子只有整数。如果需要,可以扩展。最后,给出一个完整的Java8示例代码:```javaimportjava.util.Arrays;importjava.util.Comparator;importjava.util.List;publicclassNaturalSortExample{publicstaticvoidmain(String[]args){List<String>names=Arrays.asList("test11-12","test2-01","test3-32");names.sort(NaturalSortComparator.naturalOrder());System.out.println(names);//输出:[test2-01,test3-32,test11-12]}publicstaticclassNaturalSortComparator{publicstaticComparator<String>naturalOrder(){return(s1,s2)->{//使用正则表达式拆分String[]tokens1=s1.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");String[]tokens2=s2.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");for(inti=0;i<Math.min(tokens1.length,tokens2.length);i++){Stringtoken1=tokens1[i];Stringtoken2=tokens2[i];//如果两个令牌都是数字,则按数值比较if(token1.matches("\\d+")&&token2.matches("\\d+")){intnum1=Integer.parseInt(token1);intnum2=Integer.parseInt(token2);intcmp=Integer.compare(num1,num2);if(cmp!=0)returncmp;}else{intcmp=token1.compareTo(token2);if(cmp!=0)returncmp;}}returntokens1.length-tokens2.length;};}}}```运行上述代码,将得到正确排序。另外,关于引用[2]和引用[3],它们分别讨论了中文排序和字符串加密,与当前问题关系不大,因此不在此展开。因此,针对用户的问题,解决方案是使用自定义的自然排序比较器。§§相关问题§§1.自然排序算法在处理前导零(如"001"和"1")时会如何比较?2.如果字符串中包含负数(例如"-5"和"-10"),自然排序算法如何处理?3.在Java中,除了自定义比较器,还有哪些第三方库提供了自然排序功能?</think>### 包含数字的字符串自然排序解决方案 要实现包含数字的字符串列表的自然排序(如 `test2-01` 排在 `test11-12` 之前),需要特殊处理字符串中的数字部分。自然排序(Natural Sort)会识别字符串中的数字序列,并按数值大小而非字典序进行排序。以下是具体实现方法: #### Java 实现方案 ```java import java.util.Arrays; import java.util.Comparator; import java.util.List; public class NaturalSortExample { public static void main(String[] args) { List<String> names = Arrays.asList("test11-12", "test2-01", "test3-32"); // 使用自然排序算法 names.sort(new NaturalOrderComparator()); System.out.println(names); // 输出: [test2-01, test3-32, test11-12] } static class NaturalOrderComparator implements Comparator<String> { @Override public int compare(String a, String b) { // 将字符串拆分为数字和非数字片段 String[] tokensA = a.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)"); String[] tokensB = b.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)"); int length = Math.min(tokensA.length, tokensB.length); for (int i = 0; i < length; i++) { // 如果两个片段都是数字,按数值比较 if (tokensA[i].matches("\\d+") && tokensB[i].matches("\\d+")) { int numA = Integer.parseInt(tokensA[i]); int numB = Integer.parseInt(tokensB[i]); if (numA != numB) return numA - numB; } // 否则按字符串字典序比较 else { int cmp = tokensA[i].compareTo(tokensB[i]); if (cmp != 0) return cmp; } } return tokensA.length - tokensB.length; } } } ``` #### 关键点说明 1. **正则拆分**: `split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)")` 将字符串拆分为数字和非数字片段。 例如:`"test2-01"` → `["test", "2", "-", "01"]` 2. **数字解析**: 当片段为数字时(如 `"2"` 和 `"11"`),转换为整数后比较数值大小(`2 < 11`),而非字典序(`"11" < "2"` 是错误的)。 3. **混合比较**: - 优先比较相同位置的片段:`test` vs `test`(相等) → `2` vs `11`(数值比较) - 若所有片段均相同,较短的字符串排在前 #### Python 实现方案 ```python import re def natural_key(s): return [ int(token) if token.isdigit() else token for token in re.split(r'(\d+)', s) ] names = ["test11-12", "test2-01", "test3-32"] names.sort(key=natural_key) print(names) # 输出: ['test2-01', 'test3-32', 'test11-12'] ``` - `re.split(r'(\d+)', s)`:保留分隔符(数字部分),如 `"test2-01"` → `['test', '2', '-', '01', '']` - `int(token)`:将数字字符串转为整数,确保数值比较 #### 处理前导零 若需保留前导零(如 `"01"` 和 `"1"` 视为不同),可将数字片段按字符串比较: ```java // 修改比较器中的数字比较部分 if (tokensA[i].matches("\\d+") && tokensB[i].matches("\\d+")) { // 按字符串长度和字典序比较(保留前导零) if (tokensA[i].length() != tokensB[i].length()) { return tokensA[i].length() - tokensB[i].length(); } return tokensA[i].compareTo(tokensB[i]); } ``` ### 总结 - **自然排序核心**:分离字符串中的数字和非数字部分,对数字部分按数值比较。 - **跨语言适用**:Java 和 Python 均可通过拆分+类型转换实现。 - **特殊需求**:前导零处理需调整数字比较逻辑[^1]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值