中國電動汽車產業展覽會

电动汽车是提高我国汽车产业竞争力、保障能源安全和发展低碳经济的重要途径,同时发展电动汽车也是我国汽车工业技术转型和培育战略性新兴产业的必然决择。
为深入贯彻《节能与新能源汽车产业发展规划(2012-2020)》和《“十二五”国家战略性新兴产业发展规划》等文件精神,培育战略性新兴产业,加快电动汽车产业化进程和示范推广普及应用步伐,引领产业发展,壮大产业集群,推动我国电动汽车产业快速健康发展。由重庆市商业委员会、中国汽车工程研究院、重庆市发展和改革委员会、重庆市社会科学院等单位举办的中国电动汽车产业展览会将于2013年3月在重庆举办。
本届活动以“绿色科技,畅想梦幻未来”为主题,紧紧围绕电动汽车产业发展,以展示展览为主线,力争通过万人试乘试驾、电动汽车爬坡拉力大赛、经销商大会,市长论坛、技术发展报告等活动。强化科技创新能力建设,提升产业核心竞争力,促进产业发展,加大电动汽车推广使用力度,积极发展配套产业,建立健全充换电等公共服务平台,完善销售流通渠道,抢占未来汽车产业战略制高点,进一步推动我国由汽车工业大国向汽车工业强国迈进。
中国电动汽车产业展览会
时间:2013年3月22-24日 地点:重庆国际博览中心

主办单位: 重庆市商业委员会 中国汽车工程研究院
重庆市发展和改革委员会 重庆社会科学院等
联合主办:博鳌国际汽车论坛组委会/中国化学与物理电源行业协会电源配件分会/中国化学与物理电源行业协会酸性蓄电池分会/ 北京汽车工程学会/河南省电动车辆工程协会/成都市新能源汽车产业发展联盟/佛山市南海区汽车行业协会/烟台市汽车工业协会/福建省汽车工业行业协会/广州汽车工业行业协会/湖北省汽车流通协会/南京汽车行业协会/泉州市汽车同业协会/陕西省汽车行业协会/陕西省汽车工程学会/四川省电力电子学会/四川省汽车产业协会/四川省汽车工程学会/威海市汽车流通行业协会/潍坊市汽车流通行业协会/无锡市机械汽车工业协会/厦门市出租汽车暨汽车租赁协会/重庆市电力行业协会/重庆市交通运输协会/重庆汽车工程学会/重庆市汽车摩托车运动协会等。
承办单位:重庆市立嘉会议展览有限公司
主要内容:
1、中国电动汽车产业展览会
本届活动以“绿色科技,畅想梦幻未来”为主题,紧紧围绕电动汽车产业发展,以展示展览为主线,力争通过万人试乘试驾、电动汽车爬坡拉力大赛、经销商大会,市长论坛、技术发展报告等活动。强化科技创新能力建设,提升产业核心竞争力,促进产业发展,加大电动汽车推广使用力度,积极发展配套产业,建立健全充换电等公共服务平台,完善销售流通渠道,抢占未来汽车产业战略制高点,进一步推动我国由汽车工业大国向汽车工业强国迈进。
整车集成展区:混合动力汽车(微混、轻混、中混、重混和插电式混合)、纯电动汽车、燃料电池汽车、电动客车、电动公交车、电动轿车、电动清洁车、电动观光车、电动货车、电动高尔夫球车、电动牵引车、电动警用巡逻车、电动房车、电动叉车、电动医疗车、电动邮政车特种电动车及其它各种新能源汽车等。
电池电机展区:动力电池、燃料电池、锂离子电池、锂聚合物电池、铅酸蓄电池、超级电容器产品设备等相关原材料;制造设备、测试仪器、各种动力电池与管理系统;低排放节能型发动机、混合动力发动机及清洁燃料发动机、电机、电机保护与控制技术电机电控系统等。
充电设施及公共平台建设展区:充电站智能网络项目规划及成果、 充电站项目规划及成果展示;充电站、充电机、充电桩、配电设备、变压器、电缆等相关基础设施;充换电池及电池管理系统;电能监视系统;供电解决方案、充电站配电设备、直接充电设备 、管理辅助设备、停车场充电设施、智能监控充电站供电解决方案、智能电网、输电并网技术解决方案。
零部件展区:整车总线与控制系统;储能装置等;能源管理系统;电力电容器、飞轮、逆变器、电热泵、电动助力转向、电动空调、功率模块等;相关材料、工艺、技术;相关检测、监控、试验、安全防护装备;维修、制造设备和工具;
电动车示范、试点城市成果展区:电动汽车推广应用经验与成果、电动汽车产业发展战略与规划。
其他展区:各地方政府有关机构、产业园区、金融机构、研究机构、大专院校以及相关企业。
2、2013中国重庆电动汽车万人试乘试驾活动
电动汽车普及难题除充电基础设施建设滞后等主因外,广大消费者对电动汽车的了解认知程度也是制约推广普及进程的又一主因。为了提高消费者对电动汽车的了解认知程度,强化推广力度,促进电动汽车产业化发展,进一步推动两江新区汽车城建设,更好的办好本届活动,组委会决定在中国电动汽车产业展览会期间举办中国(重庆)电动汽车万人试乘试驾活动。
3、2013中国重庆电动汽车爬坡拉力大赛
为了推广普及电动汽车,丰富中国电动汽车产业展览会内容。推动两江新区汽车城建设,培育电动汽车产业集群,促进电动汽车产业化进程。更好的办好本届活动。组委会拟定在中国电动汽车产业展览会期间举办中国重庆汽车爬坡拉力大赛。
本次赛事主要设定续航里程、加速、安全 性能速度测评频次主要指标的评比,力争通过此赛提升我国电动汽车产业的科技水平,带动相关产业发展,培育产业集群,进一步提升重庆两江汽车城在全球的影响力。宣传重庆、吸引优秀企业落户重庆,加速重庆电动汽车产业化进程。
4、首届中国电动汽车经销商大会
当前中国乃至世界范围内电动汽车产业异军突起,产业发展正处于十分关键的历史机遇期,同时我国也迎来电动汽车车型最高密度的投放期,市场需求强劲,尤其是其购车养车成本低廉、车型时尚观赏性强、低碳零排放促进环保消费等特点吸引了年轻消费者的目光,消费潜力巨大,市场前景广阔。为了进一步推广普及电动汽车,共同打造销售流通产业链,探索适合中国电动汽车发展的商业模式。组委会拟定在中国电动汽车产业展览会期间举办首届中国电动汽车经销商大会。

地址:重庆市南岸区开发路31号科尔国际商务大厦28-5 
电话:023-61221989 
传真:023-88638520
 

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

.Net Core微服務入門全紀錄(六)——EventBus-事件總線

前言

上一篇【.Net Core微服務入門全紀錄(五)——Ocelot-API網關(下)】中已經完成了Ocelot + Consul的搭建,這一篇簡單說一下EventBus。

EventBus-事件總線

  • 首先,什麼是事件總線呢?

貼一段引用:

事件總線是對觀察者(發布-訂閱)模式的一種實現。它是一種集中式事件處理機制,允許不同的組件之間進行彼此通信而又不需要相互依賴,達到一種解耦的目的。

如果沒有接觸過EventBus,可能不太好理解。其實EventBus在客戶端開發中應用非常廣泛(android,ios,web前端等),用於多個組件(或者界面)之間的相互通信,懂的人都懂。。。

  • 那麼,我們為什麼要用EventBus呢?

就拿當前的項目舉例,我們有一個訂單服務,一個產品服務。客戶端有一個下單功能,當用戶下單時,調用訂單服務的下單接口,那麼下單接口需要調用產品服務的減庫存接口,這涉及到服務與服務之間的調用。那麼服務之間又怎麼調用呢?直接RESTAPI?或者效率更高的gRPC?可能這兩者各有各的使用場景,但是他們都存在一個服務之間的耦合問題,或者難以做到異步調用。

試想一下:假設我們下單時調用訂單服務,訂單服務需要調用產品服務,產品服務又要調用物流服務,物流服務再去調用xx服務 等等。。。如果每個服務處理時間需要2s,不使用異步的話,那這種體驗可想而知。

如果使用EventBus的話,那麼訂單服務只需要向EventBus發一個“下單事件”就可以了。產品服務會訂閱“下單事件”,當產品服務收到下單事件時,自己去減庫存就好了。這樣就避免了兩個服務之間直接調用的耦合性,並且真正做到了異步調用。

既然涉及到多個服務之間的異步調用,那麼就不得不提分佈式事務。分佈式事務並不是微服務獨有的問題,而是所有的分佈式系統都會存在的問題。
關於分佈式事務,可以查一下“CAP原則”和“BASE理論”了解更多。當今的分佈式系統更多的會追求事務的最終一致性。

下面使用國人開發的優秀項目“CAP”,來演示一下EventBus的基本使用。之所以使用“CAP”是因為它既能解決分佈式系統的最終一致性,同時又是一個EventBus,它具備EventBus的所有功能!
作者介紹:https://www.cnblogs.com/savorboard/p/cap.html

CAP使用

  • 環境準備

在Docker中準備一下需要的環境,首先是數據庫,數據庫我使用PostgreSQL,用別的也行。CAP支持:SqlServer,MySql,PostgreSql,MongoDB。
關於在Docker中運行PostgreSQL可以看我的另一篇博客:https://www.cnblogs.com/xhznl/p/13155054.html

然後是MQ,這裏我使用RabbitMQ,Kafka也可以。
Docker運行RabbitMQ:

docker pull rabbitmq:management
docker run -d -p 15672:15672 -p 5672:5672 --name rabbitmq rabbitmq:management

默認用戶:guest,密碼:guest

環境準備就完成了,Docker就是這麼方便。。。

  • 代碼修改:

為了模擬以上業務,需要修改大量代碼,下面代碼如有遺漏的直接去github找。

NuGet安裝:

Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.Tools
Npgsql.EntityFrameworkCore.PostgreSQL

CAP相關:

DotNetCore.CAP
DotNetCore.CAP.RabbitMQ
DotNetCore.CAP.PostgreSql

Order.API/Controllers/OrdersController.cs增加下單接口:

[Route("[controller]")]
[ApiController]
public class OrdersController : ControllerBase
{
    private readonly ILogger<OrdersController> _logger;
    private readonly IConfiguration _configuration;
    private readonly ICapPublisher _capBus;
    private readonly OrderContext _context;

    public OrdersController(ILogger<OrdersController> logger, IConfiguration configuration, ICapPublisher capPublisher, OrderContext context)
    {
        _logger = logger;
        _configuration = configuration;
        _capBus = capPublisher;
        _context = context;
    }

    [HttpGet]
    public IActionResult Get()
    {
        string result = $"【訂單服務】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}——" +
            $"{Request.HttpContext.Connection.LocalIpAddress}:{_configuration["ConsulSetting:ServicePort"]}";
        return Ok(result);
    }

    /// <summary>
    /// 下單 發布下單事件
    /// </summary>
    /// <param name="order"></param>
    /// <returns></returns>
    [Route("Create")]
    [HttpPost]
    public async Task<IActionResult> CreateOrder(Models.Order order)
    {
        using (var trans = _context.Database.BeginTransaction(_capBus, autoCommit: true))
        {
            //業務代碼
            order.CreateTime = DateTime.Now;
            _context.Orders.Add(order);

            var r = await _context.SaveChangesAsync() > 0;

            if (r)
            {
                //發布下單事件
                await _capBus.PublishAsync("order.services.createorder", new CreateOrderMessageDto() { Count = order.Count, ProductID = order.ProductID });
                return Ok();
            }
            return BadRequest();
        }

    }

}

Order.API/MessageDto/CreateOrderMessageDto.cs:

/// <summary>
/// 下單事件消息
/// </summary>
public class CreateOrderMessageDto
{
    /// <summary>
    /// 產品ID
    /// </summary>
    public int ProductID { get; set; }

    /// <summary>
    /// 購買數量
    /// </summary>
    public int Count { get; set; }
}

Order.API/Models/Order.cs訂單實體類:

public class Order
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }

    /// <summary>
    /// 下單時間
    /// </summary>
    [Required]
    public DateTime CreateTime { get; set; }

    /// <summary>
    /// 產品ID
    /// </summary>
    [Required]
    public int ProductID { get; set; }

    /// <summary>
    /// 購買數量
    /// </summary>
    [Required]
    public int Count { get; set; }
}

Order.API/Models/OrderContext.cs數據庫Context:

public class OrderContext : DbContext
{
    public OrderContext(DbContextOptions<OrderContext> options)
       : base(options)
    {

    }

    public DbSet<Order> Orders { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {

    }
}

Order.API/appsettings.json增加數據庫連接字符串:

"ConnectionStrings": {
  "OrderContext": "User ID=postgres;Password=pg123456;Host=host.docker.internal;Port=5432;Database=Order;Pooling=true;"
}

Order.API/Startup.cs修改ConfigureServices方法,添加Cap配置:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    services.AddDbContext<OrderContext>(opt => opt.UseNpgsql(Configuration.GetConnectionString("OrderContext")));

    //CAP
    services.AddCap(x =>
    {
        x.UseEntityFramework<OrderContext>();

        x.UseRabbitMQ("host.docker.internal");
    });
}

以上是訂單服務的修改。

Product.API/Controllers/ProductsController.cs增加減庫存接口:

[Route("[controller]")]
[ApiController]
public class ProductsController : ControllerBase
{
    private readonly ILogger<ProductsController> _logger;
    private readonly IConfiguration _configuration;
    private readonly ICapPublisher _capBus;
    private readonly ProductContext _context;

    public ProductsController(ILogger<ProductsController> logger, IConfiguration configuration, ICapPublisher capPublisher, ProductContext context)
    {
        _logger = logger;
        _configuration = configuration;
        _capBus = capPublisher;
        _context = context;
    }

    [HttpGet]
    public IActionResult Get()
    {
        string result = $"【產品服務】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}——" +
            $"{Request.HttpContext.Connection.LocalIpAddress}:{_configuration["ConsulSetting:ServicePort"]}";
        return Ok(result);
    }

    /// <summary>
    /// 減庫存 訂閱下單事件
    /// </summary>
    /// <param name="message"></param>
    /// <returns></returns>
    [NonAction]
    [CapSubscribe("order.services.createorder")]
    public async Task ReduceStock(CreateOrderMessageDto message)
    {
        //業務代碼
        var product = await _context.Products.FirstOrDefaultAsync(p => p.ID == message.ProductID);
        product.Stock -= message.Count;

        await _context.SaveChangesAsync();
    }

}

Product.API/MessageDto/CreateOrderMessageDto.cs:

/// <summary>
/// 下單事件消息
/// </summary>
public class CreateOrderMessageDto
{
    /// <summary>
    /// 產品ID
    /// </summary>
    public int ProductID { get; set; }

    /// <summary>
    /// 購買數量
    /// </summary>
    public int Count { get; set; }
}

Product.API/Models/Product.cs產品實體類:

public class Product
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }

    /// <summary>
    /// 產品名稱
    /// </summary>
    [Required]
    [Column(TypeName = "VARCHAR(16)")]
    public string Name { get; set; }

    /// <summary>
    /// 庫存
    /// </summary>
    [Required]
    public int Stock { get; set; }
}

Product.API/Models/ProductContext.cs數據庫Context:

public class ProductContext : DbContext
{
    public ProductContext(DbContextOptions<ProductContext> options)
       : base(options)
    {

    }

    public DbSet<Product> Products { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        
        //初始化種子數據
        modelBuilder.Entity<Product>().HasData(new Product
        {
            ID = 1,
            Name = "產品1",
            Stock = 100
        },
        new Product
        {
            ID = 2,
            Name = "產品2",
            Stock = 100
        });
    }
}

Product.API/appsettings.json增加數據庫連接字符串:

"ConnectionStrings": {
  "ProductContext": "User ID=postgres;Password=pg123456;Host=host.docker.internal;Port=5432;Database=Product;Pooling=true;"
}

Product.API/Startup.cs修改ConfigureServices方法,添加Cap配置:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    services.AddDbContext<ProductContext>(opt => opt.UseNpgsql(Configuration.GetConnectionString("ProductContext")));

    //CAP
    services.AddCap(x =>
    {
        x.UseEntityFramework<ProductContext>();

        x.UseRabbitMQ("host.docker.internal");
    });
}

以上是產品服務的修改。

訂單服務和產品服務的修改到此就完成了,看着修改很多,其實功能很簡單。就是各自增加了自己的數據庫表,然後訂單服務增加了下單接口,下單接口會發出“下單事件”。產品服務增加了減庫存接口,減庫存接口會訂閱“下單事件”。然後客戶端調用下單接口下單時,產品服務會減去相應的庫存,功能就這麼簡單。

關於EF數據庫遷移之類的基本使用就不介紹了。使用Docker重新構建鏡像,運行訂單服務,產品服務:

docker build -t orderapi:1.1 -f ./Order.API/Dockerfile .
docker run -d -p 9060:80 --name orderservice orderapi:1.1 --ConsulSetting:ServicePort="9060"
docker run -d -p 9061:80 --name orderservice1 orderapi:1.1 --ConsulSetting:ServicePort="9061"
docker run -d -p 9062:80 --name orderservice2 orderapi:1.1 --ConsulSetting:ServicePort="9062"

docker build -t productapi:1.1 -f ./Product.API/Dockerfile .
docker run -d -p 9050:80 --name productservice productapi:1.1 --ConsulSetting:ServicePort="9050"
docker run -d -p 9051:80 --name productservice1 productapi:1.1 --ConsulSetting:ServicePort="9051"
docker run -d -p 9052:80 --name productservice2 productapi:1.1 --ConsulSetting:ServicePort="9052"

最後 Ocelot.APIGateway/ocelot.json 增加一條路由配置:

好了,進行到這裏,整個環境就有點複雜了。確保我們的PostgreSQL,RabbitMQ,Consul,Gateway,服務實例都正常運行。

服務實例運行成功后,數據庫應該是這樣的:

產品表種子數據:

cap.published表和cap.received表是由CAP自動生成的,它內部是使用本地消息表+MQ來實現異步確保。

運行測試

這次使用Postman作為客戶端調用下單接口(9070是之前的Ocelot網關端口):

訂單庫published表:

訂單庫order表:

產品庫received表:

產品庫product表:

再試一下:

OK,完成。雖然功能很簡單,但是我們實現了服務的解耦,異步調用,和最終一致性。

總結

注意,上面的例子純粹是為了說明EventBus的使用,實際中的下單流程絕對不會這麼做的!希望大家不要較真。。。

可能有人會說如果下單成功,但是庫存不足導致減庫存失敗了怎麼辦,是不是要回滾訂單表的數據?如果產生這種想法,說明還沒有真正理解最終一致性的思想。首先下單前肯定會檢查一下庫存數量,既然允許下單那麼必然是庫存充足的。這裏的事務是指:訂單保存到數據庫,和下單事件保存到cap.published表(保存到cap.published表理論上就能夠發送到MQ)這兩件事情,要麼一同成功,要麼一同失敗。如果這個事務成功,那麼就可以認為這個業務流程是成功的,至於產品服務的減庫存是否成功那就是產品服務的事情了(理論上也應該是成功的,因為消息已經確保發到了MQ,產品服務必然會收到消息),CAP也提供了失敗重試,和失敗回調機制。

如果非要數據回滾也是能實現的,CAP的ICapPublisher.Publish方法提供一個callbackName參數,當減庫存時,可以觸發這個回調。其本質也是通過發布訂閱完成,這是不推薦的做法,就不詳細說了,有興趣自己研究一下。
另外,CAP無法保證消息不重複,實際使用中需要自己考慮一下消息的重複過濾和冪等性。

這一篇內容有點多,不知道有沒有表達清楚,有問題歡迎評論交流,如有不對之處還望大家指出。

下一篇計劃寫一下授權認證相關的內容。

代碼放在:https://github.com/xiajingren/NetCoreMicroserviceDemo

未完待續…

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

Linux上TCP的幾個內核參數調優

Linux作為一個強大的操作系統,提供了一系列內核參數供我們進行調優。光TCP的調優參數就有50多個。在和線上問題鬥智斗勇的過程中,筆者積累了一些在內網環境應該進行調優的參數。在此分享出來,希望對大家有所幫助。

調優清單

好了,在這裏先列出調優清單。請記住,這裏只是筆者在內網進行TCP內核參數調優的經驗,僅供參考。同時,筆者還會在餘下的博客裏面詳細解釋了為什麼要進行這些調優!

序號 內核參數 值 備註
1.1 /proc/sys/net/ipv4/tcp_max_syn_backlog 2048
1.2 /proc/sys/net/core/somaxconn 2048
1.3 /proc/sys/net/ipv4/tcp_abort_on_overflow 1
2.1 /proc/sys/net/ipv4/tcp_tw_recycle 0 NAT環境必須為0
2.2 /proc/sys/net/ipv4/tcp_tw_reuse 1
3.1 /proc/sys/net/ipv4/tcp_syn_retries 3
3.2 /proc/sys/net/ipv4/tcp_retries2 5
3.3 /proc/sys/net/ipv4/tcp_slow_start_after_idle 0

tcp_max_syn_backlog,somaxconn,tcp_abort_on_overflow

tcp_max_syn_backlog,somaxconn,tcp_abort_on_overflow這三個參數是關於
內核TCP連接緩衝隊列的設置。如果應用層來不及將已經三次握手建立成功的TCP連接從隊列中取出,溢出了這個緩衝隊列(全連接隊列)之後就會丟棄這個連接。如下圖所示:

從而產生一些詭異的現象,這個現象詭異之處就在於,是在TCP第三次握手的時候丟棄連接

就如圖中所示,第二次握手的SYNACK發送給client端了。所以就會出現client端認為連接成功,而Server端確已經丟棄了這個連接的現象!由於無法感知到Server已經丟棄了連接。
所以如果沒有心跳的話,只有在發出第一個請求后,Server才會發送一個reset端通知這個連接已經被丟棄了,建立連接后第二天再用,也會報錯!所以我們要調大Backlog隊列!

echo 2048 > /proc/sys/net/ipv4/tcp_max_syn_backlog
echo 2048 > /proc/sys/net/core/somaxconn

當然了,為了盡量避免第一筆調用失敗問題,我們也同時要設置

echo 1 > /proc/sys/net/ipv4/tcp_abort_on_overflow

設置這個值以後,Server端內核就會在這個連接被溢出之後發送一個reset包給client端。

如果我們的client端是NIO的話,就可以收到一個socket close的事件以感知到連接被關閉!

注意Java默認的Backlog是50

這個TCP Backlog的隊列大小值是min(tcp_max_syn_backlog,somaxconn,應用層設置的backlog),而Java如果不做額外設置,Backlog默認值僅僅只有50。C語言在使用listen調用的時候需要傳進Backlog參數。

tcp_tw_recycle

tcp_tw_recycle這個參數一般是用來抑制TIME_WAIT數量的,但是它有一個副作用。即在tcp_timestamps開啟(Linux默認開啟),tcp_tw_recycle會經常導致下面這種現象。

也即,如果你的Server開啟了tcp_tw_recycle,那麼別人如果通過NAT之類的調用你的Server的話,NAT後面的機器只有一台機器能正常工作,其它情況大概率失敗。具體原因呢由下圖所示:

在tcp_tw_recycle=1同時tcp_timestamps(默認開啟的情況下),對同一個IP的連接會做這樣的限制,也即之前後建立的連接的時間戳必須要大於之前建立連接的最後時間戳,但是經過NAT的一個IP後面是不同的機器,時間戳相差極大,就會導致內核直接丟棄時間戳較低的連接的現象。由於這個參數導致的問題,高版本內核已經去掉了這個參數。如果考慮TIME_WAIT問題,可以考慮設置一下

echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse

tcp_syn_retries

這個參數值得是client發送SYN如果server端不回復的話,重傳SYN的次數。對我們的直接影響呢就是connet建立連接時的超時時間。當然Java通過一些C原生系統調用的組合使得我們可以進行超時時間的設置。在Linux裏面默認設置是5,下面給出建議值3和默認值5之間的超時時間。

tcp_syn_retries timeout
1 min(so_sndtimeo,3s)
2 min(so_sndtimeo,7s)
3 min(so_sndtimeo,15s)
4 min(so_sndtimeo,31s)
5 min(so_sndtimeo,63s)

下圖給出了,重傳和超時情況的對應圖:

當然了,不同內核版本的超時時間可能不一樣,因為初始RTO在內核小版本間都會有細微的變化。所以,有時候在抓包時候可能會出現(3,6,12……)這樣的序列。當然Java的API有超時時間:

java:
 // 函數調用中攜帶有超時時間
 public void connect(SocketAddress endpoint, int timeout) ;

所以,對於Java而言,這個內核參數的設置沒有那麼重要。但是,有些代碼可能會有忘了設置timeout的情況,例如某個版本的Kafka就是,所以它在我們一些混沌測試的情況下,容災恢復的時間會達到一分多鍾,主要時間就是卡在connect上面-_-!,而這時我們的tcp_syn_retries設置的是5,也即超時時間63s。減少這個恢復時間的手段就是:

echo 3 > /proc/sys/net/ipv4/tcp_syn_retries

tcp_retries2

tcp_retries2這個參數表面意思是在傳輸過程中tcp的重傳次數。但在某個版本之後Linux內核僅僅用這個tcp_retries2來計算超時時間,在這段時間的重傳次數純粹由RTO等環境因素決定,重傳超時時間在5/15下的表現為:

tcp_retries2 對端無響應
5 25.6s-51.2s根據動態rto定
15 924.6s-1044.6s根據動態rto定

如果我們在應用層設置的Socket所有ReadTimeout都很小的話(例如3s),這個內核參數調整是沒有必要的。但是,筆者經常發現有的系統,因為一兩個慢的接口或者SQL,所以將ReadTimeout設的很大的情況。

平常這種情況是沒有問題的,因為慢請求頻率很低,不會對系統造成什麼風險。但是,物理機突然宕機時候的情況就不一樣了,由於ReadTimeOut設置的過大,導致所有落到這台宕機的機器都會在min(ReadTimeOut,(924.6s-1044.6s)(Linux默認tcp_retries2是15))后才能從read系統調用返回。假設ReadTimeout設置了個5min,系統總線程數是200,那麼只要5min內有200個請求落到宕機的server就會使A系統失去響應!

但如果將tcp_retries2設置為5,那麼超時返回時間即為min(ReadTimeOut 5min,25.6-51.2s),也就是30s左右,極大的緩解了這一情況。

echo 5 > /proc/sys/net/ipv4/tcp_retries2

但是針對這種現象,最好要做資源上的隔離,例如線程上的隔離或者機器級的隔離。

golang的goroutine調度模型就可以很好的解決線程資源不夠的問題,但缺點是goroutine裏面不能有阻塞的系統調用,不然也會和上面一樣,但僅僅對於系統之間互相調用而言,都是非阻塞IO,所以golang做微服務還是非常Nice的。當然了我大Java用純IO事件觸發編寫代碼也不會有問題,就是對心智負擔太高-_-!

物理機突然宕機和進程宕不一樣

值得注意的是,物理機宕機和進程宕但內核還存在表現完全不一樣。

僅僅進程宕而內核存活,那麼內核會立馬發送reset給對端,從而不會卡住A系統的線程資源。

tcp_slow_start_after_idle

還有一個可能需要調整的參數是tcp_slow_start_after_idle,Linux默認是1,即開啟狀態。開啟這個參數后,我們的TCP擁塞窗口會在一個RTO時間空閑之後重置為初始擁塞窗口(CWND)大小,這無疑大幅的減少了長連接的優勢。對應Linux源碼為:

static void tcp_event_data_sent(struct tcp_sock *tp,
				struct sk_buff *skb, struct sock *sk){
	// 如果開啟了start_after_idle,而且這次發送的時間-上次發送的時間>一個rto,就重置tcp擁塞窗口
	if (sysctl_tcp_slow_start_after_idle &&
	    (!tp->packets_out && (s32)(now - tp->lsndtime) > icsk->icsk_rto))
		tcp_cwnd_restart(sk, __sk_dst_get(sk));
}

關閉這個參數后,無疑會提高某些請求的傳輸速度(在帶寬夠的情況下)。

echo 0 > /proc/sys/net/ipv4/tcp_slow_start_after_idle

當然了,Linux啟用這個參數也是有理由的,如果我們的網絡情況是時刻在變化的,例如拿個手機到處移動,那麼將擁塞窗口重置確實是個不錯的選項。但是就我們內網系統間調用而言,是不太必要的了。

初始CWND大小

毫無疑問,新建連接之後的初始TCP擁塞窗口大小也直接影響到我們的請求速率。在Linux2.6.32源碼中,其初始擁塞窗口是(2-4個)mss大小,對應於內網估計也就是(2.8-5.6K)(MTU 1500),這個大小對於某些大請求可能有點捉襟見肘。
在Linux 2.6.39以上或者某些RedHat維護的小版本中已經把CWND
增大到RFC 6928所規定的的10段,也就是在內網裡面估計14K左右(MTU 1500)。

Linux 新版本
/* TCP initial congestion window */
#define TCP_INIT_CWND		10

公眾號

關注筆者公眾號,獲取更多乾貨文章

總結

Linux提供了一大堆內參參數供我們進行調優,其默認設置的參數在很多情況下並不是最佳實踐,所以我們需要潛心研究,找到最適合當前環境的組合。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

哥倫比亞毒梟艾斯科巴的河馬 意外恢復1萬多年前部分生態系功能

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

日產結盟三菱 衝刺北美及新興電動車市場

日產和三菱汽車周二(5)宣布策略結盟,將藉由共同開發電動車,共享工廠、產能和技術,並提升北美和新興市場汽車銷量。日產在聲明中表示,「日產已與三菱達成策略結盟,此舉將擴大雷諾與日產的盟友關係。」

三菱加入後,雷諾與日產的盟友將增加至5名,還包括德國戴姆勒和俄羅斯的AvtoVAZ,共同抵禦德國福斯和日本豐田的競爭。此外,雷諾的本國對手標緻雪鐵龍(PSA Peugeot Citroen)也與通用結盟,以節省成本。

2011年,日產和三菱成立合資公司NMKV,共同研發迷你車,本次的聲明表示,「預期現有的NMKV公司將共同研發新款小車,其中包括預計在全球銷售、特定版本的電動車。」

雷諾、日產和三菱表示,結盟後的首批新車之一,將是由雷諾子公司-雷諾三星汽車在南韓生產的大型車,該車款將掛上三菱的品牌在北美市場販售。第2款較小型的車款也是為三菱設計,係由雷諾研發,生產地點尚未決定。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

日產CEO稱燃料電池車將面臨更嚴重銷售問題

據路透報導,雷諾與日產汽車執行長戈恩週三(20)重申,雷諾與日產原定到2017年3月末時售出150萬輛電動汽車的目標,將推遲兩至三年。

但他對未能按時達到電動汽車銷售目標並不感到擔心,並預測競爭對手在未來幾年的燃料電池汽車銷售計畫會面臨更大的障礙。豐田汽車和本田汽車均計畫在2015年左右開始銷售燃料電池汽車。

儘管日產推遲了達到電動汽車銷售目標的時間,但他表示,將提高純電動汽車Leaf在美國的產量。在下調價格之後,Leaf是目前全球最暢銷的電動汽車。

自三年前向市場推出首款電動汽車以來,日產與雷諾迄今僅售出了12萬輛電動汽車。不過戈恩認為,充電基礎設施方面的難題,而非技術問題,才是阻礙電動汽車普及程度的關鍵原因,這預示著燃料電池汽車的未來甚至面臨更大的挑戰。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

【Java思考】Java 中的實參与形參之間的傳遞到底是值傳遞還是引用傳遞呢?

科普:

  • 值傳遞(pass by value)是指在調用函數時將實際參數複製一份傳遞到函數中,這樣在函數中如果對參數進行修改,將不會影響到實際參數。
  • 引用傳遞(pass by reference)是指在調用函數時將實際參數的地址直接傳遞到函數中,那麼在函數中對參數所進行的修改,將影響到實際參數。
值傳遞 引用傳遞
根本區別 會創建副本(Copy) 不創建副本,直接引用
效果 函數中無法改變原始對象 函數中可以改變原始對象

Java 中的實參与形參之間的傳遞到底是值傳遞還是引用傳遞呢?

其實之前我和大多數人一樣認為:傳遞的參數如果是“基本數據類型”,那就是“值傳遞”,如果是“引用類型”(即 對象),那就是“引用傳遞”。

但是昨天我突然覺得:好像。。。不一定!
誒,別急着懟我說:Nemo!你傳遞過對象沒啊,把對象傳過去,修改對象的屬性值,屬性值就是的的確確的修改了啊!

誒,你說的沒錯,確實是修改了,但是你也說了是修改對象的屬性值,傳過去的是對象地址,而你的實際操作並沒有對你傳入的地址進行修改,只是修改了對象地址下面的屬性值。

如果只是修改對象地址下面的屬性值的話,那麼值傳遞和引用傳遞有差嗎?
值傳遞:複製對象地址給函數,函數修改對象地址下面的屬性值。
引用傳遞:引用對象地址給函數,函數修改對象地址下面的屬性值。
這兩者有差嗎,無論是複製還是引用,傳入的對象地址都沒有改變,改變的只是對象地址下面的屬性值。

類比:我們可以類比一下,你家的地址是“北京市海淀區清華園1號”。
引用傳遞:你給我引用你的地址,我過去你的地址那,打開你家的門,偷你家電動車的電瓶。
值傳遞:你不給我你的地址,我從網上找到你的地址,複製一份,過去你的地址那,打開你家的門,偷你家電動車的電瓶。
你瞧瞧,這兩者有差嗎?無論是怎樣拿到你家的地址,你家的電瓶我要定了啊,你家的電瓶都會被修改啊。

舉例代碼:

package temp;

/**
 * @author Nemo
 * @date 2020/6/22
 */
public class ValueTransfer {
    public static void main(String[] args) {
        Home yourHome = new Home("你的家");
        Nemo nemo = new Nemo();
        nemo.steal(yourHome);
        yourHome.show();
    }
}

class Home {
    public String name;
    public boolean battery = true;

    public boolean isBattery() {
        return battery;
    }

    public void setBattery(boolean battery) {
        this.battery = battery;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Home(String name) {
        this.name = name;
    }

    public void show() {
        if (this.isBattery()) {
            System.out.println(name + "的電瓶還在喲~");
        } else {
            System.out.println(name + "的電瓶被偷了!");
        }
    }

}

class Nemo {
    public void steal(Home home) {
        //如果是引用傳遞的話,那麼我把你的家整個都變為了別人的家,那麼你的家對象上現在應該存放的是別人的家
        //如果是值傳遞的話,那麼我只是把你的家對象複製了一個新的,這個新的家是別人的家,我偷一個跟你家一模一樣的別人家的電瓶,你家的電瓶應該不會變
        home = new Home("別人的家");
        home.battery = false;
        home.show();
    }

}

在 Nemo 類的 steal 方法中,我們可以看到註釋:

  1. 如果是引用傳遞,那麼我把你的家整個都變為了別人的家,那麼你的家對象上現在應該存放的是別人的家,並且你家(即 別人家)的電瓶也應該被我偷了。
  2. 如果是值傳遞,那麼我只是把你的家對象參數複製了一個新的,這個新的家我設為了別人的家,我偷一個跟你家一模一樣的別人家的電瓶,你家的電瓶應該不會變。

運行結果:

別人的家的電瓶被偷了!
你的家的電瓶還在喲~

根據運行結果來看,很顯然,是第二種情況,也就是值傳遞,我偷的是一個跟你家一模一樣的別人家的電瓶,而你家的電瓶還在。

結論

Java 中只有值傳遞。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

德出現罕見高溫旱象 綠黨籲成立氣候基金

摘錄自2018年8月6日中央社報導

德國今年出現罕見的旱象,高溫也一再打破紀錄,德國綠黨建議成立氣候調適基金,以補償氣候變遷帶來的衝擊。

根據德國氣象局(DWD)的數據,今年4月到7月的均溫,比歷史平均氣溫高攝氏3.6度,創下1881年有氣象紀錄以來的最高溫。

德國今年也出現少見的旱象,今年4月到7月的降雨量,比平均降雨量少110毫米,同樣創下有紀錄以來的新低,各地農人紛紛抱怨收成大幅減少。

鑑於氣候變遷對產業和生活都帶來衝擊,綠黨4日建議政府成立20億歐元(約新台幣708億元)的氣候調適基金,用來支付農業補償、森林大火、水患和醫療的費用。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

特斯拉Model S低價進入中國市場

美國電動車大廠特斯拉(Tesla)昨(23)日宣佈,旗下旗艦車款Model S將登陸中國市場,售價約為73.4萬元人民幣,預估2014年3月底可交車,該公司已在北京成立展示廳和服務銷售點。

不過對購買Tesla的中國車主而言,如何解決汽車充電問題將是一大挑戰。但特斯拉中國區總經理鄭順景指出,Model S充飽電後能跑500公里,因此在市區駕駛不用擔心電量問題。

特斯拉昨日公開了Model S價格是如何訂定的:該款車在美售價81,070美元,在此基礎再加上運輸與裝卸費用3,600美元,關稅和其他稅費19,000美元,以及增值稅17,700美元,總價121,370美元。 按1比6.05匯率計算,約人民幣73.4萬元。

特斯拉表示,如果按照汽車行業在中國的慣例,特斯拉完全可以將Model S在中國的價格定為美國的兩倍以上,但該公司決定不依循此一慣例,特斯拉希望公平對待中國消費者。

據特斯拉統計,2013年Model S全球銷量2萬2,300輛。但上半年只賣8,900輛,下半年銷售量才突然飆升,光第4季就賣出6,900輛。

圖:經濟日報

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

別讓烏鴉笑我們髒 法國樂園訓練鳥撿菸蒂

摘錄自2018年08月12日蘋果日報法國報導

法國主題樂園招募到新的清潔工整理環境非新鮮事,新鮮的是這些清潔工是六隻聰明的鳥。

櫸木山主題樂園(Puy du Fou,又稱狂人國)位於法國西部,曾被評選為世界最佳主題樂園,上千種稀有鳥類和小動物在此棲息,堪稱是歐洲鳥類救護基地。

園方安排六隻受過訓練的禿鼻鴉,負責銜起遊客扔下的煙蒂和垃圾。當牠們把垃圾丟進指定的小箱時,一小塊鳥食就會自動彈出,作為其辛勤工作的獎勵。

第一批「清潔鳥」已正式上線,其餘者則預計明天(13日)上班。禿鼻鴉是烏鴉的一種,而且特別聰明。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案