您现在的位置是:主页 > news > 扬州做公司网站的公司/外贸建站与推广如何做

扬州做公司网站的公司/外贸建站与推广如何做

admin2025/5/31 18:09:50news

简介扬州做公司网站的公司,外贸建站与推广如何做,山东招标网官方网站,一个vps主机放两个网站 速度可配置性是一个好的应用程序的重要指标。我们常常需要实现类似能够运行时修改配置的功能。最近在开发一个中间层的服务程序,最终发布的方式是把代码打成jar包交给调用方使用。这个中间层服务需要一些配置信息,考虑了一下有几个基本的需求: 1…

扬州做公司网站的公司,外贸建站与推广如何做,山东招标网官方网站,一个vps主机放两个网站 速度可配置性是一个好的应用程序的重要指标。我们常常需要实现类似能够运行时修改配置的功能。最近在开发一个中间层的服务程序,最终发布的方式是把代码打成jar包交给调用方使用。这个中间层服务需要一些配置信息,考虑了一下有几个基本的需求: 1…

可配置性是一个好的应用程序的重要指标。我们常常需要实现类似能够运行时修改配置的功能。最近在开发一个中间层的服务程序,最终发布的方式是把代码打成jar包交给调用方使用。这个中间层服务需要一些配置信息,考虑了一下有几个基本的需求:

1. 在ja包中提供一个service-defalut.properties配置文件来提供全部的默认配置。这样的好处是尽量减少对调用方的侵入。调用方可以不提供额外的配置。

2. 调用方也可以提供一个service-site.properties配置文件来提供自定义的配置信息,可以覆盖默认配置

3. 在分布式系统中,希望提供一个在集群中全局可见的配置信息,比如可以在ZooKeeper中设置配置信息

4. 支持并发环境下运行时修改配置,并且可以立刻生效

5. 高性能访问配置信息

之前看过Hadoop的代码,Hadoop的org.apache.hadoop.conf.Configuration实现了1,2,4项需求,但是它访问配置信息的性能不高,原因是为了支持并发访问,对读写配置都采用了加锁的方式,锁的粒度是方法级的,会影响并发的性能。

大致说一下org.apache.hadoop.conf.Configuration的实现

1. 采用Properties来存储K-V的配置信息

2. 采用CopyOnWriteArrayList来保存默认的配置文件列表

3. 采用ArrayList来保存自定义的配置文件列表

4. 对上述3个共享对象的访问都采用了加锁的方式来访问,保证并发情况下的正确性

public class Configuration implements Iterable<Map.Entry<String,String>>,Writable {private ArrayList<Object> resources = new ArrayList<Object>();private static final CopyOnWriteArrayList<String> defaultResources =new CopyOnWriteArrayList<String>();private Properties properties;public static synchronized void addDefaultResource(String name) {if(!defaultResources.contains(name)) {defaultResources.add(name);for(Configuration conf : REGISTRY.keySet()) {if(conf.loadDefaults) {conf.reloadConfiguration();}}}}public synchronized void reloadConfiguration() {properties = null;                            // trigger reloadfinalParameters.clear();                      // clear site-limits}private synchronized void addResourceObject(Object resource) {resources.add(resource);                      // add to resourcesreloadConfiguration();}private synchronized Properties getProps() {if (properties == null) {properties = new Properties();loadResources(properties, resources, quietmode);if (overlay!= null) {properties.putAll(overlay);for (Map.Entry<Object,Object> item: overlay.entrySet()) {updatingResource.put((String) item.getKey(), UNKNOWN_RESOURCE);}}}return properties;}public String getRaw(String name) {return getProps().getProperty(name);}public void set(String name, String value) {getOverlay().setProperty(name, value);getProps().setProperty(name, value);this.updatingResource.put(name, UNKNOWN_RESOURCE);}}

org.apache.hadoop.conf.Configuration 在配置的数据来源上是灵活地,可以动态的添加。它的主要问题是锁太多,读写都加锁,严重影响了并发访问的性能。

简单分析一下这个需求的场景:

1. 基于配置文件的配置信息一般是在启动服务时已经配置好了,可以用static加载的方式一次加载,是线程安全的

2. 基于运行时修改配置信息,即写配置的情况非常小,比如把配置设置在ZooKeeper中,只有在需要修改时才会运行时修改,非常少的机会会去修改配置

3. 99%以上的场景是读配置信息,最好不要加锁

基于这几个需求,我写了一个简单的Configuration实现,可以实现一下功能:

1. 灵活支持多种配置信息来源

2. 支持运行时修改配置信息,并立刻生效

3. 写配置操作保证强一致性,不会丢失写的内容。写操作需要加锁。

4. 读配置操作保证最终一致性,减少了锁的粒度,在没有写配置的情况下是无锁的。这样大大地提高了并发情况下性能

代码如下,简单测试了一下,考虑不周全的地方欢迎来拍。主要考虑并发的地方有:

1. 采用ConcurrentHashMap来取代Properties保存配置内容,提高并发下的性能和保证正确性

2. 采用volatile标识properties属性,这样保证了在reloadConfiguration时设置properties = null的操作对读操作get()立刻可见

3. get()读操作时,使用了一个引用指向properties,而不是直接使用properties,这样可以在properties被设置成null时,get操作还能读取到旧的配置,保证下一次读时能读到最新内容,这里保证了最终一致性。只有在properties == null的情况下(有配置修改),get操作才有可能加锁去加载配置

4. set()写操作时加锁,这样保证同意时候只能一个线程去修改配置。set不会重新加载配置,ConcurrentHashMap保证了set的值能立刻被get读取到。

import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;/***	Configuration用来读写配置信息,支持运行时配置的修改,支持多种数据源的配置 *  可以通过addResource()来修改配置,也可以通过set()来修改配置,保证强一致性*  get()保证最终一致性,通过减小锁的粒度来提高性能,运行时如果不调用addResource(),是无锁的*/
public class Configuration {private static Configuration instance = new Configuration();private Configuration(){}public static Configuration getInstance(){return instance;}public static final String DEFAULT_CONFIG_FILE = "service-default.properties";public static final String SITE_CONFIG_FILE = "service-site.properties";private static List<String> defaultResources = new ArrayList<String>();private static void addDefaultResource(String name){if(!defaultResources.contains(name)){defaultResources.add(name);instance.reloadConfiguration();}}static{addDefaultResource(DEFAULT_CONFIG_FILE);addDefaultResource(SITE_CONFIG_FILE);}private List<Object> resources = new ArrayList<Object>();private volatile ConcurrentHashMap<String, String> properties;private synchronized void reloadConfiguration(){properties = null;}private synchronized ConcurrentHashMap<String, String> getProperites(){// 减小锁粒度,提高性能if(properties == null){// 不直接使用properties,防止 properties = new ConcurrentHashMap<String, String>();之后被get()直接获取到未设置的propertiesConcurrentHashMap<String, String> props = new ConcurrentHashMap<String, String>();loadResources(props, resources);properties = props;}return properties;}// 最常用的方法, 保证最终一致性public String get(String key){// 如果get时另外线程在addResource,将指向老的properties对象,取老的配置ConcurrentHashMap<String, String> p = properties;if(p == null){p = getProperites();}return p.get(key);}// set保证强一致性public synchronized void set(String key, String value){getProperites().put(key, value);}private void loadResources(ConcurrentHashMap<String, String> props, List<Object> resources){// 先加载defaultfor(String resource: defaultResources){loadResource(props, resource);}// 再加载自定义for(Object resource: resources){loadResource(props, resource);}}private void loadResource(ConcurrentHashMap<String, String> props, Object resource){if(props == null){return;}Properties newProps = new Properties();if(resource instanceof String){URL url = ResourceLoader.getResource((String)resource);if(url == null){return;}try {newProps.load(url.openStream());} catch (Exception e) {// quiet}}else if(resource instanceof InputStream){try {newProps.load((InputStream)resource);} catch (Exception e) {// quiet}}else if(resource instanceof URL){try {newProps.load(((URL)resource).openStream());} catch (Exception e) {// quiet}}else if(resource instanceof Properties){newProps = (Properties)resource;}for(Map.Entry<Object, Object> entry: newProps.entrySet()){props.put(entry.getKey().toString(), entry.getValue().toString());}}public void addResource(String obj){addResourceObject(obj);}public void addResource(URL obj){addResourceObject(obj);}public void addResource(InputStream obj){addResourceObject(obj);}public void addResource(Properties obj){addResourceObject(obj);}private synchronized void addResourceObject(Object obj){if(!resources.contains(obj)){resources.add(obj);}reloadConfiguration();}}

简单的测试代码 

import java.util.Properties;public class ConfigTest {public static void main(String[] args){final Consumer obj = new Consumer();new Thread(new Runnable(){@Overridepublic void run() {while(true){System.out.println(obj.getLogFile());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}).start();new Thread(new Runnable(){@Overridepublic void run() {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}Configuration config = Configuration.getInstance();config.set("log.file", "/data/A-service.log");}}).start();new Thread(new Runnable(){@Overridepublic void run() {try {Thread.sleep(4000);} catch (InterruptedException e) {e.printStackTrace();}Configuration config = Configuration.getInstance();Properties p = new Properties();p.put("log.file", "/data/B-service.log");config.addResource(p);}}).start();}private static class Consumer{Configuration config = Configuration.getInstance();public String getLogFile(){return config.get("log.file");}}
}