1、源代码
normandy.shared.trunk: svn co http://svn.alibaba-inc.com/repos/ali_platform/normandy/shared/trunk
normandy.server:  svn co http://svn.alibaba-inc.com/repos/ali_platform/normandy/app/server/trunk/normandy.server
2、数据库
  10.20.36.26开发库 10.20.129.167测试库 normandy/normandy,Schema:normandy_dev/normandy_test
对用户授权:
GRANT ALL PRIVILEGES ON *.* TO 'normandy'@'localhost' IDENTIFIED BY 'normandy' WITH GRANT OPTION;
GRANT ALL PRIVILEGES ON *.* TO 'normandy'@'%' IDENTIFIED BY 'normandy' WITH GRANT OPTION;
 
3、编译以及环境搭建
<1> 先编译normandy.shared.trun, 再编译normandy.server, 最后在normandy.server/target/normandy.server-0.1.0/bin下面使用./start-normandy.sh进行启动。 
<2>以debug的方式启动程序
./ start-normandy.sh debug
debug启动端口 normandy.server.debug.port              = 9020
<3>以Debug方式远程调试程序
首先:必须使用debug参数开启debug端口9020
其次:在入口server的ConfigServiceImpl类的方法上面设置断点, 远程连接服务器
最后,在程序中以java或者debug方式启动客户端(即客户端是否需要开启debug模式,与服务器是否是debug模式没关系;同样服务端是否开启debug与客户端是否开启也没关系),则此时会在设置断点的地方停止下来等待继续。
断开远程端口:在eclipse的debug视图下面,点击类时出现红色的‘Terminal’按钮即可。
 
4、提供的服务
 
 
5、架构分析
 
6、业务
 
【注意】
1、注意数据的正确性
config_key, config_value
2、对Transaction进行事务各种管理,方便测试
首先:添加依赖管理
 
  
  1. <dependency> 
  2.         <groupId>com.alibaba.external</groupId> 
  3.         <artifactId>sourceforge.spring.modules.aspects</artifactId> 
  4.         <version>2.5.6</version> 
  5. </dependency> 
其次:增加切面方法
 
  
  1. package com.alibaba.normandy.server.core.service.util; 
  2.  
  3. import org.aspectj.lang.ProceedingJoinPoint; 
  4. import org.aspectj.lang.annotation.After; 
  5. import org.aspectj.lang.annotation.AfterThrowing; 
  6. import org.aspectj.lang.annotation.Around; 
  7. import org.aspectj.lang.annotation.Aspect; 
  8. import org.aspectj.lang.annotation.Before; 
  9. import org.aspectj.lang.annotation.Pointcut; 
  10.  
  11. @Aspect 
  12. public class TransactionInjectionServiceUtil { 
  13.      
  14.     @Pointcut("execution(public * com.alibaba.normandy.server.core.service.impl.*.*(..))"
  15.     private void pointcutService(){ 
  16.     } 
  17.      
  18.     @Pointcut("execution(public * com.alibaba.normandy.server.core.service.dao.*.*(..))"
  19.     private void pointcutDao(){ 
  20.     } 
  21.      
  22.     @Before("pointcutService()"
  23.     public void beforeServiceActions(){ 
  24.         //before action 
  25.         System.out.println("beforeServiceActions invoked!"); 
  26.          
  27.     } 
  28.     @After("pointcutService()"
  29.     public void afterServiceActions(){ 
  30.         //after action 
  31.         System.out.println("afterServiceActions invoked!");  
  32.     } 
  33.     @Around("pointcutService()"
  34.     public void aroundServiceActions(ProceedingJoinPoint pjp){ 
  35.         //before action 
  36.         System.out.println("before aroundServiceActions invoked!");  
  37.          
  38.         try { 
  39.             pjp.proceed(); 
  40.         } catch (Throwable e) { 
  41.             e.printStackTrace(); 
  42.         } 
  43.          
  44.         //after action 
  45.         System.out.println("after aroundServiceActions invoked!");  
  46.     } 
  47.      
  48.     @AfterThrowing("pointcutService()"
  49.     public void exceptionServiceActions(){ 
  50.         System.out.println("exceptionServiceActions invoked!");  
  51.         throw new RuntimeException("exception in service, will rollback!"); 
  52.     } 
增加配置文件:normandy-transactionService-aop.xml,在配置文件中添加如下配置
 
  
  1. <aop:aspectj-autoproxy /> 
  2. <bean id="transactionInjectionServiceUtil" class="com.alibaba.normandy.server.core.service.util.TransactionInjectionServiceUtil" /> 
在整个容器的加载地方指定要加载normandy-transactionService-aop.xml配置文件。在applicationContext-normandy-server.xml中进行添加:
 
  
  1. <import resource="classpath:spring/normandy-transactionService-aop.xml" /> 
 
最后:启动server服务器端,再开始远程调用
3、在pub时,必须要先创建application和domain的记录
例如:minas@us-domain:alibaba.platform.minas.basic.setting.workdir, 其中application为:minas, domain为:us-domain, 后面为真正的key值。 每次发布时,整个长度限制在255个字符之内,一般情况下是以'.'进行分割,也可以支持'_'。
4、定点推送
在发布的时候可以先考虑定点推送一个k/v给某台机器的某个端口进行验证,如果成功则可以大规模的推送到整个集群中。使用方法如下: 
String addressList = "10.20.30.40:8080"; client.publish(key, value, addressList);
(1)定点发布只修改config_value_change_event表,而不修改config_key和config_value表。
(2)其中的fired_server_ip字段记录了normandy集群中完成publish机器的server的ip地址。
 
5、发布保证最终的一致性
pub的的key/value键值对,会保证最终的一致性,但是需要处理经历事件的过程,正常情况在5秒之内完成。所以意味着:马上发的,马上去订阅可能订阅不了。
6、在多个client同时不断发布同一个Key,不同的value时,可能存在异常:com.alibaba.normandy.server.core.service.exception.ConcurrentConflictException:
这是由于获取了version之后都做插入的动作。服务器不应该去决定服务器是否重试,而是应该为客户端抛出异常,由客户端来做处理。
7、数据库设计
select APPLICATION_ID, DOMAIN_ID, uid,AGGREGATE_TYPE,enabled, globe_uid from config_key;
select CONFIG_KEY_ID, value,type,VERSION,publisher from config_value;
application:关于应用的内容,例如dubbo、napoli
domain:关于域的内容,例如:杭州域 hz-domain或者美国域 us-domain
normandy_server:关于normandy server自身的相关信息,其中 status的含义为: 1表示normandy server为stop,2表示normandy server为start,3为overlapped,但是3不会写到数据库。
8、normandy server允许连接数设置
 
在配置文件normandy-server-core-services.xml中有参数${connection.maxConnectionCount}
在antx.properties中,通过normandy.server.connection.max.count进行传递
 
 
9、多线程下面publish场景,出现java.util.ConcurrentModificationException
非append接口,直接抛给客户端
如果是append接口,server负责重试到成功为止
10、由于publish和publishAppend的语义的区别,所以不允许放在一起针对同一个key进行使用。
publish:config_value的type字段为 com.alibaba.normandy.common.domain.SimpleConfigValue,publisher值为 发布者ip:端口
publishAppend:config_value的type字段为 com.alibaba.normandy.common.domain.CombinedConfigValue,publisher值为 serverip:端口- 发布者ip:端口+uid
 11、联合查询
查询application、domain、key、value: select a.name, d.name, uid, value , version  from domain d, application a, config_key k, config_value v where k.id = v.CONFIG_KEY_ID;
select a.name, d.name, uid, value, version from domain d, application a, config_key k, config_value v where k.id = v.CONFIG_KEY_ID;
12、normandy的key、value长度限制:2011-06-23
(1)调整key长度范围为255,而不是256
(2)config_key表的uid长度为200(key去除domain、application、@、:后剩下的部分),存在问题,需要修改为255
(3)value设置较大时,例如长度为2048时,则触发了dubbo的重连,存在并发修改异常;或者触发ProtocolClientException